mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net v2 1/4] ieee802154: cc2520: ensure tailroom before skb_put() in promiscuous TX
       [not found] <20260919213639.3316625-1-benquike@gmail.com>
@ 2026-09-21  7:42 ` Hui Peng
  2026-09-21  7:42 ` [PATCH net v2 2/4] ieee802154: cc2520: flush fifop_irqwork before destroying buffer_mutex in probe Hui Peng
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Hui Peng @ 2026-09-21  7:42 UTC (permalink / raw)
  To: Alexander Aring, Miquel Raynal, Stefan Schmidt
  Cc: linux-wpan, netdev, linux-kernel, Hui Peng, stable

In cc2520_tx(), when priv->promiscuous is enabled, skb_put(skb, 2) is
called unconditionally to append the 2-byte software CRC without checking
whether the skb has at least 2 bytes of tailroom, triggering
skb_over_panic when skb_tailroom(skb) < 2:

  skbuff: skb_over_panic: text:ffffffffc080071a len:386 put:2
  kernel BUG at net/core/skbuff.c:214!
  Oops: invalid opcode: 0000 [#1] SMP KASAN PTI
  RIP: 0010:skb_panic+0x170/0x172
  Call Trace:
   <TASK>
   skb_put.cold+0x23/0x23
   cc2520_tx.constprop.0.isra.0+0x8a/0x1d0

Ensure at least 2 bytes of tailroom via pskb_expand_head() before calling
skb_put(skb, 2).

Tested in QEMU with KASAN enabled by passing a zero-tailroom skb to
cc2520_tx() with promiscuous mode enabled.

Fixes: 59869ebfe7a7 ("ieee802154: cc2520: Check CRC & add promiscuous")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
Changes in v2:
- Split the cc2520 and mcr20a fixes into four single-issue patches
  (1/4..4/4) and documented each change in its own commit message as
  requested by Miquel Raynal.

 drivers/net/ieee802154/cc2520.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
index abfcfe0..5454872 100644
--- a/drivers/net/ieee802154/cc2520.c
+++ b/drivers/net/ieee802154/cc2520.c
@@ -482,8 +482,14 @@ cc2520_tx(struct ieee802154_hw *hw, struct sk_buff *skb)
 	 * values on RX. This means we need to manually add the CRC on TX.
 	 */
 	if (priv->promiscuous) {
-		u16 crc = crc_ccitt(0, skb->data, skb->len);
+		u16 crc;
 
+		if (skb_tailroom(skb) < 2 &&
+		    pskb_expand_head(skb, 0, 2, GFP_KERNEL)) {
+			rc = -ENOMEM;
+			goto err_tx;
+		}
+		crc = crc_ccitt(0, skb->data, skb->len);
 		put_unaligned_le16(crc, skb_put(skb, 2));
 		pkt_len = skb->len;
 	} else {
-- 
2.47.3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net v2 2/4] ieee802154: cc2520: flush fifop_irqwork before destroying buffer_mutex in probe
       [not found] <20260919213639.3316625-1-benquike@gmail.com>
  2026-09-21  7:42 ` [PATCH net v2 1/4] ieee802154: cc2520: ensure tailroom before skb_put() in promiscuous TX Hui Peng
@ 2026-09-21  7:42 ` Hui Peng
  2026-09-22  7:44   ` netdev-bot+sashiko
  2026-09-21  7:42 ` [PATCH net v2 3/4] ieee802154: mcr20a: drop corrupted RX frames instead of reading 125 stale bytes Hui Peng
  2026-09-21  7:42 ` [PATCH net v2 4/4] ieee802154: mcr20a: fix 1-byte out-of-bounds read in mcr20a_handle_tx() Hui Peng
  3 siblings, 1 reply; 7+ messages in thread
From: Hui Peng @ 2026-09-21  7:42 UTC (permalink / raw)
  To: Alexander Aring, Miquel Raynal, Stefan Schmidt
  Cc: linux-wpan, netdev, linux-kernel, Hui Peng, stable

In cc2520_probe()'s err_hw_init path, mutex_destroy(&priv->buffer_mutex)
is called before flush_work(&priv->fifop_irqwork). If fifop_irq fires
after devm_request_irq() and schedules priv->fifop_irqwork before probe
fails, cc2520_fifop_irqwork() can lock priv->buffer_mutex after it has
already been destroyed:

  BUG: KASAN: slab-use-after-free in assign_work+0x2f1/0x340
  Read of size 8 at addr ffff88800246b0b0 by task kworker/1:1/43
  Workqueue:  0x0 (events)
  Call Trace:
   <TASK>
   dump_stack_lvl+0x70/0xa0
   print_report+0x153/0x4c6
   kasan_report+0xf1/0x120
   assign_work+0x2f1/0x340
   worker_thread+0x2b8/0xb70

Flush priv->fifop_irqwork before mutex_destroy(&priv->buffer_mutex),
matching the teardown order in cc2520_remove().

Tested in QEMU with KASAN enabled by scheduling fifop_irqwork on the
cc2520_probe() error path.

Fixes: ff5891b266a7 ("ieee802154: cc2520: fix FIFOP work use-after-free")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
Changes in v2:
- Split out as patch 2/4 and documented the probe cleanup ordering fix and
  Fixes: tag as requested by Miquel Raynal.

 drivers/net/ieee802154/cc2520.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
index 5454872..d2c8484 100644
--- a/drivers/net/ieee802154/cc2520.c
+++ b/drivers/net/ieee802154/cc2520.c
@@ -1153,8 +1153,8 @@ static int cc2520_probe(struct spi_device *spi)
 	return 0;
 
 err_hw_init:
-	mutex_destroy(&priv->buffer_mutex);
 	flush_work(&priv->fifop_irqwork);
+	mutex_destroy(&priv->buffer_mutex);
 	return ret;
 }
 
-- 
2.47.3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net v2 3/4] ieee802154: mcr20a: drop corrupted RX frames instead of reading 125 stale bytes
       [not found] <20260919213639.3316625-1-benquike@gmail.com>
  2026-09-21  7:42 ` [PATCH net v2 1/4] ieee802154: cc2520: ensure tailroom before skb_put() in promiscuous TX Hui Peng
  2026-09-21  7:42 ` [PATCH net v2 2/4] ieee802154: cc2520: flush fifop_irqwork before destroying buffer_mutex in probe Hui Peng
@ 2026-09-21  7:42 ` Hui Peng
  2026-09-22  7:44   ` netdev-bot+sashiko
  2026-09-21  7:42 ` [PATCH net v2 4/4] ieee802154: mcr20a: fix 1-byte out-of-bounds read in mcr20a_handle_tx() Hui Peng
  3 siblings, 1 reply; 7+ messages in thread
From: Hui Peng @ 2026-09-21  7:42 UTC (permalink / raw)
  To: Alexander Aring, Miquel Raynal, Stefan Schmidt
  Cc: linux-wpan, netdev, linux-kernel, Hui Peng, stable

In mcr20a_handle_rx_read_buf_complete(), when
!ieee802154_is_valid_psdu_len(len) is true, the driver overwrites len
with IEEE802154_MTU (127) and copies 125 bytes from lp->rx_buf into a new
skb even though only the original len bytes were transferred over SPI,
reading past the valid RX data and leaking up to 125 bytes of stale heap
memory to the network stack:

  BUG: KASAN: slab-out-of-bounds in mcr20a_handle_rx_read_buf_complete.constprop.0+0x91/0xc0
  Read of size 125 at addr ffff888002853f40 by task init/1
  Call Trace:
   <TASK>
   dump_stack_lvl+0x70/0xa0
   print_report+0x153/0x4c6
   kasan_report+0xf1/0x120
   kasan_check_range+0x125/0x200
   __asan_memcpy+0x23/0x60
   mcr20a_handle_rx_read_buf_complete.constprop.0+0x91/0xc0
  ...
  The buggy address belongs to the object at ffff888002853f40
   which belongs to the cache kmalloc-8 of size 8
  The buggy address is located 0 bytes inside of
   allocated 4-byte region [ffff888002853f40, ffff888002853f44)

Drop the corrupted frame, re-arm reception via mcr20a_request_rx(lp), and
return early.

Tested in QEMU with KASAN enabled by passing a corrupted 4-byte RX frame
length to mcr20a_handle_rx_read_buf_complete().

Fixes: 8c6ad9cc5157 ("ieee802154: Add NXP MCR20A IEEE 802.15.4 transceiver driver")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
Changes in v2:
- Split out as patch 3/4 covering only the mcr20a RX corrupted frame
  handling as requested by Miquel Raynal.

 drivers/net/ieee802154/mcr20a.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
index 020d392a98b6..d01b277d33d2 100644
--- a/drivers/net/ieee802154/mcr20a.c
+++ b/drivers/net/ieee802154/mcr20a.c
@@ -790,7 +790,8 @@ mcr20a_handle_rx_read_buf_complete(void *context)
 
 	if (!ieee802154_is_valid_psdu_len(len)) {
 		dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
-		len = IEEE802154_MTU;
+		mcr20a_request_rx(lp);
+		return;
 	}
 
 	len = len - 2;  /* get rid of frame check field */
-- 
2.47.3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net v2 4/4] ieee802154: mcr20a: fix 1-byte out-of-bounds read in mcr20a_handle_tx()
       [not found] <20260919213639.3316625-1-benquike@gmail.com>
                   ` (2 preceding siblings ...)
  2026-09-21  7:42 ` [PATCH net v2 3/4] ieee802154: mcr20a: drop corrupted RX frames instead of reading 125 stale bytes Hui Peng
@ 2026-09-21  7:42 ` Hui Peng
  2026-09-22  7:44   ` netdev-bot+sashiko
  3 siblings, 1 reply; 7+ messages in thread
From: Hui Peng @ 2026-09-21  7:42 UTC (permalink / raw)
  To: Alexander Aring, Miquel Raynal, Stefan Schmidt
  Cc: linux-wpan, netdev, linux-kernel, Hui Peng, stable

In mcr20a_handle_tx(), the 1-byte psduLength prefix (lp->tx_len[0]) is
already sent in a separate SPI transfer (lp->tx_xfer_len), while
lp->tx_xfer_buf transfers the payload from lp->tx_skb->data. Setting
lp->tx_xfer_buf.len = lp->tx_skb->len + 1 causes the SPI transfer to read
1 byte past the end of lp->tx_skb->data:

  BUG: KASAN: slab-out-of-bounds in mcr20a_handle_tx+0xf5/0x150
  Read of size 17 at addr ffff8880057f7500 by task init/1
  Call Trace:
   <TASK>
   dump_stack_lvl+0x70/0xa0
   print_report+0x153/0x4c6
   kasan_report+0xf1/0x120
   kasan_check_range+0x125/0x200
   __asan_memcpy+0x23/0x60
   mcr20a_handle_tx+0xf5/0x150
  ...
  The buggy address belongs to the object at ffff8880057f7500
   which belongs to the cache kmalloc-16 of size 16
  The buggy address is located 0 bytes inside of
   allocated 16-byte region [ffff8880057f7500, ffff8880057f7510)

Set lp->tx_xfer_buf.len to lp->tx_skb->len.

Tested in QEMU with KASAN enabled by transferring a 16-byte tx_skb->data
buffer in mcr20a_handle_tx().

Fixes: 8c6ad9cc5157 ("ieee802154: Add NXP MCR20A IEEE 802.15.4 transceiver driver")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Hui Peng <benquike@gmail.com>
---
Changes in v2:
- Split out as patch 4/4 covering only the mcr20a TX SPI transfer length
  fix as requested by Miquel Raynal.

 drivers/net/ieee802154/mcr20a.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
index d01b277d33d2..d7e076397550 100644
--- a/drivers/net/ieee802154/mcr20a.c
+++ b/drivers/net/ieee802154/mcr20a.c
@@ -867,8 +867,7 @@ mcr20a_handle_tx(struct mcr20a_local *lp)
 	/* add 2 bytes of FCS */
 	lp->tx_len[0]		= lp->tx_skb->len + 2;
 	lp->tx_xfer_buf.tx_buf	= lp->tx_skb->data;
-	/* add 1 byte psduLength */
-	lp->tx_xfer_buf.len	= lp->tx_skb->len + 1;
+	lp->tx_xfer_buf.len	= lp->tx_skb->len;
 
 	ret = spi_async(lp->spi, &lp->tx_buf_msg);
 	if (ret) {
-- 
2.47.3

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net v2 2/4] ieee802154: cc2520: flush fifop_irqwork before destroying buffer_mutex in probe
  2026-09-21  7:42 ` [PATCH net v2 2/4] ieee802154: cc2520: flush fifop_irqwork before destroying buffer_mutex in probe Hui Peng
@ 2026-09-22  7:44   ` netdev-bot+sashiko
  0 siblings, 0 replies; 7+ messages in thread
From: netdev-bot+sashiko @ 2026-09-22  7:44 UTC (permalink / raw)
  To: benquike
  Cc: alex.aring, miquel.raynal, stefan, linux-wpan, netdev,
	linux-kernel, stable, kuba

Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.

Critical: 0 · High: 1 · Medium: 2 (1) · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [High] Incomplete fix: the cc2520_probe() error path
  (drivers/net/ieee802154/cc2520.c:1155-1158) still uses…
- [Medium] The commit message's quoted evidence does not match the defect
  it describes or the change it makes.
- [Medium] Incorrect Fixes: tag / wrong stable backport range.

Pre-existing issues:
- [Medium] Pre-existing: the cc2520_probe() error path does not roll back
  the hardware power/reset ramp.

--

ieee802154: cc2520: flush fifop_irqwork before destroying buffer_mutex in probe

This swaps two statements on the err_hw_init path of cc2520_probe() so that
flush_work(&priv->fifop_irqwork) runs before mutex_destroy(&priv->buffer_mutex),
with the stated goal of matching the teardown order used by cc2520_remove().

A few questions about the change and the commit log below.

>From the commit message:

>     In cc2520_probe()'s err_hw_init path, mutex_destroy(&priv->buffer_mutex)
>     is called before flush_work(&priv->fifop_irqwork). If fifop_irq fires
>     after devm_request_irq() and schedules priv->fifop_irqwork before probe
>     fails, cc2520_fifop_irqwork() can lock priv->buffer_mutex after it has
>     already been destroyed:
>
>       BUG: KASAN: slab-use-after-free in assign_work+0x2f1/0x340
>       Read of size 8 at addr ffff88800246b0b0 by task kworker/1:1/43
>       Workqueue:  0x0 (events)
>       Call Trace:
>        <TASK>
>        dump_stack_lvl+0x70/0xa0
>        print_report+0x153/0x4c6
>        kasan_report+0xf1/0x120
>        assign_work+0x2f1/0x340
>        worker_thread+0x2b8/0xb70

[Severity: Medium]
Does this trace actually correspond to the ordering problem being described?

For !CONFIG_DEBUG_MUTEXES, include/linux/mutex.h has:

	static inline void mutex_destroy(struct mutex *lock) {}

so on production kernels the reorder is a no-op.  With
CONFIG_DEBUG_MUTEXES, kernel/locking/mutex-debug.c does:

	void mutex_destroy(struct mutex *lock)
	{
		DEBUG_LOCKS_WARN_ON(mutex_is_locked(lock));
		lock->magic = NULL;
	}

which can produce a DEBUG_LOCKS warning on a subsequent mutex_lock(), but
does not free any memory.

The pasted report is a use-after-free on the work_struct inside the
workqueue core (assign_work()/worker_thread()), i.e. priv freed while the
work was still queued, which is a different failure from
cc2520_fifop_irqwork() locking a destroyed buffer_mutex.  Could the commit
message be adjusted so the quoted symptom matches the described defect,
given that the log carries Cc: stable@vger.kernel.org?

Similarly, does "Tested in QEMU with KASAN enabled by scheduling
fifop_irqwork on the cc2520_probe() error path" demonstrate the described
mutex ordering issue, or the queued-work-after-free one?

>     Fixes: ff5891b266a7 ("ieee802154: cc2520: fix FIFOP work use-after-free")

[Severity: Medium]
Is this the right commit to blame?  ff5891b266a7 changes only
cc2520_remove(), where it replaced the flush with:

	disable_work_sync(&priv->fifop_irqwork);

git blame of the err_hw_init sequence being reordered here points at
0da6bc8cc341 ("ieee802154: cc2520: adds driver for TI CC2520 radio") from
2014, not ff5891b266a7.  With the current tag, stable trees that predate
ff5891b266a7 would not pick this up.

> diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
> index 545487223838..d2c8484d8fea 100644
> --- a/drivers/net/ieee802154/cc2520.c
> +++ b/drivers/net/ieee802154/cc2520.c
> @@ -1153,8 +1153,8 @@ static int cc2520_probe(struct spi_device *spi)
>  	return 0;
>  
>  err_hw_init:
> -	mutex_destroy(&priv->buffer_mutex);
>  	flush_work(&priv->fifop_irqwork);
> +	mutex_destroy(&priv->buffer_mutex);
>  	return ret;
>  }

[Severity: High]
Can flush_work() close this window at all while the FIFOP interrupt is
still armed?

The FIFOP handler re-queues unconditionally on every edge:

	static irqreturn_t cc2520_fifop_isr(int irq, void *data)
	{
		struct cc2520_private *priv = data;

		schedule_work(&priv->fifop_irqwork);

		return IRQ_HANDLED;
	}

flush_work() waits for a queued or running instance but does not prevent a
new submission, and the irq was requested with devm_request_irq(), so it
stays registered until the driver core unwinds devres after probe returns:

cc2520_probe() [err_hw_init]
    flush_work(&priv->fifop_irqwork);      /* CPU0 */
                                           /* CPU1: FIFOP edge ->
                                              cc2520_fifop_isr() ->
                                              schedule_work() re-queues */
    mutex_destroy(&priv->buffer_mutex);
    return ret;
really_probe()
    device_unbind_cleanup()
        devres_release_all()               /* frees the irq and the
                                              devm_kzalloc'ed priv */

priv embeds both fifop_irqwork and buffer_mutex, so the worker pool then
touches a freed work_struct, and cc2520_fifop_irqwork() can dereference
freed priv:

	if (gpiod_get_value(priv->fifo_pin))
		cc2520_rx(priv);
	...
	cc2520_cmd_strobe(priv, CC2520_CMD_SFLUSHRX);

reaching cc2520_cmd_strobe(), which locks the destroyed and freed
buffer_mutex.  That is the same assign_work()/worker_thread() signature
quoted in the commit message.

Would disable_work_sync() be appropriate here, the way ff5891b266a7 handled
cc2520_remove() for exactly this devm-irq-outlives-teardown case?
Alternatively, releasing or masking the FIFOP irq before draining the work.

There is also the cc2520_register() failure case, where priv->hw is freed
but not cleared:

	err_free_device:
		ieee802154_free_hw(priv->hw);

so a surviving work item can reach a freed hw through
cc2520_rx()->ieee802154_rx_irqsafe().

For reference, no later patch in this series changes this path; err_hw_init
still reads flush_work() followed by mutex_destroy() at the end of the
series.

[Severity: Medium]
This isn't a bug introduced by this patch, but while the err_hw_init path is
being touched: should it also unwind the power and reset ramp done earlier in
cc2520_probe()?

	gpiod_set_value(vreg, HIGH);
	usleep_range(100, 150);

	gpiod_set_value(reset, HIGH);
	usleep_range(200, 250);

err_hw_init only flushes the work and destroys the mutex.  Releasing a gpio
descriptor through devres does not restore its output level, so after a
failure in cc2520_hw_init(), either devm_request_irq(), or cc2520_register(),
the CC2520 stays powered and out of reset with no driver bound.  On a later
re-bind, reset is already HIGH, so does cc2520_hw_init() then program a chip
that never saw a reset pulse?  This dates back to the original driver
(0da6bc8cc341).

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260921074207.2289391-1-benquike%40gmail.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net v2 3/4] ieee802154: mcr20a: drop corrupted RX frames instead of reading 125 stale bytes
  2026-09-21  7:42 ` [PATCH net v2 3/4] ieee802154: mcr20a: drop corrupted RX frames instead of reading 125 stale bytes Hui Peng
@ 2026-09-22  7:44   ` netdev-bot+sashiko
  0 siblings, 0 replies; 7+ messages in thread
From: netdev-bot+sashiko @ 2026-09-22  7:44 UTC (permalink / raw)
  To: benquike
  Cc: alex.aring, miquel.raynal, stefan, linux-wpan, netdev,
	linux-kernel, stable, kuba

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.

Critical: 0 · High: 0 (2) · Medium: 1 · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] The commit message justifies the change with a KASAN slab-out-
  of-bounds splat ("Read of size 125 at addr ffff888002853f40 ... cache…

Pre-existing issues:
- [High] mcr20a_irq_status_complete() unconditionally programs XCVSEQ to
  MCR20A_XCVSEQ_IDLE (mcr20a.c:938-939) before the RX length/buffer read…
- [High] mcr20a_handle_rx_read_buf_complete() strips the two FCS bytes
  from the received PSDU (`len = len - 2; /* get rid of frame check…

--

ieee802154: mcr20a: drop corrupted RX frames instead of reading 125 stale bytes

When the reported PSDU length is invalid, mcr20a_handle_rx_read_buf_complete()
no longer forces len to IEEE802154_MTU and copies the whole buffer; it now
drops the frame and re-arms reception with mcr20a_request_rx(lp).

First, a question about the justification in the commit message:

>     In mcr20a_handle_rx_read_buf_complete(), when
>     !ieee802154_is_valid_psdu_len(len) is true, the driver overwrites len
>     with IEEE802154_MTU (127) and copies 125 bytes from lp->rx_buf into a new
>     skb even though only the original len bytes were transferred over SPI,
>     reading past the valid RX data and leaking up to 125 bytes of stale heap
>     memory to the network stack:
>
>       BUG: KASAN: slab-out-of-bounds in mcr20a_handle_rx_read_buf_complete.constprop.0+0x91/0xc0
>       Read of size 125 at addr ffff888002853f40 by task init/1
>       ...
>       The buggy address belongs to the object at ffff888002853f40
>        which belongs to the cache kmalloc-8 of size 8
>       The buggy address is located 0 bytes inside of
>        allocated 4-byte region [ffff888002853f40, ffff888002853f44)

[Severity: Medium]
Can this KASAN splat actually be produced by this driver?  The memcpy source
in mcr20a_handle_rx_read_buf_complete() is lp->rx_buf, which is a fixed array
embedded in struct mcr20a_local:

drivers/net/ieee802154/mcr20a.c:
	u8 rx_buf[MCR20A_MAX_BUF];

with MCR20A_MAX_BUF defined as 127, and mcr20a_setup_rx_spi_messages() binds
the SPI transfer to it permanently:

	lp->rx_xfer_buf.rx_buf = lp->rx_buf;

struct mcr20a_local itself is the priv blob from ieee802154_alloc_hw(sizeof(*lp),
...), so a 125-byte read from rx_buf stays inside the object and cannot be
reported as a slab-out-of-bounds access, and the source object can never be a
4-byte allocation in kmalloc-8.  The only small heap object in the driver is
lp->buf from devm_kzalloc(SPI_COMMAND_BUFFER), which is never the memcpy
source here.

The defect the patch fixes looks narrower: mcr20a_handle_rx_read_len_complete()
only refreshes lp->rx_xfer_buf.len bytes,

	lp->rx_xfer_buf.len = len;

so with the old "len = IEEE802154_MTU" fallback the driver handed the stale
tail of its own RX buffer (leftovers of previously received frames, or zeros)
to the 802.15.4 stack as if it were received data.  Given the Cc: stable tag,
would it make sense to describe it that way and drop the KASAN block, so that
backporters do not read this as an out-of-bounds read?

> diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> index 020d392a98b6..ee3c1e67ef60 100644
> --- a/drivers/net/ieee802154/mcr20a.c
> +++ b/drivers/net/ieee802154/mcr20a.c
> @@ -790,7 +790,8 @@ mcr20a_handle_rx_read_buf_complete(void *context)
>  
>  	if (!ieee802154_is_valid_psdu_len(len)) {
>  		dev_vdbg(&lp->spi->dev, "corrupted frame received\n");
> -		len = IEEE802154_MTU;
> +		mcr20a_request_rx(lp);
> +		return;
>  	}
>  
>  	len = len - 2;  /* get rid of frame check field */

[Severity: High]
This isn't a bug introduced by this patch, but the new branch highlights the
sibling exits of the same RX chain that do not re-arm reception.
mcr20a_irq_status_complete() always parks the sequence manager first:

	regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1,
				 DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_IDLE);

so RX only resumes when mcr20a_request_rx() writes MCR20A_XCVSEQ_RX.  A few
lines below the hunk, mcr20a_handle_rx_read_buf_complete() returns without
doing that:

	skb = dev_alloc_skb(len);
	if (!skb)
		return;

and mcr20a_handle_rx_read_len_complete() does the same on a submission
failure:

	ret = spi_async(lp->spi, &lp->rx_buf_msg);
	if (ret)
		dev_err(printdev(lp), "failed to read rx buffer length\n");

With XCVSEQ left at IDLE, does the part generate any further RXIRQ/SEQIRQ that
could restart the chain?  mcr20a_request_rx() is only reachable from
mcr20a_handle_rx_read_buf_complete(), mcr20a_handle_tx_complete() and
mcr20a_start(), so recovery would seem to require a transmit or an interface
down/up, while the netdev stays up and silently deaf - for a receive-only or
monitor configuration there is no such event.  Would it be worth re-arming RX
on these paths too, in the same way the new corrupted-length branch does?

Related: mcr20a_request_rx() issues the re-arm with
regmap_update_bits_async() and returns 0 unconditionally:

	regmap_update_bits_async(lp->regmap_dar, DAR_PHY_CTRL1,
				 DAR_PHY_CTRL1_XCVSEQ_MASK, MCR20A_XCVSEQ_RX);

	return 0;

so is a failed register write distinguishable from a successful re-arm?

[Severity: High]
This is a pre-existing issue, but it sits on the length computation this patch
touches.  The driver removes the two FCS bytes and hands the FCS-less data to
ieee802154_rx_irqsafe(), while mcr20a_hw_setup() advertises:

	hw->flags = IEEE802154_HW_TX_OMIT_CKSUM |
			IEEE802154_HW_AFILT |
			IEEE802154_HW_PROMISCUOUS;

i.e. without IEEE802154_HW_RX_OMIT_CKSUM.  In net/mac802154/rx.c,
ieee802154_rx() only synthesizes an FCS when that flag is set, and then trims
two bytes regardless:

	if (local->hw.flags & IEEE802154_HW_RX_OMIT_CKSUM) {
		crc = crc_ccitt(0, skb->data, skb->len);
		put_unaligned_le16(crc, skb_put(skb, 2));
	}
	...
	skb_trim(skb, skb->len - 2);

Does this mean every frame received through mcr20a loses two bytes of real MAC
payload, and gets dropped by the crc_ccitt() check when
phy->filtering == IEEE802154_FILTERING_NONE?  adf7242, the other driver that
strips the CRC, sets IEEE802154_HW_OMIT_CKSUM in adf7242_hw_init().  Should
mcr20a either advertise IEEE802154_HW_RX_OMIT_CKSUM or keep the FCS in the
skb?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260921074207.2289391-1-benquike%40gmail.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net v2 4/4] ieee802154: mcr20a: fix 1-byte out-of-bounds read in mcr20a_handle_tx()
  2026-09-21  7:42 ` [PATCH net v2 4/4] ieee802154: mcr20a: fix 1-byte out-of-bounds read in mcr20a_handle_tx() Hui Peng
@ 2026-09-22  7:44   ` netdev-bot+sashiko
  0 siblings, 0 replies; 7+ messages in thread
From: netdev-bot+sashiko @ 2026-09-22  7:44 UTC (permalink / raw)
  To: benquike
  Cc: alex.aring, miquel.raynal, stefan, linux-wpan, netdev,
	linux-kernel, stable, kuba

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.

Critical: 0 · High: 0 (1) · Medium: 1 · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] The commit message of "ieee802154: mcr20a: fix 1-byte out-of-
  bounds read in mcr20a_handle_tx()" misrepresents the severity of the…

Pre-existing issues:
- [High] Unhandled spi_async() failure in the TX state machine leaks the
  skb and wedges the TX queue forever.

--

ieee802154: mcr20a: fix 1-byte out-of-bounds read in mcr20a_handle_tx()

This drops the "+ 1" from lp->tx_xfer_buf.len in mcr20a_handle_tx(), so the
payload SPI transfer now clocks out exactly lp->tx_skb->len bytes instead of
one extra byte. The 1-byte psduLength prefix is already carried by the
separate lp->tx_xfer_len transfer.

A couple of questions below, one about the commit message and one about the
error path that the hunk touches.

>     In mcr20a_handle_tx(), the 1-byte psduLength prefix (lp->tx_len[0]) is
>     already sent in a separate SPI transfer (lp->tx_xfer_len), while
>     lp->tx_xfer_buf transfers the payload from lp->tx_skb->data. Setting
>     lp->tx_xfer_buf.len = lp->tx_skb->len + 1 causes the SPI transfer to read
>     1 byte past the end of lp->tx_skb->data:
>
>       BUG: KASAN: slab-out-of-bounds in mcr20a_handle_tx+0xf5/0x150
>       Read of size 17 at addr ffff8880057f7500 by task init/1
>       ...
>       The buggy address belongs to the object at ffff8880057f7500
>        which belongs to the cache kmalloc-16 of size 16

[Severity: Medium]
Can this splat actually be produced by the driver's own TX path?

lp->tx_skb comes from mac802154 via mcr20a_xmit(), and an skb head allocated
by __alloc_skb()/kmalloc_reserve() is always sized as the data area plus
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) inside one slab object.
sizeof(struct skb_shared_info) alone is a few hundred bytes, so an skb head
cannot live in kmalloc-16, and skb->data[skb->len] always lands inside the
same allocation (tailroom or shared info) where KASAN has no redzone to
report.

The last paragraph says:

>     Tested in QEMU with KASAN enabled by transferring a 16-byte tx_skb->data
>     buffer in mcr20a_handle_tx().

Would it be clearer to state up front that the trace comes from an
instrumented/synthetic buffer rather than from a normal transmit, and to
describe the real effect instead?

As far as I can tell the real effect is that one byte of unrelated
in-allocation memory was clocked into the transceiver packet buffer at the
first FCS position, which the chip then overwrites because mcr20a_hw_setup()
sets IEEE802154_HW_TX_OMIT_CKSUM and the hardware generates the FCS itself.
That reads as a correctness fix with no kernel memory-safety violation and
no over-the-air leak, which matters for how stable maintainers judge the
Cc: stable tag.

The code change itself looks right: mcr20a_setup_tx_spi_messages() already
sends psduLength as its own transfer:

	lp->tx_xfer_len.len = 1;
	lp->tx_xfer_len.tx_buf = lp->tx_len;

and at86rf230_write_frame() uses the same layout (length byte = skb->len + 2,
payload = skb->len bytes).

> diff --git a/drivers/net/ieee802154/mcr20a.c b/drivers/net/ieee802154/mcr20a.c
> index ee3c1e67ef60..d7e076397550 100644
> --- a/drivers/net/ieee802154/mcr20a.c
> +++ b/drivers/net/ieee802154/mcr20a.c
> @@ -867,8 +867,7 @@ mcr20a_handle_tx(struct mcr20a_local *lp)
>  	/* add 2 bytes of FCS */
>  	lp->tx_len[0]		= lp->tx_skb->len + 2;
>  	lp->tx_xfer_buf.tx_buf	= lp->tx_skb->data;
> -	/* add 1 byte psduLength */
> -	lp->tx_xfer_buf.len	= lp->tx_skb->len + 1;
> +	lp->tx_xfer_buf.len	= lp->tx_skb->len;
>  
>  	ret = spi_async(lp->spi, &lp->tx_buf_msg);
>  	if (ret) {

[Severity: High]
This isn't a bug introduced by this patch, but since the hunk sits right
above it: does this error path leak lp->tx_skb and stall the TX queue for
good?

	ret = spi_async(lp->spi, &lp->tx_buf_msg);
	if (ret) {
		dev_err(printdev(lp), "SPI write Failed for TX buf\n");
		return ret;
	}

On failure the message is never submitted, so no completion callback runs.
lp->tx_skb is neither completed nor freed and lp->is_tx stays 1. The only
caller discards the return value:

mcr20a_irq_clean_complete() {
	...
	case (DAR_IRQSTS1_SEQIRQ):
		if (lp->is_tx) {
			dev_dbg(printdev(lp), "TX is starting\n");
			mcr20a_handle_tx(lp);
	...
}

Meanwhile ieee802154_tx() in net/mac802154/tx.c already did
ieee802154_hold_queue() and atomic_inc(&local->phy->ongoing_txs) when the
earlier drv_xmit_async() (mcr20a_xmit()) returned 0, and only
mcr20a_handle_tx_complete() -> ieee802154_xmit_complete() undoes that. So
the queue is never woken and ongoing_txs stays non-zero.

Does that then make ieee802154_sync_queue() wait forever?

net/mac802154/tx.c:ieee802154_sync_queue() {
	...
	wait_event(local->phy->sync_txq, !atomic_read(&local->phy->ongoing_txs));
	...
}

There is no timeout and no alternative wake condition, so any MLME operation
going through ieee802154_mlme_op_pre() would block indefinitely.

spi_async() can fail for real reasons: -EBUSY when ctlr->bus_lock_flag is
set by a concurrent spi_bus_lock() user, or an error propagated from
spi_maybe_optimize_message()/__spi_async().

Would ieee802154_xmit_error(lp->hw, lp->tx_skb, IEEE802154_SYSTEM_ERROR),
or ieee802154_wake_queue() plus kfree_skb(), together with clearing
lp->is_tx, be the right handling here?

mcr20a_write_tx_buf_complete() looks to have the same gap for the SEQ TX
register write:

	ret = spi_async(lp->spi, &lp->reg_msg);
	if (ret)
		dev_err(printdev(lp), "failed to set SEQ TX\n");

Should that path also release the skb and the queue?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260921074207.2289391-1-benquike%40gmail.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-09-22  7:44 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20260919213639.3316625-1-benquike@gmail.com>
2026-09-21  7:42 ` [PATCH net v2 1/4] ieee802154: cc2520: ensure tailroom before skb_put() in promiscuous TX Hui Peng
2026-09-21  7:42 ` [PATCH net v2 2/4] ieee802154: cc2520: flush fifop_irqwork before destroying buffer_mutex in probe Hui Peng
2026-09-22  7:44   ` netdev-bot+sashiko
2026-09-21  7:42 ` [PATCH net v2 3/4] ieee802154: mcr20a: drop corrupted RX frames instead of reading 125 stale bytes Hui Peng
2026-09-22  7:44   ` netdev-bot+sashiko
2026-09-21  7:42 ` [PATCH net v2 4/4] ieee802154: mcr20a: fix 1-byte out-of-bounds read in mcr20a_handle_tx() Hui Peng
2026-09-22  7:44   ` netdev-bot+sashiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®