mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 14:33:24 -04:00
scsi: qla2xxx: Clamp MSI-X derived queue counts to avoid truncation
ha->msix_count is u16, but ha->max_req_queues, ha->max_rsp_queues and
ha->max_qpairs are u8. Deriving the queue count as
"ha->max_req_queues = ha->msix_count - 1" therefore truncates: a board
(or a misconfigured/malicious hot-plugged device) advertising 257 MSI-X
vectors yields msix_count - 1 == 256, which truncates to 0. An MSI-X
count of 1 zeroes it as well, and in target mode the subsequent
"ha->max_req_queues--" then underflows 0 to 255.
When the count is 0, qla2x00_alloc_queues() calls
kzalloc_objs(struct req_que *, 0), which returns ZERO_SIZE_PTR. That is
not NULL, so the allocation check passes and the following
"ha->req_q_map[0] = req" dereferences ZERO_SIZE_PTR, corrupting memory
or crashing the kernel.
Add qla_calc_queue_count() to clamp the derived value into
[1, QLA_MAX_QUEUES - 1] so it always fits in u8 and is never zero, and
use it at all three derivation sites (qla25xx_iospace_config(),
qla83xx_iospace_config() and qla24xx_enable_msix()). Also guard the
target-mode decrement so it cannot reintroduce a zero (which would in
turn underflow max_qpairs).
Fixes: d74595278f ("scsi: qla2xxx: Add multiple queue pair functionality.")
Cc: stable@vger.kernel.org
Reported-by: Sashiko <sashiko-dev@google.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Link: https://patch.msgid.link/20260730155838.2119230-2-njavali@marvell.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
committed by
Martin K. Petersen (Oracle)
parent
34ea7691e5
commit
ebfd35c644
@@ -138,6 +138,19 @@ qla_logio_set_vp_index(struct qla_hw_data *ha, void *pkt, u16 vp_idx)
|
||||
((struct logio_entry_24xx *)pkt)->vp_index = vp_idx;
|
||||
}
|
||||
|
||||
static inline u8
|
||||
qla_calc_queue_count(u16 msix_count)
|
||||
{
|
||||
/*
|
||||
* Request/response queues are bounded by the MSI-X vector count less
|
||||
* the mailbox vector. These counters are u8, so a board advertising
|
||||
* e.g. 257 vectors would truncate msix_count - 1 (256) to 0 and hand
|
||||
* kzalloc_objs() a zero count (ZERO_SIZE_PTR), faulting on the first
|
||||
* ha->req_q_map[0] store. Clamp into [1, QLA_MAX_QUEUES - 1].
|
||||
*/
|
||||
return clamp_t(u16, msix_count - 1, 1, QLA_MAX_QUEUES - 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qla2x00_poll(struct rsp_que *rsp)
|
||||
{
|
||||
|
||||
@@ -4705,10 +4705,10 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
|
||||
ha->msix_count = ret;
|
||||
/* Recalculate queue values */
|
||||
if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) {
|
||||
ha->max_req_queues = ha->msix_count - 1;
|
||||
ha->max_req_queues = qla_calc_queue_count(ha->msix_count);
|
||||
|
||||
/* ATIOQ needs 1 vector. That's 1 less QPair */
|
||||
if (QLA_TGT_MODE_ENABLED())
|
||||
if (QLA_TGT_MODE_ENABLED() && ha->max_req_queues > 1)
|
||||
ha->max_req_queues--;
|
||||
|
||||
ha->max_rsp_queues = ha->max_req_queues;
|
||||
|
||||
@@ -2132,7 +2132,7 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
|
||||
ha->msix_count = msix + 1;
|
||||
/* Max queues are bounded by available msix vectors */
|
||||
/* MB interrupt uses 1 vector */
|
||||
ha->max_req_queues = ha->msix_count - 1;
|
||||
ha->max_req_queues = qla_calc_queue_count(ha->msix_count);
|
||||
ha->max_rsp_queues = ha->max_req_queues;
|
||||
/* Queue pairs is the max value minus the base queue pair */
|
||||
ha->max_qpairs = ha->max_rsp_queues - 1;
|
||||
@@ -2224,10 +2224,10 @@ qla83xx_iospace_config(struct qla_hw_data *ha)
|
||||
*/
|
||||
if (ql2xmqsupport || ql2xnvmeenable) {
|
||||
/* MB interrupt uses 1 vector */
|
||||
ha->max_req_queues = ha->msix_count - 1;
|
||||
ha->max_req_queues = qla_calc_queue_count(ha->msix_count);
|
||||
|
||||
/* ATIOQ needs 1 vector. That's 1 less QPair */
|
||||
if (QLA_TGT_MODE_ENABLED())
|
||||
if (QLA_TGT_MODE_ENABLED() && ha->max_req_queues > 1)
|
||||
ha->max_req_queues--;
|
||||
|
||||
ha->max_rsp_queues = ha->max_req_queues;
|
||||
|
||||
Reference in New Issue
Block a user