From: Miquel Raynal <miquel.raynal@bootlin.com>
To: Kaiwen Shi <skwkevin@mail.ustc.edu.cn>
Cc: alex.aring@gmail.com, stefan@datenfreihafen.org,
linux-wpan@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH net] mac802154: fix data race and NULL deref on local->assoc_dev
Date: Tue, 25 Aug 2026 15:15:10 +0200 [thread overview]
Message-ID: <87ik4ygx41.fsf@bootlin.com> (raw)
In-Reply-To: <20260824175938.11143-1-skwkevin@mail.ustc.edu.cn> (Kaiwen Shi's message of "Tue, 25 Aug 2026 01:59:38 +0800")
Hi Kaiwen,
On 25/08/2026 at 01:59:38 +08, Kaiwen Shi <skwkevin@mail.ustc.edu.cn> wrote:
> `local->assoc_dev` is accessed from three places with no common lock
> and, on the read side, no NULL or lifetime guarantee:
>
> - mac802154_perform_association() stores the coordinator pointer in
> it, then blocks in wait_for_completion_killable_timeout() for up
> to 10 s;
>
> - its clear_assoc label sets it back to NULL;
>
> - mac802154_process_association_resp(), which runs from the
> rx_mac_cmd workqueue, dereferences
> `local->assoc_dev->extended_addr` with neither lock nor NULL
> check.
>
> The dereference races with both write sites:
>
> 1. NULL dereference: clear_assoc() stores NULL while the RESP
> handler is between loading and dereferencing the pointer; the
> subsequent dereference of `->extended_addr` on a NULL pointer
> faults.
>
> 2. use-after-free: mac802154_associate() frees the freshly
> allocated `parent` in its free_parent path after
> perform_association() returns an error. If the RESP handler
> still holds the now-dangling pointer, it reads freed memory.
>
> No existing lock serializes these accesses. The
> wpan_dev->association_lock mutex only guards the coordinator-side
> parent/child list (mac802154_process_association_req() and
> friends), which is a different data structure, and it is not held
> while this device is associating. The writer blocks in
> wait_for_completion_killable_timeout() for up to 10 s after storing
> assoc_dev, so the reader on the rx_mac_cmd workqueue races with both
> the NULL store in clear_assoc and the kfree() of the leftover
> ieee802154_pan_device in mac802154_associate()'s error path.
>
> Add a dedicated assoc_dev_lock and hold it around all three
> accesses; the RESP handler additionally validates the pointer before
> dereferencing it. This is a per-field lock so it cannot contend
> with the completion logic.
>
> Fixes: fefd19807fe9 ("mac802154: Handle associating")
This likely deserves a `Cc: stable*` tag.
[...]
> @@ -613,7 +615,9 @@ int mac802154_perform_association(struct ieee802154_sub_if_data *sdata,
>
> clear_assoc:
> clear_bit(IEEE802154_IS_ASSOCIATING, &local->ongoing);
> + spin_lock_bh(&local->assoc_dev_lock);
> local->assoc_dev = NULL;
> + spin_unlock_bh(&local->assoc_dev_lock);
Is _bh really useful here? Isn't the dereferencing always happening in
process context?
> @@ -626,6 +630,7 @@ int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata,
> u64 deaddr = swab64((__force u64)dest->extended_addr);
> struct ieee802154_local *local = sdata->local;
> struct wpan_dev *wpan_dev = &sdata->wpan_dev;
> + struct ieee802154_pan_device *assoc_dev;
The below block can be much simpler: just cache the extended addr of the
assoc device for the time of the check.
> struct ieee802154_assoc_resp_pl resp_pl = {};
>
> if (skb->len != sizeof(resp_pl))
> @@ -635,9 +640,15 @@ int mac802154_process_association_resp(struct ieee802154_sub_if_data *sdata,
> dest->mode != IEEE802154_EXTENDED_ADDRESSING))
> return -EINVAL;
>
> - if (unlikely(dest->extended_addr != wpan_dev->extended_addr ||
> - src->extended_addr != local->assoc_dev->extended_addr))
> + spin_lock_bh(&local->assoc_dev_lock);
> + assoc_dev = local->assoc_dev;
> + if (unlikely(!assoc_dev ||
> + dest->extended_addr != wpan_dev->extended_addr ||
> + src->extended_addr != assoc_dev->extended_addr)) {
> + spin_unlock_bh(&local->assoc_dev_lock);
> return -ENODEV;
> + }
> + spin_unlock_bh(&local->assoc_dev_lock);
Actually, even simpler than using a lock, since the only information we
use from assoc_dev is the extended address, why not just caching the
extended address value directly in the local structure?
Thanks,
Miquèl
prev parent reply other threads:[~2026-08-25 13:15 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-24 17:59 [PATCH net] mac802154: fix data race and NULL deref on local->assoc_dev Kaiwen Shi
2026-08-25 13:15 ` Miquel Raynal [this message]
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=87ik4ygx41.fsf@bootlin.com \
--to=miquel.raynal@bootlin.com \
--cc=alex.aring@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wpan@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=skwkevin@mail.ustc.edu.cn \
--cc=stefan@datenfreihafen.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.