From: Michael Bommarito <michael.bommarito@gmail.com>
To: Hannes Reinecke <hare@suse.de>,
"Martin K . Petersen" <martin.petersen@oracle.com>,
"James E . J . Bottomley" <James.Bottomley@HansenPartnership.com>,
Hannes Reinecke <hare@kernel.org>
Cc: Robert Love <robert.w.love@intel.com>,
Vasu Dev <vasu.dev@intel.com>, Joe Eykholt <jeykholt@cisco.com>,
Saurav Kashyap <skashyap@marvell.com>,
Javed Hasan <jhasan@marvell.com>,
Nilesh Javali <njavali@marvell.com>,
Karan Tilak Kumar <kartilak@cisco.com>,
Sesidhar Baddela <sebaddel@cisco.com>,
Arun Easi <aeasi@cisco.com>, Kees Cook <kees@kernel.org>,
linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [DRAFT][PATCH] scsi: fcoe: reject FIP descriptors with zero fip_dlen in CVL walker
Date: Mon, 18 May 2026 10:11:49 -0400 [thread overview]
Message-ID: <20260518141150.2755252-1-michael.bommarito@gmail.com> (raw)
drivers/scsi/fcoe/fcoe_ctlr.c::fcoe_ctlr_recv_clr_vlink() advances
the descriptor cursor by an attacker-supplied fip_dlen without
ever requiring dlen >= sizeof(struct fip_desc) in the default
branch. The named descriptor cases (FIP_DT_MAC, FIP_DT_NAME,
FIP_DT_VN_ID) check their per-type minimum lengths, but a
FIP_DT_NON_CRITICAL descriptor (fip_dtype >= 128, which the
standard requires receivers to silently ignore) skips that check
entirely.
The function is reached on every host that has selected an FCoE
Forwarder and logged into the fabric: any L2 peer on the FCoE
control VLAN that spoofs the elected FCF source MAC, or wins
FIP election, can deliver a CVL frame; FIP frames are not
cryptographically authenticated.
A FIP CVL frame with one FIP_DT_NON_CRITICAL descriptor whose
fip_dlen == 0 leaves desc and rlen unchanged after one loop
iteration, so the loop condition rlen >= sizeof(*desc) stays
true forever and fcoe_ctlr_recv_work never returns.
Impact: an unauthenticated L2 peer on the FCoE control VLAN can
hang fcoe_ctlr_recv_work on an fcoe, qedf, or bnx2fc initiator
indefinitely by emitting one FIP CVL frame whose single
descriptor has fip_dtype == FIP_DT_NON_CRITICAL and
fip_dlen == 0, blocking every subsequent FIP frame (FCF
keepalives, FLOGI, FDISC, real CVLs) on that controller and,
once the fabric ages out the session, leaving FCoE storage on
the affected initiator unavailable until reboot.
Reject the descriptor in the default branch when fip_dlen *
FIP_BPW is less than sizeof(struct fip_desc), i.e. when the
attacker-supplied length cannot even cover the descriptor
header. This is the same lower-bound that the named cases
already apply and is the minimum scope that closes the loop.
I reproduced this on a KASAN-enabled x86_64 mainline kernel at
f0db6484b6ea via an out-of-tree module that initialises a real
struct fcoe_ctlr through fcoe_ctlr_init(FIP_MODE_FABRIC),
installs a fcoe_fcf with fcf_mac and switch_name, sets
ctlr->state = FIP_ST_ENABLED and lp->port_id, then queues a
crafted FIP CVL skb whose single descriptor has fip_dtype ==
FIP_DT_NON_CRITICAL and fip_dlen == 0, and calls the exported
fcoe_ctlr_recv() from the init thread. Without the patch, a
bounded watchdog timer fires three seconds into the call with
the workqueue still inside fcoe_ctlr_recv_work (RIP
fcoe_ctlr_recv_work+0x1161/0x34d0 in [libfcoe]). The
patched-kernel A/B run, the legitimate non-critical-descriptor
regression (fip_dlen == 1) run, and the checkpatch and
get_maintainer outputs are pending the final patch draft and
will be captured before send. A reproducer is available
off-list on request.
Three driver-private walkers in qedf and fnic share the same
algorithmic invariant (qedf_fcoe_process_vlan_resp at
drivers/scsi/qedf/qedf_fip.c:90, qedf CVL walker at
qedf_fip.c:233, fnic_fcoe_process_vlan_resp at
drivers/scsi/fnic/fip.c:117). Those are companion fixes for a
separate posting; they need the same dlen lower bound in their
own walker bodies and live-evidence on qedf or fnic hardware.
Fixes: 97c8389d54b9 ("[SCSI] fcoe, libfcoe: Add support for FIP. FCoE discovery and keep-alive.")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
next reply other threads:[~2026-05-18 14:12 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-18 14:11 Michael Bommarito [this message]
2026-05-18 14:11 ` [PATCH] " Michael Bommarito
2026-05-18 14:43 ` [PATCH v2] " Michael Bommarito
2026-05-19 8:36 ` Hannes Reinecke
2026-05-23 3:15 ` Martin K. Petersen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260518141150.2755252-1-michael.bommarito@gmail.com \
--to=michael.bommarito@gmail.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=aeasi@cisco.com \
--cc=hare@kernel.org \
--cc=hare@suse.de \
--cc=jeykholt@cisco.com \
--cc=jhasan@marvell.com \
--cc=kartilak@cisco.com \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=njavali@marvell.com \
--cc=robert.w.love@intel.com \
--cc=sebaddel@cisco.com \
--cc=skashyap@marvell.com \
--cc=vasu.dev@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®