drivers/scsi/scsi_transport_fc.c::fc_fpin_li_stats_update() and fc_fpin_peer_congn_stats_update() walk the on-wire pname_list[] with a u8 loop counter against the 32-bit __be32 pname_count field, and never bound pname_count by the descriptor body the TLV walker already validated.
The two functions are reached on every host running lpfc or qla2xxx as soon as the fabric controller (well-known S_ID 0xFFFFFD on an FC fabric) emits an FPIN ELS for that initiator; no host-side capability is required, the fabric is the source. A pname_count of 256 leaves the u8 condition i < 256 true for every value i can take, so the walker never terminates: it takes fc_host->rport_lock once per iteration via fc_find_rport_by_wwpn() and never releases the calling thread. Impact: a fabric-side FPIN sender (the elected fabric controller, a co-tenant N_Port that spoofs S_ID 0xFFFFFD after FLOGI, or a compromised switch supervisor) can hang the FC ELS receive thread of an lpfc or qla2xxx initiator indefinitely by emitting one FPIN ELS frame whose Link-Integrity or Peer-Congestion descriptor sets pname_count to 256, blocking subsequent FPIN, RSCN, and multipath-health processing on that HBA function until reboot. Switch i to u32 in both walkers and clamp pname_count against the per-descriptor available bytes (desc_len minus the offset of pname_list[]) before the loop. This refuses a malformed descriptor that claims more entries than its TLV body can hold, and is the minimum scope that covers both walkers. I reproduced this on a KASAN-enabled x86_64 mainline kernel at f0db6484b6ea via an out-of-tree module that allocates a real Scsi_Host through the FC transport API (fc_attach_transport(), scsi_host_alloc(), scsi_add_host()), builds a 2096-byte FPIN payload with pname_count == 256, and calls the exported fc_host_fpin_rcv() from a kernel thread. Without the patch, a bounded watchdog timer fires three seconds into the call with the kthread still inside fc_find_rport_by_wwpn() (offset 0x14b/0x2b0 in [scsi_transport_fc]) under fc_host_fpin_rcv()+0x4e8. The patched-kernel A/B run, the legitimate pname_count <= 4 regression 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. Two in-tree forwarders reach this code: lpfc passes the full hardware-reported payload_len with no software clamp (drivers/scsi/lpfc/lpfc_els.c:10830); qla2xxx clamps total_bytes to sizeof(item->iocb.iocb) == 64 in qla27xx_copy_fpin_pkt (drivers/scsi/qla2xxx/qla_isr.c :1170-1171), so qla2xxx delivers at most 64 bytes of FPIN payload, but the walker bug fires regardless because the inner walker never consults desc_len before reading pname_list[i]. qedf, bnx2fc, sw-fcoe and bfa do not forward FPIN ELS to fc_host_fpin_rcv() in mainline. The in-flight v10 "fc_els: use 'union fc_tlv_desc'" series from Hannes Reinecke and John Meneghini (linux-scsi mid [email protected]) touches the same file but only changes the descriptor pointer type; the u8 i counter is preserved verbatim in v10. Can rebase on top of that series if it lands first, or land this fix standalone against current mainline. Fixes: 3dcfe0de5a97 ("scsi: fc: Parse FPIN packets and update statistics") Cc: [email protected] Assisted-by: Claude:claude-opus-4-7 Signed-off-by: Michael Bommarito <[email protected]>

