In the Linux kernel, the following vulnerability has been resolved:
scsi: qla2xxx: Serialize NVMe unsol ctx list with a per-fcport lock
The fcport->unsol_ctx_head list is modified from several contexts without
a common lock. Entries are added in qla2xxx_process_purls_iocb() from the
response queue ISR (under the qpair qp_lock), while they are removed from
qla2xxx_process_purls_pkt() (DPC/purex worker), qla_nvme_xmt_ls_rsp()
(NVMe-FC transport callback) and qla_nvme_release_lsrsp_cmd_kref() (SRB
completion). The qpair qp_lock cannot serialize this per-fcport list since
multiqueue adapters add entries through different qpairs, so a concurrent
add and delete (or two concurrent deletes) can corrupt the list pointers.
Introduce a dedicated per-fcport spinlock, unsol_ctx_lock, initialized in
qla2x00_alloc_fcport(), and take it around every list_add_tail()/list_del()
on unsol_ctx_head. The add nests under the existing qp_lock; no delete path
takes qp_lock, so the lock order is consistent and deadlock free.
CVSS Vector: CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVSS Score: 8.8
AV:A - qla24xx_msix_rsp_q/qla2xxx_msix_rsp_q → qla24xx_process_response_queue dispatches PT_LS4_UNSOL (0x56) into qla2xxx_process_purls_iocb, which list_add_tail's uctx onto fcport->unsol_ctx_head. Those are unsolicited NVMe-FC LS frames a SAN N_Port put on the wire. FC/FCoE is a non-routable fabric, so Adjacent.
AC:L - A fabric peer floods concurrent PT_LS4_UNSOL so ISR list_add_tail in qla2xxx_process_purls_iocb (qp_lock only; different qpairs on MQ) races list_del in qla2xxx_process_purls_pkt (DPC; nvme_fc_rcv_ls_req -E2BIG on oversized LS), qla_nvme_xmt_ls_rsp, or qla_nvme_release_lsrsp_cmd_kref. The attacker drives both sides.
PR:N - qla2xxx_process_purls_iocb only needs qla2x00_find_fcport_by_nportid to match a non-deleted N_Port that completed NVMe PRLI (nvme_remote_port). The PT_LS4_UNSOL path has no uid, capability, or EDIF check; fabric zoning is network access, not a host privilege.
UI:N - PT_LS4_UNSOL is consumed in the MSI-X response-queue handler and queued via qla24xx_queue_purex_item to PROCESS_PUREX_IOCB; nvme_fc later calls qla_nvme_xmt_ls_rsp from lsrcv_work. No victim mount, open, or other interactive step is required.
S:U - Corrupting fcport->unsol_ctx_head and the qla_nvme_unsol_ctx list nodes stays inside the host kernel that owns the qla2xxx adapter. This is not a VM escape, IOMMU bypass, or other cross-authority impact.
C:H - Unlocked list_add_tail versus list_del on unsol_ctx_head can leave head->prev pointing at a qla_nvme_unsol_ctx that qla2xxx_process_purls_pkt already kfree'd, so the next add writes through freed slab. Reuse of that uctx is an arbitrary kernel read primitive.
I:H - The same race lets list_del write prev/next of a neighbor uctx or the list head through a stale pointer, and a second delete of a poisoned node writes LIST_POISON or a reused object, which is a kernel write and control-flow hijack primitive.
A:H - list_del on a corrupted unsol_ctx_head hits LIST_POISON or a bad dereference in qla2xxx_process_purls_pkt, qla_nvme_xmt_ls_rsp, or qla_nvme_release_lsrsp_cmd_kref and oopses or panics the host, taking down the NVMe-FC path.
| Attack Vector |
Adjacent Network |
Scope |
Unchanged |
| Attack Complexity |
Low |
Confidentiality Impact |
High |
| Privileges Required |
None |
Integrity Impact |
High |
| User Interaction |
None |
Availability Impact |
High |
AV:A - qla24xx_msix_rsp_q/qla2xxx_msix_rsp_q → qla24xx_process_response_queue dispatches PT_LS4_UNSOL (0x56) into qla2xxx_process_purls_iocb, which list_add_tail's uctx onto fcport->unsol_ctx_head. Those are unsolicited NVMe-FC LS frames a SAN N_Port put on the wire. FC/FCoE is a non-routable fabric, so Adjacent.
AC:L - A fabric peer floods concurrent PT_LS4_UNSOL so ISR list_add_tail in qla2xxx_process_purls_iocb (qp_lock only; different qpairs on MQ) races list_del in qla2xxx_process_purls_pkt (DPC; nvme_fc_rcv_ls_req -E2BIG on oversized LS), qla_nvme_xmt_ls_rsp, or qla_nvme_release_lsrsp_cmd_kref. The attacker drives both sides.
PR:N - qla2xxx_process_purls_iocb only needs qla2x00_find_fcport_by_nportid to match a non-deleted N_Port that completed NVMe PRLI (nvme_remote_port). The PT_LS4_UNSOL path has no uid, capability, or EDIF check; fabric zoning is network access, not a host privilege.
UI:N - PT_LS4_UNSOL is consumed in the MSI-X response-queue handler and queued via qla24xx_queue_purex_item to PROCESS_PUREX_IOCB; nvme_fc later calls qla_nvme_xmt_ls_rsp from lsrcv_work. No victim mount, open, or other interactive step is required.
S:U - Corrupting fcport->unsol_ctx_head and the qla_nvme_unsol_ctx list nodes stays inside the host kernel that owns the qla2xxx adapter. This is not a VM escape, IOMMU bypass, or other cross-authority impact.
C:H - Unlocked list_add_tail versus list_del on unsol_ctx_head can leave head->prev pointing at a qla_nvme_unsol_ctx that qla2xxx_process_purls_pkt already kfree'd, so the next add writes through freed slab. Reuse of that uctx is an arbitrary kernel read primitive.
I:H - The same race lets list_del write prev/next of a neighbor uctx or the list head through a stale pointer, and a second delete of a poisoned node writes LIST_POISON or a reused object, which is a kernel write and control-flow hijack primitive.
A:H - list_del on a corrupted unsol_ctx_head hits LIST_POISON or a bad dereference in qla2xxx_process_purls_pkt, qla_nvme_xmt_ls_rsp, or qla_nvme_release_lsrsp_cmd_kref and oopses or panics the host, taking down the NVMe-FC path.
CVSS 3.1