]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
scsi: fcoe: Reject FIP descriptors with zero fip_dlen in CVL walker
authorMichael Bommarito <michael.bommarito@gmail.com>
Mon, 18 May 2026 14:43:07 +0000 (10:43 -0400)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 23 May 2026 01:56:42 +0000 (21:56 -0400)
drivers/scsi/fcoe/fcoe_ctlr.c::fcoe_ctlr_recv_clr_vlink() advanced 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) checked
their per-type minimum lengths, but a FIP_DT_NON_CRITICAL descriptor
(fip_dtype >= 128, which the standard requires receivers to silently
ignore) skipped that check entirely.

An unauthenticated L2 peer on the FCoE control VLAN could hang
fcoe_ctlr_recv_work on an fcoe, qedf, or bnx2fc initiator indefinitely
by emitting one FIP CVL frame whose single descriptor had fip_dtype ==
FIP_DT_NON_CRITICAL and fip_dlen == 0: the cursor advanced zero bytes
per iteration and the loop condition rlen >= sizeof(*desc) stayed true
forever, blocking every subsequent FIP frame on that controller.

Tighten the outer dlen guard to also reject dlen < sizeof(struct
fip_desc), so a malformed descriptor whose length cannot even cover the
descriptor header is rejected before the switch.  This is the same
lower-bound the named cases already apply and is the minimum scope that
closes the loop.

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>
Reviewed-by: Hannes Reinecke <hare@kernel.org>
Link: https://patch.msgid.link/20260518144307.2820961-1-michael.bommarito@gmail.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/fcoe/fcoe_ctlr.c

index 02cd4410efca70a5f50d22a01bb195875cd87448..496ddd45f74da45afedd96efca3308ba4b09ec08 100644 (file)
@@ -1385,7 +1385,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
 
        while (rlen >= sizeof(*desc)) {
                dlen = desc->fip_dlen * FIP_BPW;
-               if (dlen > rlen)
+               if (dlen < sizeof(*desc) || dlen > rlen)
                        goto err;
                /* Drop CVL if there are duplicate critical descriptors */
                if ((desc->fip_dtype < 32) &&