All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ibrahim Hashimov <security@auditcode.ai>
To: Johannes Berg <johannes@sipsolutions.net>
Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: [PATCH net] wifi: mac80211_hwsim: reject undersized HWSIM_ATTR_TX_INFO
Date: Sat, 11 Jul 2026 17:15:51 +0200	[thread overview]
Message-ID: <20260711151551.65504-1-security@auditcode.ai> (raw)

hwsim_tx_info_frame_received_nl() casts the HWSIM_ATTR_TX_INFO
attribute payload to a `struct hwsim_tx_rate *` and then
unconditionally walks IEEE80211_TX_MAX_RATES (4) entries of it:

	tx_attempts = (struct hwsim_tx_rate *)nla_data(
		       info->attrs[HWSIM_ATTR_TX_INFO]);
	...
	for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
		txi->status.rates[i].idx = tx_attempts[i].idx;
		txi->status.rates[i].count = tx_attempts[i].count;
	}

struct hwsim_tx_rate is `{s8 idx; u8 count;} __packed`, i.e. 2 bytes,
so the loop reads a fixed 8 bytes out of the attribute regardless of
its actual length.

The attribute's policy entry only bounds the payload from above:

	[HWSIM_ATTR_TX_INFO] = { .type = NLA_BINARY,
				 .len = IEEE80211_TX_MAX_RATES *
					sizeof(struct hwsim_tx_rate)},

For NLA_BINARY, nla_policy.len is a maximum, not a minimum -
nla_validate() happily accepts a shorter attribute, including a
zero-length one. The HWSIM_CMD_TX_INFO_FRAME op also sets
GENL_DONT_VALIDATE_STRICT, so no implicit minimum-length enforcement
kicks in either. The handler itself never calls nla_len() on
HWSIM_ATTR_TX_INFO before dereferencing it.

The net effect: any process that has completed HWSIM_CMD_REGISTER as
the netgroup's wmediumd (CAP_NET_ADMIN at registration time, e.g. via
an unprivileged user+net namespace) can send a HWSIM_CMD_TX_INFO_FRAME
with a 0-length HWSIM_ATTR_TX_INFO and drive tx_attempts[0..3] to read
up to 8 bytes past the end of the attribute payload.

This driver already validates NLA_BINARY payload length before use in
two other handlers in this same file:

 - hwsim_cloned_frame_received_nl() bounds-checks HWSIM_ATTR_FRAME
   before touching it:

	frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
	...
	if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) ||
	    frame_data_len > IEEE80211_MAX_DATA_LEN)
		goto err;

 - hwsim_new_radio_nl() bounds-checks HWSIM_ATTR_CIPHER_SUPPORT before
   use, rejecting a length that doesn't cleanly divide into whole
   elements:

	u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]);
	...
	if (len % sizeof(u32)) {
		NL_SET_ERR_MSG_ATTR(...);
		return -EINVAL;
	}

hwsim_tx_info_frame_received_nl() is missing the equivalent check for
HWSIM_ATTR_TX_INFO. Add a minimum-length check next to the existing
attrs-presence check at the top of the function (before any pending
skb is unlinked from data2->pending, to avoid holding/leaking that skb
on the new error path), requiring at least
IEEE80211_TX_MAX_RATES * sizeof(struct hwsim_tx_rate) bytes - matching
the exact quantity the loop below unconditionally reads. A too-short
attribute now takes the existing `goto out;` / -EINVAL path instead of
reading past the attribute payload.

On a v6.19 KASAN-enabled stand, the differential reproducer confirmed
the unpatched handler accepts a 0-length HWSIM_ATTR_TX_INFO and runs
the fixed-count read loop to completion (ack err = 0); KASAN did not
report anything here, since the resulting 8-byte over-read stays
inside the same skb's kmalloc/shinfo tailroom rather than crossing a
slab redzone. The check added above makes the same 0-length attribute
fail before that loop runs, taking the existing goto out / -EINVAL
path instead.

Fixes: 7882513bacb1 ("mac80211_hwsim driver support userspace frame tx/rx")
Cc: stable@vger.kernel.org
Signed-off-by: Ibrahim Hashimov <security@auditcode.ai>
Assisted-by: AuditCode-AI:2026.07
---
 drivers/net/wireless/virtual/mac80211_hwsim_main.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
index 0dd8a6c85953..6ef7398ffaad 100644
--- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c
+++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c
@@ -6340,6 +6340,17 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
 	    !info->attrs[HWSIM_ATTR_TX_INFO])
 		goto out;
 
+	/*
+	 * HWSIM_ATTR_TX_INFO is NLA_BINARY with only a maximum length in
+	 * its policy entry, so nla_validate() accepts any shorter (incl.
+	 * zero-length) payload. The read loop below unconditionally walks
+	 * IEEE80211_TX_MAX_RATES entries, so reject undersized attributes
+	 * here before any data is touched.
+	 */
+	if (nla_len(info->attrs[HWSIM_ATTR_TX_INFO]) <
+	    IEEE80211_TX_MAX_RATES * sizeof(struct hwsim_tx_rate))
+		goto out;
+
 	src = (void *)nla_data(info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
 	hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
 	ret_skb_cookie = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
-- 
2.50.1 (Apple Git-155)


                 reply	other threads:[~2026-07-11 15:16 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20260711151551.65504-1-security@auditcode.ai \
    --to=security@auditcode.ai \
    --cc=johannes@sipsolutions.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.