From: Joas Antonio dos Santos <joasantonio108@gmail.com>
To: Alexander Aring <alex.aring@gmail.com>,
Stefan Schmidt <stefan@datenfreihafen.org>,
Miquel Raynal <miquel.raynal@bootlin.com>
Cc: David S. Miller <davem@davemloft.net>,
Eric Dumazet <edumazet@kernel.org>,
Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
Simon Horman <horms@kernel.org>,
syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com,
linux-wpan@vger.kernel.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [PATCH net] ieee802154: reject ARPHRD_IEEE802154 devices without ieee802154_ptr
Date: Fri, 30 Oct 2026 16:25:42 -0300 [thread overview]
Message-ID: <179338834213.72059.10411262981778676981@gmail.com> (raw)
TUNSETLINK lets a TUN device change its link type to ARPHRD_IEEE802154
without it becoming a WPAN device: dev->ieee802154_ptr and dev->ml_priv
stay NULL. The legacy 802.15.4 netlink code and the AF_IEEE802154
socket code only check dev->type before dereferencing them:
- ieee802154_llsec_dump_table() calls ieee802154_mlme_ops(dev)->llsec
(the syzbot report below);
- ieee802154_dump_iface() and ieee802154_nl_get_dev() users such as
IEEE802154_LIST_IFACE, which needs no privileges, go through
ieee802154_nl_fill_iface() and dev->ieee802154_ptr->wpan_phy;
- ieee802154_del_iface() reads dev->ieee802154_ptr->wpan_phy;
- ieee802154_get_dev(), used by bind() and sendmsg() on any
AF_IEEE802154 datagram socket, reads tmp->ieee802154_ptr->pan_id when
looking up a short address, and dgram_sendmsg() and
ieee802154_dgram_deliver() use dev->ieee802154_ptr of the device they
picked by type.
Once such a TUN device exists in init_net, an unprivileged user can
crash the kernel with an IEEE802154_LIST_IFACE dump or by binding an
AF_IEEE802154 datagram socket to a short address:
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
pc : ieee802154_nl_fill_iface.isra.0+0xf0/0x64c
KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f]
pc : ieee802154_get_dev+0x2b8/0x478
Reject devices without ieee802154_ptr wherever a device is picked by
its type, as was done for lowpan_newlink() in commit bf79662bc85e
("ieee802154: 6lowpan: fix NULL dereference in lowpan_newlink").
The bug was reported by syzbot; the other paths were found by
LLM-assisted review of the same pattern and confirmed with a test that
sets up the TUN device as root and then triggers them as uid 65534.
Fixes: 3e9c156e2c21 ("ieee802154: add netlink interfaces for llsec")
Reported-by: syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90
Cc: stable@vger.kernel.org
Signed-off-by: Joas Antonio dos Santos <joasantonio108@gmail.com>
Assisted-by: Yaga Agent HackerSec Claude:claude-opus-5-5
---
Tested on arm64 QEMU with KASAN (net/main 94cea342e891, mac802154_hwsim
loaded): a TUN device set to ARPHRD_IEEE802154 by root, then
- LLSEC_LIST_KEY dump as root: NULL deref in ieee802154_llsec_dump_table()
without the patch, normal dump with it;
- LIST_IFACE dump as uid 65534: NULL deref in ieee802154_nl_fill_iface()
without the patch, lists the hwsim interfaces with it;
- bind() of an AF_IEEE802154 datagram socket to a short address as uid
65534: NULL deref in ieee802154_get_dev() without the patch, -ENODEV
with it;
- sendto() on an unbound datagram socket keeps working (it picks a hwsim
interface).
net/ieee802154/nl-mac.c | 8 +++++---
net/ieee802154/nl-phy.c | 2 +-
net/ieee802154/socket.c | 18 ++++++++++++++++--
3 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/net/ieee802154/nl-mac.c b/net/ieee802154/nl-mac.c
index 74ef0a310..5bf6725eb 100644
--- a/net/ieee802154/nl-mac.c
+++ b/net/ieee802154/nl-mac.c
@@ -162,7 +162,7 @@ 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) {
dev_put(dev);
return NULL;
}
@@ -437,7 +437,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)
goto cont;
if (ieee802154_nl_fill_iface(skb, NETLINK_CB(cb->skb).portid,
@@ -771,7 +772,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)
goto skip;
data.ops = ieee802154_mlme_ops(dev);
diff --git a/net/ieee802154/nl-phy.c b/net/ieee802154/nl-phy.c
index 4c07a475c..39aaa9745 100644
--- a/net/ieee802154/nl-phy.c
+++ b/net/ieee802154/nl-phy.c
@@ -284,7 +284,7 @@ int ieee802154_del_iface(struct sk_buff *skb, struct genl_info *info)
dev = dev_get_by_name(genl_info_net(info), name);
if (!dev)
return rc;
- if (dev->type != ARPHRD_IEEE802154)
+ if (dev->type != ARPHRD_IEEE802154 || !dev->ieee802154_ptr)
goto out;
phy = dev->ieee802154_ptr->wpan_phy;
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index be8ca1f05..f87c9ccbc 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -53,7 +53,8 @@ ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
rtnl_lock();
for_each_netdev(net, tmp) {
- if (tmp->type != ARPHRD_IEEE802154)
+ if (tmp->type != ARPHRD_IEEE802154 ||
+ !tmp->ieee802154_ptr)
continue;
pan_id = tmp->ieee802154_ptr->pan_id;
@@ -74,6 +75,14 @@ ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
break;
}
+ /* A TUN device can have its type set to ARPHRD_IEEE802154 without
+ * being a WPAN device.
+ */
+ if (dev && !dev->ieee802154_ptr) {
+ dev_put(dev);
+ dev = NULL;
+ }
+
return dev;
}
@@ -641,6 +650,11 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
else
dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
+ if (dev && !dev->ieee802154_ptr) {
+ dev_put(dev);
+ dev = NULL;
+ }
+
if (!dev) {
pr_debug("no dev\n");
err = -ENXIO;
@@ -1097,7 +1111,7 @@ static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
ieee802154_raw_deliver(dev, skb);
- if (dev->type != ARPHRD_IEEE802154)
+ if (dev->type != ARPHRD_IEEE802154 || !dev->ieee802154_ptr)
goto drop;
if (skb->pkt_type != PACKET_OTHERHOST)
--
2.43.0
next reply other threads:[~2026-10-30 19:25 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 19:25 Joas Antonio dos Santos [this message]
2026-11-03 19:38 ` netdev-bot+sashiko
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=179338834213.72059.10411262981778676981@gmail.com \
--to=joasantonio108@gmail.com \
--cc=alex.aring@gmail.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wpan@vger.kernel.org \
--cc=miquel.raynal@bootlin.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stefan@datenfreihafen.org \
--cc=syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com \
/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
all inboxes | Powered by JetHome®