Re: [PATCH net v3] tun: disallow setting IEEE 802.15.4 and 6LoWPAN link types via TUNSETLINK
From: netdev-bot+sashiko
Date: Sun Nov 08 2026 - 11:50:00 EST
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