* [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK
@ 2026-11-07 16:26 Kalpesh Solanki
2026-11-07 17:13 ` Willem de Bruijn
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Kalpesh Solanki @ 2026-11-07 16:26 UTC (permalink / raw)
To: willemdebruijn.kernel, jasowangio, alex.aring, stefan,
miquel.raynal, davem, edumazet, kuba, pabeni
Cc: andrew+netdev, 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, ARPHRD_IEEE802154_MONITOR, or ARPHRD_6LOWPAN
via ioctl(fd, TUNSETLINK, arg) because tun_get_addr_len() explicitly
recognized these types.
However, TUN devices cannot function as genuine IEEE 802.15.4 or 6LoWPAN
interfaces:
1. They lack wpan_phy, channels, PAN IDs, and MLME operations, and tun
never initializes dev->ieee802154_ptr or dev->ml_priv. 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.
2. Similarly, the 6LoWPAN subsystem assumes via lowpan_dev(dev) that
netdev_priv(dev) is struct lowpan_dev. On a TUN device, netdev_priv(dev)
is struct tun_struct. On netdev events (such as NETDEV_DOWN in
net/6lowpan/core.c:lowpan_device_event), it clears bits in
lowpan_dev(dev)->ctx.table flags, which corrupts private memory inside
tun_struct.
Rather than scattering checks across subsystems, fix the issue at the
source: disallow setting ARPHRD_IEEE802154, ARPHRD_IEEE802154_MONITOR, and
ARPHRD_6LOWPAN via TUNSETLINK by returning -EINVAL.
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>
---
v2 -> v3:
- Include ARPHRD_6LOWPAN alongside ARPHRD_IEEE802154 as agreed with Willem
de Bruijn, preventing Sashiko AI flags and addressing the underlying
lowpan_dev(dev) memory corruption.
- Minimize code churn as advised by Willem de Bruijn: drop unrelated
USHRT_MAX check and preserve tun_get_addr_len(), headers, and existing
block indentation.
- Fresh standalone thread as advised by Jakub Kicinski.
- Link to v1 and v2 discussion:
https://lore.kernel.org/all/20261101092219.1278751-1-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 | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index dcec7311e60..05eb28578b8 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -3362,6 +3362,10 @@ 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 if (arg == ARPHRD_IEEE802154 ||
+ arg == ARPHRD_IEEE802154_MONITOR ||
+ arg == ARPHRD_6LOWPAN) {
+ ret = -EINVAL;
} else {
ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
tun->dev);
--
2.53.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK
2026-11-07 16:26 [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK Kalpesh Solanki
@ 2026-11-07 17:13 ` Willem de Bruijn
2026-11-07 17:26 ` Kalpesh Solanki
2026-11-08 16:49 ` netdev-bot+sashiko
2 siblings, 0 replies; 4+ messages in thread
From: Willem de Bruijn @ 2026-11-07 17:13 UTC (permalink / raw)
To: Kalpesh Solanki, willemdebruijn.kernel, jasowangio, alex.aring,
stefan, miquel.raynal, davem, edumazet, kuba, pabeni
Cc: andrew+netdev, linux-wpan, netdev, linux-kernel,
syzbot+9ea34da5ca6100593c90, Kalpesh Solanki
Kalpesh Solanki wrote:
> A userspace application can set the link type of a TUN/TAP interface
> to ARPHRD_IEEE802154, ARPHRD_IEEE802154_MONITOR, or ARPHRD_6LOWPAN
> via ioctl(fd, TUNSETLINK, arg) because tun_get_addr_len() explicitly
> recognized these types.
>
> However, TUN devices cannot function as genuine IEEE 802.15.4 or 6LoWPAN
> interfaces:
>
> 1. They lack wpan_phy, channels, PAN IDs, and MLME operations, and tun
> never initializes dev->ieee802154_ptr or dev->ml_priv. 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.
>
> 2. Similarly, the 6LoWPAN subsystem assumes via lowpan_dev(dev) that
> netdev_priv(dev) is struct lowpan_dev. On a TUN device, netdev_priv(dev)
> is struct tun_struct. On netdev events (such as NETDEV_DOWN in
> net/6lowpan/core.c:lowpan_device_event), it clears bits in
> lowpan_dev(dev)->ctx.table flags, which corrupts private memory inside
> tun_struct.
>
> Rather than scattering checks across subsystems, fix the issue at the
> source: disallow setting ARPHRD_IEEE802154, ARPHRD_IEEE802154_MONITOR, and
> ARPHRD_6LOWPAN via TUNSETLINK by returning -EINVAL.
>
> Fixes: cca8ea3b05c9 ("net: tun: set tun->dev->addr_len during TUNSETLINK processing")
Should this be
Fixes: ff4cc3ac93e1 ("[TUNTAP]: Allow setting the linktype of the tap device from userspace")
> Reported-by: syzbot+9ea34da5ca6100593c90@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90
> Signed-off-by: Kalpesh Solanki <skalpesh942@gmail.com>
> ---
> v2 -> v3:
> - Include ARPHRD_6LOWPAN alongside ARPHRD_IEEE802154 as agreed with Willem
> de Bruijn, preventing Sashiko AI flags and addressing the underlying
> lowpan_dev(dev) memory corruption.
> - Minimize code churn as advised by Willem de Bruijn: drop unrelated
> USHRT_MAX check and preserve tun_get_addr_len(), headers, and existing
> block indentation.
> - Fresh standalone thread as advised by Jakub Kicinski.
> - Link to v1 and v2 discussion:
> https://lore.kernel.org/all/20261101092219.1278751-1-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 | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index dcec7311e60..05eb28578b8 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -3362,6 +3362,10 @@ 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 if (arg == ARPHRD_IEEE802154 ||
> + arg == ARPHRD_IEEE802154_MONITOR ||
> + arg == ARPHRD_6LOWPAN) {
> + ret = -EINVAL;
Thanks, a lot simpler.
But, arg is unsigned long while tun->dev->type is unsigned short.
An arg ARPHRD_IEEE802154 | 0x10000 could pass this check, get and get
assigned while truncated.
Cast to unsigned short in these comparisons?
> } else {
> ret = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
> tun->dev);
> --
> 2.53.0
>
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK
2026-11-07 16:26 [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK Kalpesh Solanki
2026-11-07 17:13 ` Willem de Bruijn
@ 2026-11-07 17:26 ` Kalpesh Solanki
2026-11-08 16:49 ` netdev-bot+sashiko
2 siblings, 0 replies; 4+ messages in thread
From: Kalpesh Solanki @ 2026-11-07 17:26 UTC (permalink / raw)
To: willemb
Cc: Kalpesh Solanki, willemdebruijn.kernel, jasowangio, alex.aring,
stefan, miquel.raynal, davem, edumazet, kuba, pabeni,
andrew+netdev, linux-wpan, netdev, linux-kernel,
syzbot+9ea34da5ca6100593c90
> Should this be
>
> Fixes: ff4cc3ac93e1 ("[TUNTAP]: Allow setting the linktype of the tap device from userspace")
Yes, will update the Fixes tag.
> Cast to unsigned short in these comparisons?
Yes, makes sense. Will cast to unsigned short in v4.
Thanks,
Kalpesh
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK
2026-11-07 16:26 [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK Kalpesh Solanki
2026-11-07 17:13 ` Willem de Bruijn
2026-11-07 17:26 ` Kalpesh Solanki
@ 2026-11-08 16:49 ` netdev-bot+sashiko
2 siblings, 0 replies; 4+ messages in thread
From: netdev-bot+sashiko @ 2026-11-08 16:49 UTC (permalink / raw)
To: skalpesh942
Cc: willemdebruijn.kernel, jasowangio, alex.aring, stefan,
miquel.raynal, davem, edumazet, kuba, pabeni, andrew+netdev,
linux-wpan, netdev, linux-kernel, syzbot+9ea34da5ca6100593c90
Thank you for your contribution! Sashiko AI review found 2 potential
issue(s) to consider.
Critical: 0 · High: 1 · Medium: 0 · Low: 1
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 new TUNSETLINK denylist in __tun_chr_ioctl()
(drivers/net/tun.c:3365-3368) can be bypassed by setting high bits in…
- [Low] The commit message gets the root cause wrong.
--
tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK
This patch makes TUNSETLINK return -EINVAL when the requested link type is
ARPHRD_IEEE802154, ARPHRD_IEEE802154_MONITOR or ARPHRD_6LOWPAN. The goal is
to keep code that expects 802.15.4 or 6LoWPAN private data from treating
TUN devices as those device types.
Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90
> A userspace application can set the link type of a TUN/TAP interface
> to ARPHRD_IEEE802154, ARPHRD_IEEE802154_MONITOR, or ARPHRD_6LOWPAN
> via ioctl(fd, TUNSETLINK, arg) because tun_get_addr_len() explicitly
> recognized these types.
[Severity: Low]
Is this the actual root cause?
tun_get_addr_len() only maps a type to an address length. Its default case
returns 0 for any type it doesn't list, so it never accepts or rejects a
type.
The TUNSETLINK branch in __tun_chr_ioctl() stores whatever value userspace
passes:
tun->dev->type = (int) arg;
That means these types could be set the same way before cca8ea3b05c9.
Would it be more accurate to say that TUNSETLINK accepts arbitrary type
values?
> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index dcec7311e6011..05eb28578b8b0 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c
> @@ -3362,6 +3362,10 @@ 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 if (arg == ARPHRD_IEEE802154 ||
> + arg == ARPHRD_IEEE802154_MONITOR ||
> + arg == ARPHRD_6LOWPAN) {
> + ret = -EINVAL;
[Severity: High]
Can this check be bypassed by setting bits above the low 16 bits of arg?
Here arg is an unsigned long. On the compat path it is a 32-bit value,
because tun_chr_compat_ioctl() only does arg = (compat_ulong_t)arg. But
net_device::type is an unsigned short:
include/linux/netdevice.h:
unsigned short type;
Later in the same branch, __tun_chr_ioctl() stores the value like this:
tun->dev->type = (int) arg;
tun->dev->addr_len = tun_get_addr_len(tun->dev->type);
With arg = 0x10324, the comparison against ARPHRD_IEEE802154 (0x324) is
false, so the else branch runs. dev->type then ends up as 0x324, which is
ARPHRD_IEEE802154, and tun_get_addr_len() returns the 802.15.4 extended
address length.
0x10325 and 0x10339 work the same way for ARPHRD_IEEE802154_MONITOR and
ARPHRD_6LOWPAN. This also works from 32-bit userspace through the compat
path.
The code named in the commit message only checks the 16-bit dev->type.
Here is ieee802154_llsec_dump_table():
if (idx < first_dev || dev->type != ARPHRD_IEEE802154)
goto skip;
data.ops = ieee802154_mlme_ops(dev);
And here is lowpan_event() handling NETDEV_DOWN:
if (dev->type != ARPHRD_6LOWPAN)
return NOTIFY_DONE;
...
clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
&lowpan_dev(dev)->ctx.table[i].flags);
So it looks like an unprivileged user in a user+net namespace can still
trigger both the syzbot NULL dereference and the write into tun_struct
through lowpan_dev().
v2 had an arg > USHRT_MAX check that covered this case, and v3 dropped it
as unrelated. Should the comparison use (u16)arg, or should values above
USHRT_MAX be rejected?
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261107162649.282982-1-skalpesh942%40gmail.com
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-08 16:49 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-07 16:26 [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK Kalpesh Solanki
2026-11-07 17:13 ` Willem de Bruijn
2026-11-07 17:26 ` Kalpesh Solanki
2026-11-08 16:49 ` 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®