From: Michael Bommarito <michael.bommarito@gmail.com>
To: Samuel Mendoza-Jonas <sam@mendozajonas.com>,
Paul Fertser <fercerpav@gmail.com>,
netdev@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
linux-kernel@vger.kernel.org,
Michael Bommarito <michael.bommarito@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH net 2/6] net/ncsi: bound filter table state to software limits
Date: Wed, 22 Apr 2026 12:03:38 -0400 [thread overview]
Message-ID: <20260422160342.1975093-3-michael.bommarito@gmail.com> (raw)
In-Reply-To: <20260422160342.1975093-1-michael.bommarito@gmail.com>
The NCSI filter state uses single-word bitmaps for both MAC and VLAN
entries, but Get Capabilities and Get Parameters responses can still
feed larger counts into that state.
Cap the stored VLAN table size to the bitmap width before it reaches
the manage-side bitmap walkers, reject GP tables that exceed the sizes
advertised by GC, and stop indexing the MAC filter bitmap past its
software capacity. Also stop shifting past the width of the enable
bitfields when GP reports more entries than fit in those masks.
This keeps oversized or inconsistent filter counts from turning into
out-of-bounds bitmap accesses and oversized table walks in the response
and manage paths. A follow-up patch in this series separately validates
that the GP payload actually covers the consumed MAC/VLAN table bytes.
A live x86_64/KASAN QEMU repro can drive this after GC advertises a
single MAC filter slot and GP then reports mac_cnt=65. Without this
change, KASAN reports a slab-out-of-bounds write in
ncsi_rsp_handler_gp(); with this change applied, the same reply is
rejected with -ERANGE.
Fixes: 062b3e1b6d4f ("net/ncsi: Refactor MAC, VLAN filters")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
net/ncsi/ncsi-rsp.c | 46 ++++++++++++++++++++++++++++++++++++---------
1 file changed, 37 insertions(+), 9 deletions(-)
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 1fe061ede26d..47ddf2bbb13b 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -22,6 +22,8 @@
/* Nibbles within [0xA, 0xF] add zero "0" to the returned value.
* Optional fields (encoded as 0xFF) will default to zero.
*/
+#define NCSI_FILTER_BITS BITS_PER_TYPE(u64)
+
static u8 decode_bcd_u8(u8 x)
{
int lo = x & 0xF;
@@ -32,6 +34,12 @@ static u8 decode_bcd_u8(u8 x)
return lo + hi * 10;
}
+static bool ncsi_filter_is_enabled(unsigned long enable, unsigned int index,
+ unsigned int nbits)
+{
+ return index < nbits && (enable & BIT(index));
+}
+
static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
unsigned short payload)
{
@@ -481,7 +489,8 @@ static int ncsi_rsp_handler_sma(struct ncsi_request *nr)
bitmap = &ncf->bitmap;
if (cmd->index == 0 ||
- cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed)
+ cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed ||
+ cmd->index > NCSI_FILTER_BITS)
return -ERANGE;
index = (cmd->index - 1) * ETH_ALEN;
@@ -798,6 +807,7 @@ static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
struct ncsi_channel *nc;
struct ncsi_package *np;
size_t size;
+ unsigned int vlan_cnt;
/* Find the channel */
rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp);
@@ -819,6 +829,12 @@ static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode &
NCSI_CAP_VLAN_MASK;
+ vlan_cnt = min_t(unsigned int, rsp->vlan_cnt, NCSI_FILTER_BITS);
+ if (vlan_cnt != rsp->vlan_cnt)
+ netdev_warn(ndp->ndev.dev,
+ "NCSI: VLAN filter count %u exceeds software limit %u\n",
+ rsp->vlan_cnt, (unsigned int)NCSI_FILTER_BITS);
+
size = (rsp->uc_cnt + rsp->mc_cnt + rsp->mixed_cnt) * ETH_ALEN;
nc->mac_filter.addrs = kzalloc(size, GFP_ATOMIC);
if (!nc->mac_filter.addrs)
@@ -827,7 +843,7 @@ static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
nc->mac_filter.n_mc = rsp->mc_cnt;
nc->mac_filter.n_mixed = rsp->mixed_cnt;
- nc->vlan_filter.vids = kcalloc(rsp->vlan_cnt,
+ nc->vlan_filter.vids = kcalloc(vlan_cnt,
sizeof(*nc->vlan_filter.vids),
GFP_ATOMIC);
if (!nc->vlan_filter.vids)
@@ -836,7 +852,7 @@ static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
* configuration state
*/
nc->vlan_filter.bitmap = U64_MAX;
- nc->vlan_filter.n_vids = rsp->vlan_cnt;
+ nc->vlan_filter.n_vids = vlan_cnt;
np->ndp->channel_count = rsp->channel_cnt;
return 0;
@@ -853,6 +869,9 @@ static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
unsigned char *pdata;
unsigned long flags;
void *bitmap;
+ unsigned int mac_cnt;
+ unsigned int mac_nbits;
+ unsigned int vlan_cnt;
int i;
/* Find the channel */
@@ -862,6 +881,15 @@ static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
if (!nc)
return -ENODEV;
+ ncmf = &nc->mac_filter;
+ ncvf = &nc->vlan_filter;
+ mac_cnt = min_t(unsigned int, rsp->mac_cnt, NCSI_FILTER_BITS);
+ mac_nbits = ncmf->n_uc + ncmf->n_mc + ncmf->n_mixed;
+ vlan_cnt = min_t(unsigned int, rsp->vlan_cnt, ncvf->n_vids);
+
+ if (rsp->mac_cnt > mac_nbits || rsp->vlan_cnt > ncvf->n_vids)
+ return -ERANGE;
+
/* Modes with explicit enabled indications */
if (ntohl(rsp->valid_modes) & 0x1) { /* BC filter mode */
nc->modes[NCSI_MODE_BC].enable = 1;
@@ -887,11 +915,11 @@ static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
/* MAC addresses filter table */
pdata = (unsigned char *)rsp + 48;
enable = rsp->mac_enable;
- ncmf = &nc->mac_filter;
spin_lock_irqsave(&nc->lock, flags);
bitmap = &ncmf->bitmap;
- for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) {
- if (!(enable & (0x1 << i)))
+ for (i = 0; i < mac_cnt; i++, pdata += 6) {
+ if (!ncsi_filter_is_enabled(enable, i,
+ BITS_PER_TYPE(rsp->mac_enable)))
clear_bit(i, bitmap);
else
set_bit(i, bitmap);
@@ -902,11 +930,11 @@ static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
/* VLAN filter table */
enable = ntohs(rsp->vlan_enable);
- ncvf = &nc->vlan_filter;
bitmap = &ncvf->bitmap;
spin_lock_irqsave(&nc->lock, flags);
- for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) {
- if (!(enable & (0x1 << i)))
+ for (i = 0; i < vlan_cnt; i++, pdata += 2) {
+ if (!ncsi_filter_is_enabled(enable, i,
+ BITS_PER_TYPE(rsp->vlan_enable)))
clear_bit(i, bitmap);
else
set_bit(i, bitmap);
--
2.53.0
next prev parent reply other threads:[~2026-04-22 16:05 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20260422160342.1975093-1-michael.bommarito@gmail.com>
2026-04-22 16:03 ` [PATCH net 1/6] net/ncsi: validate response packet lengths against the skb Michael Bommarito
2026-04-22 16:03 ` Michael Bommarito [this message]
2026-04-22 16:03 ` [PATCH net 3/6] net/ncsi: validate GMCMA address counts against the payload Michael Bommarito
2026-04-22 16:03 ` [PATCH net 4/6] net/ncsi: validate OEM response payloads before parsing Michael Bommarito
2026-04-22 16:03 ` [PATCH net 5/6] net/ncsi: validate AEN packet lengths against the skb Michael Bommarito
2026-04-22 16:03 ` [PATCH net 6/6] net/ncsi: validate GP payload lengths before parsing Michael Bommarito
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260422160342.1975093-3-michael.bommarito@gmail.com \
--to=michael.bommarito@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=fercerpav@gmail.com \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=sam@mendozajonas.com \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox