Netdev List
 help / color / mirror / Atom feed
* [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
@ 2026-11-06 14:24 ` Kalpesh Solanki
  2026-11-06 16:53   ` Willem de Bruijn
  2026-11-10 14:41   ` netdev-bot+sashiko
  0 siblings, 2 replies; 6+ 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 related	[flat|nested] 6+ 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
  2026-11-10 14:41   ` netdev-bot+sashiko
  1 sibling, 1 reply; 6+ 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] 6+ 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; 6+ 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] 6+ messages in thread

* Re: [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK
@ 2026-11-07  6:27 Kalpesh Solanki
  2026-11-07 15:08 ` Willem de Bruijn
  0 siblings, 1 reply; 6+ messages in thread
From: Kalpesh Solanki @ 2026-11-07  6:27 UTC (permalink / raw)
  To: willemb
  Cc: Kalpesh Solanki, willemdebruijn.kernel, jasowang, alex.aring,
	stefan, miquel.raynal, andrew+netdev, davem, edumazet, kuba,
	pabeni, linux-wpan, netdev, linux-kernel,
	syzbot+9ea34da5ca6100593c90

On Sat, Nov 07, 2026 at 01:51, Willem de Bruijn wrote:
> 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.

Right, this has never worked.

TUN devices only have tun_netdev_ops and never allocate dev->ieee802154_ptr
or register with wpan_phy. Setting ARPHRD_IEEE802154 via TUNSETLINK was only
handled in tun_get_addr_len() to set addr_len, but any actual use (like
dumping interfaces, llsec keys, or opening an IEEE 802.15.4 socket) immediately
triggers a NULL pointer dereference. Real virtual wpan devices are created
with mac802154_hwsim. So blocking it won't break any working userspace setup.

> Apparently a similar issue affects ARPHRD_6LOWPAN.

Yes, good catch. Setting ARPHRD_6LOWPAN has the same issue: lowpan_dev(dev)
assumes netdev_priv(dev) is struct lowpan_dev, but on TUN it's struct
tun_struct. On events like NETDEV_DOWN, lowpan_device_event() writes to
lowpan_dev(dev)->ctx.table flags, which corrupts tun's private memory.

Should I block ARPHRD_6LOWPAN in the same patch, or would you prefer that
in a separate fix?

> If blocking this proves safe, prefer as little unrelated code churn as
> possible.

Understood. I'll drop the USHRT_MAX check and avoid touching tun_get_addr_len
or the include header in v3, keeping the patch strictly to checking the
rejected types in TUNSETLINK.

Thanks,
Kalpesh

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK
  2026-11-07  6:27 [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK Kalpesh Solanki
@ 2026-11-07 15:08 ` Willem de Bruijn
  0 siblings, 0 replies; 6+ messages in thread
From: Willem de Bruijn @ 2026-11-07 15:08 UTC (permalink / raw)
  To: Kalpesh Solanki, willemb
  Cc: Kalpesh Solanki, willemdebruijn.kernel, jasowang, alex.aring,
	stefan, miquel.raynal, andrew+netdev, davem, edumazet, kuba,
	pabeni, linux-wpan, netdev, linux-kernel,
	syzbot+9ea34da5ca6100593c90

Kalpesh Solanki wrote:
> On Sat, Nov 07, 2026 at 01:51, Willem de Bruijn wrote:
> > 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.
> 
> Right, this has never worked.

In that case, the fewer these weird exceptions, the better.
+1 on explicitly failing this, thanks.

> TUN devices only have tun_netdev_ops and never allocate dev->ieee802154_ptr
> or register with wpan_phy. Setting ARPHRD_IEEE802154 via TUNSETLINK was only
> handled in tun_get_addr_len() to set addr_len, but any actual use (like
> dumping interfaces, llsec keys, or opening an IEEE 802.15.4 socket) immediately
> triggers a NULL pointer dereference. Real virtual wpan devices are created
> with mac802154_hwsim. So blocking it won't break any working userspace setup.
> 
> > Apparently a similar issue affects ARPHRD_6LOWPAN.
> 
> Yes, good catch. Setting ARPHRD_6LOWPAN has the same issue: lowpan_dev(dev)
> assumes netdev_priv(dev) is struct lowpan_dev, but on TUN it's struct
> tun_struct. On events like NETDEV_DOWN, lowpan_device_event() writes to
> lowpan_dev(dev)->ctx.table flags, which corrupts tun's private memory.
> 
> Should I block ARPHRD_6LOWPAN in the same patch, or would you prefer that
> in a separate fix?

Depends on the complexity? If you could handle both, that would be
great. Sashiko would probably call out the same thing otherwise, too.
No preference on whether one patch or two from me.

> > If blocking this proves safe, prefer as little unrelated code churn as
> > possible.
> 
> Understood. I'll drop the USHRT_MAX check and avoid touching tun_get_addr_len
> or the include header in v3, keeping the patch strictly to checking the
> rejected types in TUNSETLINK.

Mostly, try to avoid changing the indentation of that otherwise untouched
basic block.

> Thanks,
> Kalpesh



^ permalink raw reply	[flat|nested] 6+ 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-10 14:41   ` netdev-bot+sashiko
  1 sibling, 0 replies; 6+ messages in thread
From: netdev-bot+sashiko @ 2026-11-10 14:41 UTC (permalink / raw)
  To: skalpesh942
  Cc: willemdebruijn.kernel, jasowangio, alex.aring, stefan,
	miquel.raynal, andrew+netdev, davem, edumazet, kuba, pabeni,
	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: 0 · Medium: 2 (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).

- [Medium] The commit message rejects NULL checks in net/ieee802154/ and
  says it fixes the problem "at the source".
- [Medium] The commit message misstates the root cause and points the
  Fixes tag at the wrong commit.

Pre-existing issues:
- [Medium] This problem wasn't introduced by this patch, but tun still
  lets users set ARPHRD_6LOWPAN through TUNSETLINK.
- [Medium] This problem wasn't introduced by this patch, but TUNSETLINK
  still accepts ARPHRD_MCTP (290), and an unprivileged user can use that…

--

tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK

The TUNSETLINK ioctl now rejects ARPHRD_IEEE802154 and
ARPHRD_IEEE802154_MONITOR. It also rejects any arg larger than USHRT_MAX.
The IEEE 802.15.4 cases and the <linux/ieee802154.h> include are removed
from tun_get_addr_len().

Closes: https://syzkaller.appspot.com/bug?extid=9ea34da5ca6100593c90

> 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.

[Severity: Medium]
Is this the right root cause? TUNSETLINK has assigned any arg to
dev->type since commit ff4cc3ac93e1 ("[TUN]: Allow setting the linktype
of the tap device.") from 2005:

    tun->dev->type = (int) arg;

tun_get_addr_len() came later, in cca8ea3b05c9, and only picks addr_len
after the type has already been set. Unknown types fall through to the
default case and get addr_len 0, but they are still accepted.

The dereference in ieee802154_llsec_dump_table() goes back to
3e9c156e2c21 (2014).

With that history, is this tag correct?

    Fixes: cca8ea3b05c9 ("net: tun: set tun->dev->addr_len during TUNSETLINK processing")

It looks like the bug predates cca8ea3b05c9. Removing the IEEE802154
cases from tun_get_addr_len() also seems to be cleanup made dead by the
new TUNSETLINK check, not part of the fix itself.

[ ... ]

> 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.

[ ... ]

> Rather than scattering NULL checks across every site in net/ieee802154/,
> fix the issue at the source: validate that arg fits within unsigned short

[Severity: Medium]
Is tun the only way to break this invariant? bond_enslave() in
drivers/net/bonding/bond_main.c rejects only CAN devices:

    if (slave_dev->type == ARPHRD_CAN) {
        BOND_NL_ERR(bond_dev, extack,
                    "CAN devices cannot be enslaved");
        return -EPERM;
    }

For the first non-Ethernet slave, bond_setup_by_slave() copies the type
onto the bond:

    bond_dev->type = slave_dev->type;

Nothing in drivers/net/bonding/ sets ml_priv or ieee802154_ptr.

Enslaving a wpan interface that is down (from mac802154, hwsim or
fakelb) would therefore give a bond of type ARPHRD_IEEE802154. On that
bond, ieee802154_llsec_dump_table() would still run:

    if (idx < first_dev || dev->type != ARPHRD_IEEE802154)
        goto skip;

    data.ops = ieee802154_mlme_ops(dev);
    if (!data.ops->llsec)

with dev->ml_priv == NULL. The nl-phy.c and socket.c sites look exposed
in the same way.

Unlike the tun case, this path needs CAP_NET_ADMIN and an existing WPAN
netdev.

Team already closed this gap in commit 9043be310c6a ("team: reject CAN,
IEEE 802.15.4 and 6LoWPAN devices in team_port_add"). That commit noted
that bonding only had the CAN fix (8ba68464e478):

    if (port_dev->type == ARPHRD_CAN ||
        port_dev->type == ARPHRD_IEEE802154 ||
        port_dev->type == ARPHRD_IEEE802154_MONITOR ||
        port_dev->type == ARPHRD_6LOWPAN) {

The commit message relies on this invariant as the reason for not adding
checks in net/ieee802154/. Would bonding need a similar rejection before
the fix at the source is complete?

> diff --git a/drivers/net/tun.c b/drivers/net/tun.c
> index dcec7311e6011..f2915e929e395 100644
> --- a/drivers/net/tun.c
> +++ b/drivers/net/tun.c

[ ... ]

> @@ -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;

[ ... ]

> +		if (arg > USHRT_MAX) {
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		if (arg == ARPHRD_IEEE802154 || arg == ARPHRD_IEEE802154_MONITOR) {
> +			ret = -EINVAL;
> +			break;
> +		}

[Severity: Medium]
This is a pre-existing issue and was not introduced by this patch, but
should ARPHRD_6LOWPAN be rejected here too? tun_get_addr_len() still has:

    case ARPHRD_6LOWPAN:
        return EUI64_ADDR_LEN;

lowpan_event() in net/6lowpan/core.c is a global netdevice notifier. It
checks only dev->type == ARPHRD_6LOWPAN and __in6_dev_get(dev), and then
treats netdev_priv(dev) as a struct lowpan_dev. The header comment on
lowpan_is_ll() says:

    /* caller need to be sure it's dev->type is ARPHRD_6LOWPAN */

For a tun device, netdev_priv() is a struct tun_struct, which starts
with:

    struct tun_file __rcu *tfiles[MAX_TAP_QUEUES];

On NETDEV_DOWN, lowpan_event() runs:

    for (i = 0; i < LOWPAN_IPHC_CTX_TABLE_SIZE; i++)
        clear_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE,
                  &lowpan_dev(dev)->ctx.table[i].flags);

These writes land inside tun->tfiles[].

On NETDEV_UP or NETDEV_CHANGE it reads lowpan_dev(dev)->lltype, which
overlays tfiles[0]. If that value equals LOWPAN_LLTYPE_IEEE802154,
addrconf_ifid_802154_6lowpan() dereferences
lowpan_802154_dev(dev)->wdev->ieee802154_ptr, which comes from tun
memory.

The inet6_dev created at NETDEV_REGISTER survives the type change, so
the notifier check passes.

With the current layouts, each clear_bit() targets bit 0 of an aligned
pointer. lltype can read as 1 only on some 64-bit big-endian layouts, so
the crash depends on the memory layout. The path is still reachable by
an unprivileged user with tun in a user+net namespace.

Team rejects ARPHRD_6LOWPAN for this reason. Commit 9043be310c6a notes
that "the 6LoWPAN netdev notifier writes through lowpan_dev(dev) on
NETDEV_DOWN".

[Severity: Medium]
This is also a pre-existing issue and was not introduced by this patch,
but TUNSETLINK still accepts ARPHRD_MCTP (290). Can this hit a WARN_ON
in the MCTP receive path?

An IFF_TUN device registers as ARPHRD_NONE, and mctp_known() in
net/mctp/device.c accepts that type:

    return dev->type == ARPHRD_MCTP ||
           dev->type == ARPHRD_LOOPBACK ||
           dev->type == ARPHRD_NONE;

So mctp_register() attaches an mctp_dev at NETDEV_REGISTER.
mctp_dev_notify() handles only NETDEV_REGISTER and NETDEV_UNREGISTER, so
the mctp_dev stays in place after a type change.

Suppose the user calls TUNSETLINK(ARPHRD_MCTP), brings the link up, and
writes a frame whose packet info header carries ETH_P_MCTP.
tun_get_user() sets skb->protocol = pi.proto, and the frame reaches
mctp_pkttype_receive():

    if (dev->type == ARPHRD_MCTP) {
        cb = mctp_cb(skb);
    } else {

The skb cb was zeroed at allocation and no MCTP driver ever filled it
in, so mctp_cb() hits:

    WARN_ON(cb->magic != 0x4d435450);

An unprivileged user can reach this with tun in a user+net namespace,
and on panic_on_warn systems it panics the machine. Should ARPHRD_MCTP be
rejected here as well?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261106142421.17793-1-skalpesh942%40gmail.com

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-11-10 14:41 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-07  6:27 [PATCH net v2] tun: disallow setting IEEE 802.15.4 link types via TUNSETLINK Kalpesh Solanki
2026-11-07 15:08 ` Willem de Bruijn
  -- strict thread matches above, loose matches on Subject: below --
2026-11-01  9:22 [PATCH] ieee802154: nl-mac: validate device pointers before dereference Kalpesh Solanki
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
2026-11-10 14:41   ` 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