git: 57f5252ff8a1 - main - aq(4): Fix RSS indirection table OOB write and queue distribution
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 20 Jun 2026 19:10:34 UTC
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);