The branch main has been updated by adrian:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=57f5252ff8a17aa837f677638cce5885b8a5fb3b

commit 57f5252ff8a17aa837f677638cce5885b8a5fb3b
Author:     Nick Price <[email protected]>
AuthorDate: 2026-06-20 19:02:22 +0000
Commit:     Adrian Chadd <[email protected]>
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);

Reply via email to