Date: Sat, 20 Jun 2026 19:10:34 +0000 From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Nick Price <nick@spun.io> Subject: git: 57f5252ff8a1 - main - aq(4): Fix RSS indirection table OOB write and queue distribution Message-ID: <6a36e5aa.3364c.1c16886e@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by adrian: URL: https://cgit.FreeBSD.org/src/commit/?id=57f5252ff8a17aa837f677638cce5885b8a5fb3b commit 57f5252ff8a17aa837f677638cce5885b8a5fb3b Author: Nick Price <nick@spun.io> AuthorDate: 2026-06-20 19:02:22 +0000 Commit: Adrian Chadd <adrian@FreeBSD.org> CommitDate: 2026-06-20 19:10:15 +0000 aq(4): Fix RSS indirection table OOB write and queue distribution Two related fixes to `aq(4)`'s RSS indirection table handling: 1. Fix an out-of-bounds stack write in `aq_hw_rss_set()`. RSS table entries are 3 bits (8 queues max), but with more than 8 RX rings `rss_table[]` holds larger values; the 32-bit write then spills one `uint16_t` past `bitary[]` and corrupts the stack, so the NIC never links or the kernel panics. Mask each value to 3 bits and pack 16 bits at a time to keep the write in bounds. 2. Build the indirection table in `aq_if_attach_post()` with a modulo over `min(rx_rings_count, HW_ATL_RSS_INDIRECTION_QUEUES_MAX)` instead of `i & (rx_rings_count - 1)`, which assumed a power-of-two ring count. Reviewed by: adrian Differential Revision: https://reviews.freebsd.org/D57240 --- sys/dev/aq/aq_hw.c | 12 ++++++++++-- sys/dev/aq/aq_hw.h | 2 ++ sys/dev/aq/aq_main.c | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/sys/dev/aq/aq_hw.c b/sys/dev/aq/aq_hw.c index f73805a939cd..5a45e61041c3 100644 --- a/sys/dev/aq/aq_hw.c +++ b/sys/dev/aq/aq_hw.c @@ -878,8 +878,16 @@ aq_hw_rss_set(struct aq_hw_s *self, memset(bitary, 0, sizeof(bitary)); for (i = HW_ATL_RSS_INDIRECTION_TABLE_MAX; i--;) { - (*(uint32_t *)(bitary + ((i * 3U) / 16U))) |= - ((rss_table[i]) << ((i * 3U) & 0xFU)); + uint32_t bit_pos = i * HW_ATL_RSS_INDIRECTION_ENTRY_BITS; + uint32_t word = bit_pos / 16U; + uint32_t shift = bit_pos % 16U; + uint32_t field = (uint32_t)(rss_table[i] & + (HW_ATL_RSS_INDIRECTION_QUEUES_MAX - 1U)) << shift; + + bitary[word] |= (uint16_t)field; + if (shift + HW_ATL_RSS_INDIRECTION_ENTRY_BITS > 16U && + word + 1U < ARRAY_SIZE(bitary)) + bitary[word + 1U] |= (uint16_t)(field >> 16); } for (i = ARRAY_SIZE(bitary); i--;) { diff --git a/sys/dev/aq/aq_hw.h b/sys/dev/aq/aq_hw.h index a4d4dbb3a512..bdd79871fd76 100644 --- a/sys/dev/aq/aq_hw.h +++ b/sys/dev/aq/aq_hw.h @@ -197,6 +197,8 @@ struct aq_hw { #define HW_ATL_RSS_INDIRECTION_TABLE_MAX 64U #define HW_ATL_RSS_HASHKEY_SIZE 40U +#define HW_ATL_RSS_INDIRECTION_QUEUES_MAX 8U +#define HW_ATL_RSS_INDIRECTION_ENTRY_BITS 3U /* PCI core control register */ #define AQ_HW_PCI_REG_CONTROL_6_ADR 0x1014U diff --git a/sys/dev/aq/aq_main.c b/sys/dev/aq/aq_main.c index 2ed9bd050780..e893bb7f73b3 100644 --- a/sys/dev/aq/aq_main.c +++ b/sys/dev/aq/aq_main.c @@ -466,8 +466,9 @@ aq_if_attach_post(if_ctx_t ctx) aq_add_stats_sysctls(softc); /* RSS */ arc4rand(softc->rss_key, HW_ATL_RSS_HASHKEY_SIZE, 0); + uint32_t rss_qs = MIN(softc->rx_rings_count, HW_ATL_RSS_INDIRECTION_QUEUES_MAX); for (int i = ARRAY_SIZE(softc->rss_table); i--;){ - softc->rss_table[i] = i & (softc->rx_rings_count - 1); + softc->rss_table[i] = i % rss_qs; } exit: AQ_DBG_EXIT(rc);home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a36e5aa.3364c.1c16886e>
