* [PATCH] ieee802154: nl-mac: validate device pointers before dereference
@ 2026-11-01 9:22 Kalpesh Solanki
2026-11-01 19:43 ` Andrew Lunn
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Kalpesh Solanki @ 2026-11-01 9:22 UTC (permalink / raw)
To: alex.aring, stefan, miquel.raynal, davem, edumazet, kuba, pabeni
Cc: horms, linux-wpan, netdev, linux-kernel,
syzbot+9ea34da5ca6100593c90, Kalpesh Solanki, stable
A virtual network device (such as a TUN interface) can have its link
type set to ARPHRD_IEEE802154 via ioctl(tun_fd, TUNSETLINK,
ARPHRD_IEEE802154). However, such devices do not have an IEEE 802.15.4
private context allocated (dev->ieee802154_ptr is NULL) and do not
register MAC operations (dev->ml_priv / ieee802154_mlme_ops(dev) is NULL).
When dumping security keys via IEEE802154_LLSEC_LIST_KEY,
ieee802154_llsec_dump_table() iterates through all net devices and
dereferences data.ops->llsec assuming that any ARPHRD_IEEE802154 device
has valid mlme ops. Because data.ops is NULL, this causes an immediate
null-pointer dereference / General Protection Fault:
Oops: general protection fault, probably for non-canonical address
KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
RIP: 0010:ieee802154_llsec_dump_table+0x204/0x5d0
Call Trace:
<TASK>
genl_dumpit+0x125/0x230 net/netlink/genetlink.c:1026
netlink_dump+0x53b/0xd00 net/netlink/af_netlink.c:2351
__netlink_dump_start+0x6d6/0x990 net/netlink/af_netlink.c:2466
Similarly, ieee802154_dump_iface() and ieee802154_nl_get_dev() assume
that ARPHRD_IEEE802154 devices have valid dev->ieee802154_ptr and
ieee802154_mlme_ops(dev) pointers.
Fix this by ensuring dev->ieee802154_ptr and ieee802154_mlme_ops(dev)
are non-NULL before proceeding in ieee802154_nl_get_dev(),
ieee802154_dump_iface(), and ieee802154_llsec_dump_table().
Fixes: 3e9c156e2c21 ("ieee802154: add netlink interfaces for llsec")
Cc: stable@vger.kernel.org
Reported-by: syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90
Tested-by: syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com
Signed-off-by: Kalpesh Solanki <skalpesh942@gmail.com>
---
net/ieee802154/nl-mac.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index 74ef0a310af..1acde5af4b5 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -162,7 +162,8 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
if (!dev)
return NULL;
- if (dev->type != ARPHRD_IEEE802154) {
+ if (dev->type != ARPHRD_IEEE802154 || !dev->ieee802154_ptr ||
+ !ieee802154_mlme_ops(dev)) {
dev_put(dev);
return NULL;
}
@@ -437,7 +438,8 @@ int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb)
idx = 0;
for_each_netdev(net, dev) {
- if (idx < s_idx || dev->type != ARPHRD_IEEE802154)
+ if (idx < s_idx || dev->type != ARPHRD_IEEE802154 ||
+ !dev->ieee802154_ptr || !ieee802154_mlme_ops(dev))
goto cont;
if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
@@ -771,7 +773,8 @@ ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb,
int rc;
for_each_netdev(net, dev) {
- if (idx < first_dev || dev->type != ARPHRD_IEEE802154)
+ if (idx < first_dev || dev->type != ARPHRD_IEEE802154 ||
+ !dev->ieee802154_ptr || !ieee802154_mlme_ops(dev))
goto skip;
data.ops = ieee802154_mlme_ops(dev);
--
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] ieee802154: nl-mac: validate device pointers before dereference
2026-11-01 9:22 [PATCH] ieee802154: nl-mac: validate device pointers before dereference Kalpesh Solanki
@ 2026-11-01 19:43 ` Andrew Lunn
2026-11-02 2:47 ` Kalpesh Solanki
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Andrew Lunn @ 2026-11-01 19:43 UTC (permalink / raw)
To: Kalpesh Solanki
Cc: alex.aring, stefan, miquel.raynal, davem, edumazet, kuba, pabeni,
horms, linux-wpan, netdev, linux-kernel,
syzbot+9ea34da5ca6100593c90, stable
On Sun, Nov 01, 2026 at 02:52:19PM +0530, Kalpesh Solanki wrote:
> A virtual network device (such as a TUN interface) can have its link
> type set to ARPHRD_IEEE802154 via ioctl(tun_fd, TUNSETLINK,
> ARPHRD_IEEE802154). However, such devices do not have an IEEE 802.15.4
> private context allocated (dev->ieee802154_ptr is NULL) and do not
> register MAC operations (dev->ml_priv / ieee802154_mlme_ops(dev) is NULL).
> Fix this by ensuring dev->ieee802154_ptr and ieee802154_mlme_ops(dev)
> are non-NULL before proceeding in ieee802154_nl_get_dev(),
> ieee802154_dump_iface(), and ieee802154_llsec_dump_table().
Did you consider the other fix? Is there a use case for setting a TUN
interface to ARPHRD_IEEE802154? If not, maybe return EOPNOTSUPP, or
EINVAL?
Andrew
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] ieee802154: nl-mac: validate device pointers before dereference
2026-11-01 9:22 [PATCH] ieee802154: nl-mac: validate device pointers before dereference Kalpesh Solanki
2026-11-01 19:43 ` Andrew Lunn
@ 2026-11-02 2:47 ` Kalpesh Solanki
2026-11-02 14:00 ` Andrew Lunn
2026-11-02 9:24 ` netdev-bot+sashiko
2026-11-06 14:24 ` [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK Kalpesh Solanki
3 siblings, 1 reply; 8+ messages in thread
From: Kalpesh Solanki @ 2026-11-02 2:47 UTC (permalink / raw)
To: andrew
Cc: alex.aring, stefan, miquel.raynal, davem, edumazet, kuba, pabeni,
horms, linux-wpan, netdev, linux-kernel,
syzbot+9ea34da5ca6100593c90, stable, Kalpesh Solanki
On Mon, Nov 02, 2026 at 01:13:xx +0100, Andrew Lunn wrote:
> Did you consider the other fix? Is there a use case for setting a TUN
> interface to ARPHRD_IEEE802154? If not, maybe return EOPNOTSUPP, or
> EINVAL?
>
> Andrew
Hi Andrew,
Thanks for reviewing and raising this point!
Regarding whether there is a use case for setting a TUN interface to
ARPHRD_IEEE802154:
In real hardware/subsystem usage, virtual 802.15.4 interfaces are typically
handled via mac802154_hwsim or fakelb (which properly allocate wpan_phy and
dev->ieee802154_ptr), rather than raw TUN. However, tun.c explicitly recognizes
ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR in tun_get_addr_len():
case ARPHRD_IEEE802154:
case ARPHRD_IEEE802154_MONITOR:
return IEEE802154_EXTENDED_ADDR_LEN;
which sets the hardware address length to IEEE802154_EXTENDED_ADDR_LEN on
TUNSETLINK for userspace network stacks/simulators (such as IoT testbeds or
custom TAP-based emulators) that expect 802.15.4 addressing.
Regarding fixing this in drivers/net/tun.c vs net/ieee802154/nl-mac.c:
We considered returning -EOPNOTSUPP / -EINVAL in TUNSETLINK, but chose to
guard nl-mac.c for the following reasons:
1. Subsystem robustness / Defense-in-depth:
ieee802154_llsec_dump_table(), ieee802154_dump_iface(), and
ieee802154_nl_get_dev() assumed that any netdevice in the namespace
with dev->type == ARPHRD_IEEE802154 has valid ieee802154_ptr and
mlme_ops. When that assumption fails, it triggers a NULL dereference
while holding genl_mutex, leaving the mutex permanently locked and
deadlocking generic netlink system-wide for unprivileged users.
Other parts of the ieee802154 subsystem already make this defensive check:
- net/ieee802154/6lowpan/core.c (lowpan_newlink):
if (wdev->type != ARPHRD_IEEE802154 || !wdev->ieee802154_ptr)
- net/ieee802154/socket.c:
if (dev->type == ARPHRD_IEEE802154 && dev->ieee802154_ptr && ...)
Guarding nl-mac.c ensures the IEEE 802.15.4 netlink handlers are safe
regardless of how an ARPHRD_IEEE802154 device was created or modified.
2. Userspace ABI compatibility:
TUNSETLINK has historically permitted arbitrary link types on down
interfaces, and explicitly supports ARPHRD_IEEE802154 address lengths.
Disallowing it in TUNSETLINK might break existing user tools or test
frameworks that use TAP/TUN with this link type.
That said, if the consensus is that TUNSETLINK should reject
ARPHRD_IEEE802154 (or arbitrary link types that lack driver backend support),
I would be more than happy to submit a follow-up patch for tun.c as well.
Do you think we should reject it in tun.c in addition to guarding nl-mac.c,
or do you prefer restricting TUNSETLINK instead?
Thanks,
Kalpesh
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] ieee802154: nl-mac: validate device pointers before dereference
2026-11-01 9:22 [PATCH] ieee802154: nl-mac: validate device pointers before dereference Kalpesh Solanki
2026-11-01 19:43 ` Andrew Lunn
2026-11-02 2:47 ` Kalpesh Solanki
@ 2026-11-02 9:24 ` netdev-bot+sashiko
2026-11-06 14:24 ` [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK Kalpesh Solanki
3 siblings, 0 replies; 8+ messages in thread
From: netdev-bot+sashiko @ 2026-11-02 9:24 UTC (permalink / raw)
To: skalpesh942
Cc: alex.aring, stefan, miquel.raynal, davem, edumazet, kuba, pabeni,
horms, linux-wpan, netdev, linux-kernel,
syzbot+9ea34da5ca6100593c90, stable
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 1 (2) · Medium: 0 (2) · 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] The fix is incomplete within the same legacy IEEE802154
genetlink family.
Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but several non-
netlink IEEE 802.15.4 paths also treat `dev->type ==…
- [High] This problem wasn't introduced by this patch, but
ieee802154_dump_iface() and ieee802154_llsec_dump_table() walk…
- [Medium] This problem wasn't introduced by this patch, but
ieee802154_llsec_dump_table() never saves its intra-table resume…
- [Medium] This problem wasn't introduced by this patch, but
llsec_iter_devkeys() (net/ieee802154/nl-mac.c:1185-1206) resets the…
--
ieee802154: nl-mac: validate device pointers before dereference
This patch adds checks for a NULL dev->ieee802154_ptr and a NULL
ieee802154_mlme_ops(dev) in ieee802154_nl_get_dev(),
ieee802154_dump_iface() and ieee802154_llsec_dump_table(). It is meant to
stop crashes on devices such as TUN interfaces whose link type was set to
ARPHRD_IEEE802154 with TUNSETLINK.
> diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
> index 74ef0a310afbb..1acde5af4b564 100644
> --- a/net/ieee802154/nl-mac.c
> +++ b/net/ieee802154/nl-mac.c
> @@ -162,7 +162,8 @@ static struct net_device *ieee802154_nl_get_dev(struct genl_info *info)
> if (!dev)
> return NULL;
>
> - if (dev->type != ARPHRD_IEEE802154) {
> + if (dev->type != ARPHRD_IEEE802154 || !dev->ieee802154_ptr ||
> + !ieee802154_mlme_ops(dev)) {
> dev_put(dev);
> return NULL;
> }
[Severity: High]
Can the IEEE802154_DEL_IFACE handler still hit the same crash?
ieee802154_del_iface() in net/ieee802154/nl-phy.c is registered in the
same nl802154_family. It does not go through ieee802154_nl_get_dev().
It looks the device up with dev_get_by_name() and only checks the link
type:
net/ieee802154/nl-phy.c:ieee802154_del_iface() {
...
dev = dev_get_by_name(genl_info_net(info), name);
if (!dev)
return rc;
if (dev->type != ARPHRD_IEEE802154)
goto out;
phy = dev->ieee802154_ptr->wpan_phy;
BUG_ON(!phy);
...
}
Take the TUN setup from the commit message (TUNSETLINK to
ARPHRD_IEEE802154 while the interface is down). An IEEE802154_DEL_IFACE
request with IEEE802154_ATTR_DEV_NAME set to the TUN name would pass the
type check and then dereference a NULL dev->ieee802154_ptr.
This op uses GENL_ADMIN_PERM, the same privilege needed for the
IEEE802154_LLSEC_LIST_KEY dump fixed here. Should ieee802154_del_iface()
get the same check?
[Severity: High]
This is a pre-existing issue, but several non-netlink 802.15.4 paths
also assume that dev->type == ARPHRD_IEEE802154 means
dev->ieee802154_ptr is valid. Would they crash with the same TUN device?
In net/ieee802154/socket.c, the short-address branch of
ieee802154_get_dev() does this. It is reachable from dgram_bind() and
dgram_sendmsg() on an unprivileged SOCK_DGRAM socket:
for_each_netdev(net, tmp) {
if (tmp->type != ARPHRD_IEEE802154)
continue;
pan_id = tmp->ieee802154_ptr->pan_id;
On an unbound socket, dgram_sendmsg() calls
dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154), which can return
the TUN device. That device is then passed to wpan_dev_hard_header():
struct wpan_dev *wpan_dev = dev->ieee802154_ptr;
return wpan_dev->ops->header_create(skb, dev, daddr, saddr, len);
On receive, a frame written into the TUN with ETH_P_IEEE802154 goes
through ieee802154_rcv() -> ieee802154_dgram_deliver(), which reads:
pan_id = dev->ieee802154_ptr->pan_id;
short_addr = dev->ieee802154_ptr->short_addr;
hw_addr = dev->ieee802154_ptr->extended_addr;
lowpan_rcv() in net/ieee802154/6lowpan/rx.c also checks only the type
before doing this:
ldev = wdev->ieee802154_ptr->lowpan_dev;
It has no init_net restriction. Once any 6LoWPAN interface on the host
is up, a TUN in another network namespace could reach it.
ieee802154_dev_ioctl() and 6lowpan/core.c already allow for a NULL
ieee802154_ptr. Should these other sites check for it too?
> @@ -437,7 +438,8 @@ int ieee802154_dump_iface(struct sk_buff *skb, struct netlink_callback *cb)
>
> idx = 0;
> for_each_netdev(net, dev) {
> - if (idx < s_idx || dev->type != ARPHRD_IEEE802154)
> + if (idx < s_idx || dev->type != ARPHRD_IEEE802154 ||
> + !dev->ieee802154_ptr || !ieee802154_mlme_ops(dev))
> goto cont;
>
> if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
[Severity: High]
This isn't a bug introduced by this patch, but what keeps dev alive
during this walk? ieee802154_dump_iface() and
ieee802154_llsec_dump_table() loop with plain for_each_netdev(). They
hold no RTNL and no rcu_read_lock(), and take no dev_hold() on the
current device.
genl_dumpit() only takes genl_lock around the dump, because
nl802154_family has no parallel_ops. That lock does not serialize
against netdev unregistration.
The caller can't hold RTNL here either, because
ieee802154_nl_fill_iface() takes and drops it itself:
rtnl_lock();
short_addr = dev->ieee802154_ptr->short_addr;
pan_id = dev->ieee802154_ptr->pan_id;
rtnl_unlock();
RCU would not cover the llsec path, because llsec->lock_table() takes a
mutex.
Suppose the wpan interface is unregistered at the same time (ip link
del, or ieee802154_unregister_hw()). Can free_netdev() finish while the
dump is still using dev or following dev->dev_list.next?
IEEE802154_LIST_IFACE does not require GENL_ADMIN_PERM. The new
dev->ieee802154_ptr and ml_priv reads added here are part of the same
unprotected walk.
> @@ -771,7 +773,8 @@ ieee802154_llsec_dump_table(struct sk_buff *skb, struct netlink_callback *cb,
> int rc;
>
> for_each_netdev(net, dev) {
> - if (idx < first_dev || dev->type != ARPHRD_IEEE802154)
> + if (idx < first_dev || dev->type != ARPHRD_IEEE802154 ||
> + !dev->ieee802154_ptr || !ieee802154_mlme_ops(dev))
> goto skip;
>
> data.ops = ieee802154_mlme_ops(dev);
[Severity: Medium]
This is a pre-existing issue, but does ieee802154_llsec_dump_table()
lose its place inside a table when the skb fills up?
Further down, the function loads its cursors from cb->args:
data.s_idx = cb->args[1];
data.s_idx2 = cb->args[2];
The step iterators, such as llsec_iter_keys(), only advance
data->s_idx. On -EMSGSIZE the loop breaks before idx++, and only the
interface index is saved:
cb->args[0] = idx;
Nothing in nl-mac.c writes cb->args[1] or cb->args[2]. The next
callback picks the same interface and starts its table again from
index 0.
If one interface's key, device, devkey or seclevel table doesn't fit in
a single dump skb, could IEEE802154_LLSEC_LIST_KEY and the other llsec
dumps repeat the same records forever? Smaller overflows would give
duplicate records.
[Severity: Medium]
This is also a pre-existing issue, but llsec_iter_devkeys() seems to
skip device keys. It is reached through
ieee802154_llsec_dump_devkeys() -> ieee802154_llsec_dump_table():
list_for_each_entry(dpos, &data->table->devices, list) {
if (idx++ < data->s_idx)
continue;
idx2 = 0;
list_for_each_entry(kpos, &dpos->keys, list) {
if (idx2++ < data->s_idx2)
continue;
...
data->s_idx2++;
}
data->s_idx++;
}
idx2 is reset for each device, but data->s_idx2 is not. Once the first
device has emitted k keys, would the first k keys of every later device
be skipped?
The iterator still returns 0, so those devkeys would be missing from
the IEEE802154_LLSEC_LIST_DEVKEY output even when the buffer has room.
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261101092219.1278751-1-skalpesh942%40gmail.com
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] ieee802154: nl-mac: validate device pointers before dereference
2026-11-02 2:47 ` Kalpesh Solanki
@ 2026-11-02 14:00 ` Andrew Lunn
0 siblings, 0 replies; 8+ messages in thread
From: Andrew Lunn @ 2026-11-02 14:00 UTC (permalink / raw)
To: Kalpesh Solanki
Cc: alex.aring, stefan, miquel.raynal, davem, edumazet, kuba, pabeni,
horms, linux-wpan, netdev, linux-kernel,
syzbot+9ea34da5ca6100593c90, stable
On Mon, Nov 02, 2026 at 08:17:21AM +0530, Kalpesh Solanki wrote:
> On Mon, Nov 02, 2026 at 01:13:xx +0100, Andrew Lunn wrote:
> > Did you consider the other fix? Is there a use case for setting a TUN
> > interface to ARPHRD_IEEE802154? If not, maybe return EOPNOTSUPP, or
> > EINVAL?
> >
> > Andrew
>
> Hi Andrew,
>
> Thanks for reviewing and raising this point!
>
> Regarding whether there is a use case for setting a TUN interface to
> ARPHRD_IEEE802154:
> In real hardware/subsystem usage, virtual 802.15.4 interfaces are typically
> handled via mac802154_hwsim or fakelb (which properly allocate wpan_phy and
> dev->ieee802154_ptr), rather than raw TUN. However, tun.c explicitly recognizes
> ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR in tun_get_addr_len():
>
> case ARPHRD_IEEE802154:
> case ARPHRD_IEEE802154_MONITOR:
> return IEEE802154_EXTENDED_ADDR_LEN;
I looked at the history. Those two were added along with a bunch of
other ARPHRD_ values. There is nothing i could see to indicate
IEEE802154 was a deliberate choice. So i think you need the IEEE802154
Maintainers to comment on if this is useful or not.
> 1. Subsystem robustness / Defense-in-depth:
> ieee802154_llsec_dump_table(), ieee802154_dump_iface(), and
> ieee802154_nl_get_dev() assumed that any netdevice in the namespace
> with dev->type == ARPHRD_IEEE802154 has valid ieee802154_ptr and
> mlme_ops. When that assumption fails, it triggers a NULL dereference
> while holding genl_mutex, leaving the mutex permanently locked and
> deadlocking generic netlink system-wide for unprivileged users.
Which is good. An Opps with a splat makes it clear there is a bug. If
anybody cares, it will get reported and fixed.
Subsystem robustness / Defense-in-depth generally results in bugs
being hidden, rather than exposed.
The fact ieee802154 has ieee802154_ptr and the code unconditionally
accesses it suggests it is actually needed. So the commit message in
your change needs to argue why TUN is special and does not need
it. The commit message is all about "Why?". Why did you decided to fix
it this way, rather than some other way.
Is the correct fix to actually set ieee802154_ptr to something?
> Other parts of the ieee802154 subsystem already make this defensive check:
> - net/ieee802154/6lowpan/core.c (lowpan_newlink):
> if (wdev->type != ARPHRD_IEEE802154 || !wdev->ieee802154_ptr)
> - net/ieee802154/socket.c:
> if (dev->type == ARPHRD_IEEE802154 && dev->ieee802154_ptr && ...)
>
> Guarding nl-mac.c ensures the IEEE 802.15.4 netlink handlers are safe
> regardless of how an ARPHRD_IEEE802154 device was created or modified.
Now look at the history of this. Does the commit message adding this
code suggest why these checks are there?
I also wondered if IEEE802154 is special? struct net_device has:
#if IS_ENABLED(CONFIG_VLAN_8021Q)
struct vlan_info __rcu *vlan_info;
#endif
#if IS_ENABLED(CONFIG_NET_DSA)
struct dsa_port *dsa_ptr;
#endif
#if IS_ENABLED(CONFIG_TIPC)
struct tipc_bearer __rcu *tipc_ptr;
#endif
#if IS_ENABLED(CONFIG_CFG80211)
struct wireless_dev *ieee80211_ptr;
#endif
#if IS_ENABLED(CONFIG_IEEE802154) || IS_ENABLED(CONFIG_6LOWPAN)
struct wpan_dev *ieee802154_ptr;
#endif
#if IS_ENABLED(CONFIG_MPLS_ROUTING)
struct mpls_dev __rcu *mpls_ptr;
#endif
#if IS_ENABLED(CONFIG_MCTP)
struct mctp_dev __rcu *mctp_ptr;
#endif
#if IS_ENABLED(CONFIG_INET_PSP)
struct psp_dev __rcu *psp_dev;
#endif
Did you look at all of these? Can any of them cause issues in the same
way as ieee802154_ptr?
Something you learn after a while. If you find a bug, look around and
see if the same bug exists close by, because it often does.
Andrew
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK
2026-11-01 9:22 [PATCH] ieee802154: nl-mac: validate device pointers before dereference Kalpesh Solanki
` (2 preceding siblings ...)
2026-11-02 9:24 ` netdev-bot+sashiko
@ 2026-11-06 14:24 ` Kalpesh Solanki
2026-11-06 16:53 ` Willem de Bruijn
3 siblings, 1 reply; 8+ messages in thread
From: Kalpesh Solanki @ 2026-11-06 14:24 UTC (permalink / raw)
To: willemdebruijn.kernel, jasowangio, alex.aring, stefan,
miquel.raynal, andrew+netdev, davem, edumazet, kuba, pabeni
Cc: linux-wpan, netdev, linux-kernel, syzbot+9ea34da5ca6100593c90,
Kalpesh Solanki
A userspace application can set the link type of a TUN/TAP interface
to ARPHRD_IEEE802154 or ARPHRD_IEEE802154_MONITOR via ioctl(fd,
TUNSETLINK, arg) because tun_get_addr_len() explicitly recognized
these types.
However, TUN devices cannot function as IEEE 802.15.4 radios (they
lack wpan_phy, channels, PAN IDs, and MLME operations), and tun
never initializes dev->ieee802154_ptr or dev->ml_priv.
The IEEE 802.15.4 subsystem operates on the invariant that any
net_device with dev->type == ARPHRD_IEEE802154 is a genuine WPAN device
with a valid dev->ieee802154_ptr context. When an unprivileged user
creates a TUN interface in a user+net namespace, changes its link type
to ARPHRD_IEEE802154, and issues a netlink dump request (such as
IEEE802154_LLSEC_LIST_KEY), ieee802154_llsec_dump_table()
unconditionally dereferences dev->ieee802154_ptr /
ieee802154_mlme_ops(dev), triggering a supervisor null-pointer
dereference / general protection fault. Similar dereferences occur
across net/ieee802154/nl-phy.c (ieee802154_del_iface) and
net/ieee802154/socket.c.
Rather than scattering NULL checks across every site in net/ieee802154/,
fix the issue at the source: validate that arg fits within unsigned short
(rejecting arg > USHRT_MAX to prevent upper-bit truncation), disallow
setting ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR via TUNSETLINK
by returning -EINVAL, and remove these unsupported types from
tun_get_addr_len() along with the unused <linux/ieee802154.h> include.
Fixes: cca8ea3b05c9 ("net: tun: set tun->dev->addr_len during TUNSETLINK processing")
Reported-by: syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90
Signed-off-by: Kalpesh Solanki <skalpesh942@gmail.com>
---
v1 -> v2:
- Instead of adding NULL checks in net/ieee802154/nl-mac.c, disallow setting
ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR link types via TUNSETLINK in
drivers/net/tun.c, as discussed with Andrew Lunn and identified in Sashiko
bot review. Virtual IEEE 802.15.4 interfaces are properly provided by
mac802154_hwsim and fakelb; TUN devices cannot function as genuine 802.15.4
radios and lack private 802.15.4 contexts.
- Add an explicit bounds check (arg > USHRT_MAX) to prevent integer truncation
bypasses when casting 64-bit ioctl arg to 16-bit dev->type.
- Remove ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR from tun_get_addr_len()
and drop unused <linux/ieee802154.h> header.
drivers/net/tun.c | 45 ++++++++++++++++++++++++++-------------------
1 file changed, 26 insertions(+), 19 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index dcec7311e60..f2915e929e3 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -70,7 +70,6 @@
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/mutex.h>
-#include <linux/ieee802154.h>
#include <uapi/linux/if_ltalk.h>
#include <uapi/linux/if_fddi.h>
#include <uapi/linux/if_hippi.h>
@@ -3183,9 +3182,6 @@ static unsigned char tun_get_addr_len(unsigned short type)
return 4;
case ARPHRD_ETHER:
return ETH_ALEN;
- case ARPHRD_IEEE802154:
- case ARPHRD_IEEE802154_MONITOR:
- return IEEE802154_EXTENDED_ADDR_LEN;
case ARPHRD_PHONET_PIPE:
case ARPHRD_PPP:
case ARPHRD_NONE:
@@ -3362,22 +3358,33 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
netif_info(tun, drv, tun->dev,
"Linktype set failed because interface is up\n");
ret = -EBUSY;
- } else {
- ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
- tun->dev);
- ret = notifier_to_errno(ret);
- if (ret) {
- netif_info(tun, drv, tun->dev,
- "Refused to change device type\n");
- break;
- }
- tun->dev->type = (int) arg;
- tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
- netif_info(tun, drv, tun->dev, "linktype set to %d\n",
- tun->dev->type);
- call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
- tun->dev);
+ break;
+ }
+
+ if (arg > USHRT_MAX) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (arg == ARPHRD_IEEE802154 || arg == ARPHRD_IEEE802154_MONITOR) {
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
+ tun->dev);
+ ret = notifier_to_errno(ret);
+ if (ret) {
+ netif_info(tun, drv, tun->dev,
+ "Refused to change device type\n");
+ break;
}
+ tun->dev->type = (unsigned short)arg;
+ tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
+ netif_info(tun, drv, tun->dev, "linktype set to %d\n",
+ tun->dev->type);
+ call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
+ tun->dev);
break;
case TUNSETDEBUG:
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK
2026-11-06 14:24 ` [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK Kalpesh Solanki
@ 2026-11-06 16:53 ` Willem de Bruijn
2026-11-06 20:21 ` Willem de Bruijn
0 siblings, 1 reply; 8+ messages in thread
From: Willem de Bruijn @ 2026-11-06 16:53 UTC (permalink / raw)
To: Kalpesh Solanki
Cc: willemdebruijn.kernel, jasowangio, alex.aring, stefan,
miquel.raynal, andrew+netdev, davem, edumazet, kuba, pabeni,
linux-wpan, netdev, linux-kernel, syzbot+9ea34da5ca6100593c90
On Fri, Nov 6, 2026 at 9:32 AM Kalpesh Solanki <skalpesh942@gmail.com> wrote:
>
> A userspace application can set the link type of a TUN/TAP interface
> to ARPHRD_IEEE802154 or ARPHRD_IEEE802154_MONITOR via ioctl(fd,
> TUNSETLINK, arg) because tun_get_addr_len() explicitly recognized
> these types.
>
> However, TUN devices cannot function as IEEE 802.15.4 radios (they
> lack wpan_phy, channels, PAN IDs, and MLME operations), and tun
> never initializes dev->ieee802154_ptr or dev->ml_priv.
>
> The IEEE 802.15.4 subsystem operates on the invariant that any
> net_device with dev->type == ARPHRD_IEEE802154 is a genuine WPAN device
> with a valid dev->ieee802154_ptr context. When an unprivileged user
> creates a TUN interface in a user+net namespace, changes its link type
> to ARPHRD_IEEE802154, and issues a netlink dump request (such as
> IEEE802154_LLSEC_LIST_KEY), ieee802154_llsec_dump_table()
> unconditionally dereferences dev->ieee802154_ptr /
> ieee802154_mlme_ops(dev), triggering a supervisor null-pointer
> dereference / general protection fault. Similar dereferences occur
> across net/ieee802154/nl-phy.c (ieee802154_del_iface) and
> net/ieee802154/socket.c.
>
> Rather than scattering NULL checks across every site in net/ieee802154/,
> fix the issue at the source: validate that arg fits within unsigned short
> (rejecting arg > USHRT_MAX to prevent upper-bit truncation), disallow
> setting ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR via TUNSETLINK
> by returning -EINVAL, and remove these unsupported types from
> tun_get_addr_len() along with the unused <linux/ieee802154.h> include.
I don't think we can do this.
TUNSETLINK is a weird quirk. It never intended to fully change the link
layer. IFF_TAP still only supports Ethernet (calls eth_type_trans).
It was added in commit ff4cc3ac93e1 ("[TUNTAP]: Allow setting the linktype
of the tap device from userspace"), seemingly exactly to be able to process
other protocols.
Kismet would write captured 802.11 frames into a tap. The device would be
labelled ARPHRD_IEEE80211* so that tcpdump or wireshark interface would
see the "right" link type for processing.
> Fixes: cca8ea3b05c9 ("net: tun: set tun->dev->addr_len during TUNSETLINK processing")
> Reported-by: syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90
> Signed-off-by: Kalpesh Solanki <skalpesh942@gmail.com>
> ---
> v1 -> v2:
> - Instead of adding NULL checks in net/ieee802154/nl-mac.c, disallow setting
> ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR link types via TUNSETLINK in
> drivers/net/tun.c, as discussed with Andrew Lunn and identified in Sashiko
> bot review. Virtual IEEE 802.15.4 interfaces are properly provided by
> mac802154_hwsim and fakelb; TUN devices cannot function as genuine 802.15.4
> radios and lack private 802.15.4 contexts.
> - Add an explicit bounds check (arg > USHRT_MAX) to prevent integer truncation
> bypasses when casting 64-bit ioctl arg to 16-bit dev->type.
> - Remove ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR from tun_get_addr_len()
> and drop unused <linux/ieee802154.h> header.
>
> drivers/net/tun.c | 45 ++++++++++++++++++++++++++-------------------
> 1 file changed, 26 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index dcec7311e60..f2915e929e3 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -70,7 +70,6 @@
> #include <linux/bpf.h>
> #include <linux/bpf_trace.h>
> #include <linux/mutex.h>
> -#include <linux/ieee802154.h>
> #include <uapi/linux/if_ltalk.h>
> #include <uapi/linux/if_fddi.h>
> #include <uapi/linux/if_hippi.h>
> @@ -3183,9 +3182,6 @@ static unsigned char tun_get_addr_len(unsigned short type)
> return 4;
> case ARPHRD_ETHER:
> return ETH_ALEN;
> - case ARPHRD_IEEE802154:
> - case ARPHRD_IEEE802154_MONITOR:
> - return IEEE802154_EXTENDED_ADDR_LEN;
> case ARPHRD_PHONET_PIPE:
> case ARPHRD_PPP:
> case ARPHRD_NONE:
> @@ -3362,22 +3358,33 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
> netif_info(tun, drv, tun->dev,
> "Linktype set failed because interface is up\n");
> ret = -EBUSY;
> - } else {
> - ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
> - tun->dev);
> - ret = notifier_to_errno(ret);
> - if (ret) {
> - netif_info(tun, drv, tun->dev,
> - "Refused to change device type\n");
> - break;
> - }
> - tun->dev->type = (int) arg;
> - tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
> - netif_info(tun, drv, tun->dev, "linktype set to %d\n",
> - tun->dev->type);
> - call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
> - tun->dev);
> + break;
> + }
> +
> + if (arg > USHRT_MAX) {
> + ret = -EINVAL;
> + break;
> + }
> +
> + if (arg == ARPHRD_IEEE802154 || arg == ARPHRD_IEEE802154_MONITOR) {
> + ret = -EINVAL;
> + break;
> + }
> +
> + ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
> + tun->dev);
> + ret = notifier_to_errno(ret);
> + if (ret) {
> + netif_info(tun, drv, tun->dev,
> + "Refused to change device type\n");
> + break;
> }
> + tun->dev->type = (unsigned short)arg;
> + tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
> + netif_info(tun, drv, tun->dev, "linktype set to %d\n",
> + tun->dev->type);
> + call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
> + tun->dev);
> break;
>
> case TUNSETDEBUG:
> --
> 2.53.0
>
>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK
2026-11-06 16:53 ` Willem de Bruijn
@ 2026-11-06 20:21 ` Willem de Bruijn
0 siblings, 0 replies; 8+ messages in thread
From: Willem de Bruijn @ 2026-11-06 20:21 UTC (permalink / raw)
To: Willem de Bruijn, Kalpesh Solanki
Cc: willemdebruijn.kernel, jasowangio, alex.aring, stefan,
miquel.raynal, andrew+netdev, davem, edumazet, kuba, pabeni,
linux-wpan, netdev, linux-kernel, syzbot+9ea34da5ca6100593c90
Willem de Bruijn wrote:
> On Fri, Nov 6, 2026 at 9:32 AM Kalpesh Solanki <skalpesh942@gmail.com> wrote:
> >
> > A userspace application can set the link type of a TUN/TAP interface
> > to ARPHRD_IEEE802154 or ARPHRD_IEEE802154_MONITOR via ioctl(fd,
> > TUNSETLINK, arg) because tun_get_addr_len() explicitly recognized
> > these types.
> >
> > However, TUN devices cannot function as IEEE 802.15.4 radios (they
> > lack wpan_phy, channels, PAN IDs, and MLME operations), and tun
> > never initializes dev->ieee802154_ptr or dev->ml_priv.
> >
> > The IEEE 802.15.4 subsystem operates on the invariant that any
> > net_device with dev->type == ARPHRD_IEEE802154 is a genuine WPAN device
> > with a valid dev->ieee802154_ptr context. When an unprivileged user
> > creates a TUN interface in a user+net namespace, changes its link type
> > to ARPHRD_IEEE802154, and issues a netlink dump request (such as
> > IEEE802154_LLSEC_LIST_KEY), ieee802154_llsec_dump_table()
> > unconditionally dereferences dev->ieee802154_ptr /
> > ieee802154_mlme_ops(dev), triggering a supervisor null-pointer
Apparently a similar issue affects ARPHRD_6LOWPAN.
> > dereference / general protection fault. Similar dereferences occur
> > across net/ieee802154/nl-phy.c (ieee802154_del_iface) and
> > net/ieee802154/socket.c.
> >
> > Rather than scattering NULL checks across every site in net/ieee802154/,
> > fix the issue at the source: validate that arg fits within unsigned short
> > (rejecting arg > USHRT_MAX to prevent upper-bit truncation), disallow
> > setting ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR via TUNSETLINK
> > by returning -EINVAL, and remove these unsupported types from
> > tun_get_addr_len() along with the unused <linux/ieee802154.h> include.
>
> I don't think we can do this.
One exception is if this has never worked. If this was a NULL ptr
exception from the start, then clearly no userspace can depend on it.
> TUNSETLINK is a weird quirk. It never intended to fully change the link
> layer. IFF_TAP still only supports Ethernet (calls eth_type_trans).
>
> It was added in commit ff4cc3ac93e1 ("[TUNTAP]: Allow setting the linktype
> of the tap device from userspace"), seemingly exactly to be able to process
> other protocols.
>
> Kismet would write captured 802.11 frames into a tap. The device would be
> labelled ARPHRD_IEEE80211* so that tcpdump or wireshark interface would
> see the "right" link type for processing.
>
> > Fixes: cca8ea3b05c9 ("net: tun: set tun->dev->addr_len during TUNSETLINK processing")
> > Reported-by: syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com
> > Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90
> > Signed-off-by: Kalpesh Solanki <skalpesh942@gmail.com>
> > ---
> > v1 -> v2:
> > - Instead of adding NULL checks in net/ieee802154/nl-mac.c, disallow setting
> > ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR link types via TUNSETLINK in
> > drivers/net/tun.c, as discussed with Andrew Lunn and identified in Sashiko
> > bot review. Virtual IEEE 802.15.4 interfaces are properly provided by
> > mac802154_hwsim and fakelb; TUN devices cannot function as genuine 802.15.4
> > radios and lack private 802.15.4 contexts.
> > - Add an explicit bounds check (arg > USHRT_MAX) to prevent integer truncation
> > bypasses when casting 64-bit ioctl arg to 16-bit dev->type.
> > - Remove ARPHRD_IEEE802154 and ARPHRD_IEEE802154_MONITOR from tun_get_addr_len()
> > and drop unused <linux/ieee802154.h> header.
> >
> > drivers/net/tun.c | 45 ++++++++++++++++++++++++++-------------------
> > 1 file changed, 26 insertions(+), 19 deletions(-)
> >
> > diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> > index dcec7311e60..f2915e929e3 100644
> > --- a/drivers/net/tun.c
> > +++ b/drivers/net/tun.c
> > @@ -70,7 +70,6 @@
> > #include <linux/bpf.h>
> > #include <linux/bpf_trace.h>
> > #include <linux/mutex.h>
> > -#include <linux/ieee802154.h>
> > #include <uapi/linux/if_ltalk.h>
> > #include <uapi/linux/if_fddi.h>
> > #include <uapi/linux/if_hippi.h>
> > @@ -3183,9 +3182,6 @@ static unsigned char tun_get_addr_len(unsigned short type)
> > return 4;
> > case ARPHRD_ETHER:
> > return ETH_ALEN;
> > - case ARPHRD_IEEE802154:
> > - case ARPHRD_IEEE802154_MONITOR:
> > - return IEEE802154_EXTENDED_ADDR_LEN;
> > case ARPHRD_PHONET_PIPE:
> > case ARPHRD_PPP:
> > case ARPHRD_NONE:
> > @@ -3362,22 +3358,33 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
> > netif_info(tun, drv, tun->dev,
> > "Linktype set failed because interface is up\n");
> > ret = -EBUSY;
> > - } else {
> > - ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
> > - tun->dev);
> > - ret = notifier_to_errno(ret);
> > - if (ret) {
> > - netif_info(tun, drv, tun->dev,
> > - "Refused to change device type\n");
> > - break;
> > - }
> > - tun->dev->type = (int) arg;
> > - tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
> > - netif_info(tun, drv, tun->dev, "linktype set to %d\n",
> > - tun->dev->type);
> > - call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
> > - tun->dev);
> > + break;
> > + }
> > +
> > + if (arg > USHRT_MAX) {
> > + ret = -EINVAL;
> > + break;
> > + }
> > +
> > + if (arg == ARPHRD_IEEE802154 || arg == ARPHRD_IEEE802154_MONITOR) {
> > + ret = -EINVAL;
> > + break;
> > + }
> > +
> > + ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
> > + tun->dev);
> > + ret = notifier_to_errno(ret);
> > + if (ret) {
> > + netif_info(tun, drv, tun->dev,
> > + "Refused to change device type\n");
> > + break;
> > }
> > + tun->dev->type = (unsigned short)arg;
> > + tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
> > + netif_info(tun, drv, tun->dev, "linktype set to %d\n",
> > + tun->dev->type);
> > + call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
> > + tun->dev);
If blocking this proves safe, prefer as little unrelated code churn as
possible.
> > break;
> >
> > case TUNSETDEBUG:
> > --
> > 2.53.0
> >
> >
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-11-06 20:21 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-01 9:22 [PATCH] ieee802154: nl-mac: validate device pointers before dereference Kalpesh Solanki
2026-11-01 19:43 ` Andrew Lunn
2026-11-02 2:47 ` Kalpesh Solanki
2026-11-02 14:00 ` Andrew Lunn
2026-11-02 9:24 ` netdev-bot+sashiko
2026-11-06 14:24 ` [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK Kalpesh Solanki
2026-11-06 16:53 ` Willem de Bruijn
2026-11-06 20:21 ` Willem de Bruijn
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®