From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=pass header.oldest-pass=0 smtp.remote-ip=85.215.255.51 ARC-Seal: i=2; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=pass; t=1792669351; b=uvmgOumeGl/2Wri1V7QKbiGz4lCVROhOnGcQ1+QoksR5OtYF2Y3FzlPnvnfgw4BhlE4+ MQraIEZaqUvEcLf057mjBG8f3TuMZGThauG3FaHU/yY+9ZQVEAtsAzpvxDVGyahbNSz9j b4MulIF9LPrzDndXQiyeLGgBQLBu3GqPvEaNGDwQ8sSlDLbsDjuHZcUmCpZnRXQKd4uJ6 WB+hjjTMu7xNWCwLzPk0+HbGKjcSO3eJ2FTaidg/aH2bGUSfYhAqTOD7ikI6j9sZHvskO tNRVhDDWzdt3NJRoI8fuEZogdGAbMmv6eFE3efdjZkEgAKvki7OYz1HtzcE+JvTuF8Q== ARC-Message-Signature: i=2; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1792669351; h=DMARC-Filter:X-RZG-CLASS-ID:DKIM-Signature:DKIM-Signature:X-RZG-AUTH: Received:From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To: References:MIME-Version:Content-Transfer-Encoding:Content-Type; bh=GoklJZBDhk1WUIjxmbOB6jIuhZElYRWCVUEyXeOwZGo=; b=E5+Qs3r40M7XaszInUS1BiXevtjoRu3tEQtdnFDn7Hz3VeC1+PiGpyg0z8zJQpCdEie6 Wh3iATh5YA926uzxuPiFOjlCb9Xk62YeGmjp2Wfaa6wGoSJh5W12kA4iHdCVN4LFtmIJe ZA79SseI95dKfYIk5QzeEAfSy7lDqf267Ctbu2oWIlPTt4WtDU0cUszejzliz1Urrtfx9 azEZnrrmDdodnKnC4wYG6D2FiBguVAIlvJAQpuSiKt489x85IfK98L9gvVNi5e4KUUMyu VqbzjLSXK+moSc6arinPSP3RC8W9cxnsIo3ORYeiNRKpsa70757C1aW4brPULFwzQqg== ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass header.from=hartkopp.net; spf=fail smtp.mailfrom=hartkopp.net; dkim=pass header.d=hartkopp.net header.i=@hartkopp.net header.a=rsa-sha256 header.s=strato-dkim-0002 header.b=RkOKsiQu; dkim=pass header.d=hartkopp.net header.i=@hartkopp.net header.a=ed25519-sha256 header.s=strato-dkim-0003 header.b=BCYljUK+; arc=pass header.oldest-pass=0 smtp.remote-ip=85.215.255.51 Received: from mo4-p01-ob.smtp.rzone.de (mo4-p01-ob.smtp.rzone.de [85.215.255.51]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AA6C8606A31E for ; Thu, 22 Oct 2026 11:42:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org AA6C8606A31E Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=hartkopp.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=hartkopp.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=hartkopp.net header.i=@hartkopp.net header.a=rsa-sha256 header.s=strato-dkim-0002 header.b=RkOKsiQu; dkim=pass header.d=hartkopp.net header.i=@hartkopp.net header.a=ed25519-sha256 header.s=strato-dkim-0003 header.b=BCYljUK+ ARC-Seal: i=1; a=rsa-sha256; t=1792669338; cv=none; d=strato.com; s=strato-dkim-0002; b=C87DbOK1J12E8aL3Rb43mM4mkSVrON9VwqBOgcxaMSKndvqHf9aU70q0cqCvgWDfW5 RzTbzgiYdrH8RDEUHd/Nl9sH2naEpVIA4XHEK2ZrAI4epf+nB1aHSpxDaEr0PCgzqdBD fV0p5uoNoCZ1AuNFcGeyY0YcH9YBuDbWXuEhrbVV9AJlsT1AYbY40slnZmqDtSaTRPGj n6iTbMR0QZO8AL//kfj3VOHpuAvrAy21159R8uignALPKD1POW/5G3SFvA79Palx024q vI5xFxOvfXN/Rf6HO6mLhB1TtbJTab0teK7xnGHIZ+koE9NwM8Y36X+iEcBWE916fqLp mzWg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; t=1792669338; s=strato-dkim-0002; d=strato.com; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=GoklJZBDhk1WUIjxmbOB6jIuhZElYRWCVUEyXeOwZGo=; b=APySm2T5Vr94Qys8swYjRMvcbH+IhKUwHK0PHN/VT81b1UJbRdKK+Li7ilTi7RRyGl NVCTIynFSyqwBcxjmtq3vaI5j5PjJZldzweC8r2hfEvNwFC2zGaLZ9Jjc2OAhsFe0Ytx 545AkJ5MS80yS3J8mdmFHi8ORYUsBjWRTaBRd1jY0Sd7xITmnWW1pzA+7AYXD6qQk5Dr KXaYR0J/zbGdAs6YTij9Ozk0mTdA+bKMYiZEAtkT0b42DLirIW4FzSm7eMqLg1+O4Rog vTX6wUnn9OTRqQmVsDk2zUdH/vu6wgS2JcziSD2AELo8gaD9I4VBCGMpe/z7Vm/GIzoI ZHzA== ARC-Authentication-Results: i=1; strato.com; arc=none; dkim=none X-RZG-CLASS-ID: mo01 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; t=1792669338; s=strato-dkim-0002; d=hartkopp.net; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=GoklJZBDhk1WUIjxmbOB6jIuhZElYRWCVUEyXeOwZGo=; b=RkOKsiQux+CYXDpHxRaDpuy7gSo8qPoxL7mM/aDgz4ilVxu/mNQiR4SV8a/OwJ5XXv WeGwaWW69bVtMitSXd9XyjgEe8CT8zItlCChdGfVOKHH3QjkkPH0wfFemxla0qLoua6F nJEh1RfS81ChcIl461tyhKwHnxairsMlgv6VTSDqSSV+VeoVcLdIU2vjLhB8uuxvRBdL UeFR+br5YStctkcHdBO3eYBwOl64/2cJBPCMEZ0pFHFyVQmaOQMQb1/H7ggBEvYxkC++ QG+aKYgH2HVUVe+rFN9Yw7X669SSAj9sQDvNid4zhLMOTLPwyRmYE80bW2+zpAeM30A0 AXpw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; t=1792669338; s=strato-dkim-0003; d=hartkopp.net; h=References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Cc:Date: From:Subject:Sender; bh=GoklJZBDhk1WUIjxmbOB6jIuhZElYRWCVUEyXeOwZGo=; b=BCYljUK+5f1Sw9EVODxdG3OY1e9PyJL5oXSxTxwDrn6NY8prH2h8icS4ap9Tq5TP8S kJiyQ4N+J+Kw4M/+WkBA== X-RZG-AUTH: ":P2MHfkW8eP4Mre39l357AZT/I7AY/7nT2yrDxb8mjH4JKvMdQv2tTUsMrZpkO3Mw3lZ/t54cFxeEQ7s8bDup0Q==" Received: from vivo.lan by smtp.strato.de (RZmta 55.6.3 AUTH) with ESMTPSA id Kfdf2a29MBgIo54 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256 bits)) (Client did not present a certificate); Thu, 22 Oct 2026 13:42:18 +0200 (CEST) From: Oliver Hartkopp To: linux-can@vger.kernel.org Cc: Oliver Hartkopp , stable@kernel.org, Oleksij Rempel , Marc Kleine-Budde Subject: [PATCH can-next v7 4/5] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Date: Thu, 22 Oct 2026 13:42:00 +0200 Message-ID: <20261022114202.180023-5-socketcan@hartkopp.net> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20261022114202.180023-1-socketcan@hartkopp.net> References: <20261022114202.180023-1-socketcan@hartkopp.net> X-Mailing-List: linux-can@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="us-ascii" Commit 4e096a18867a ("net: introduce CAN specific pointer in the struct net_device") introduced an explicit way to assign the midlayer private pointer (dev->ml_priv) to named users like ML_PRIV_CAN. A valid pointer returned by can_get_ml_priv() therefore identifies a real CAN device. The referenced commit only converted the j1939 and proc code to this check, while the other parts of the CAN subsystem still rely on dev->type == ARPHRD_CAN. The TUNSETLINK ioctl allows a down TUN/TAP device to set its hardware type to ARPHRD_CAN while dev->ml_priv remains NULL. Such a repurposed netdevice passes the ARPHRD_CAN checks. Commit 8aa59e355949 ("can: af_can: fix NULL pointer dereference in can_rx_register()") already made can_rx_register() reject such devices. But can_rx_unregister() still only checks dev->type and dereferences the NULL ml_priv when it walks the receive lists of the device. CAN_ISOTP reaches this path: isotp_bind() ignores the return values of can_rx_register() and binds the socket anyway. When the socket is released or the device is unregistered, isotp_release() and isotp_notify() remove the filters that have never been registered and trigger the NULL pointer dereference in can_rx_unregister(). This only requires owning a TUN/TAP device or CAP_NET_ADMIN in an unprivileged user namespace. Convert the remaining ARPHRD_CAN checks in af_can, bcm, gw, isotp and raw to can_get_ml_priv(). Fixes: 4e096a18867a ("net: introduce CAN specific pointer in the struct net_device") Cc: stable@kernel.org Cc: Oleksij Rempel Signed-off-by: Oliver Hartkopp Link: https://patch.msgid.link/20261012164802.94113-1-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde --- net/can/af_can.c | 15 ++++++--------- net/can/bcm.c | 7 ++++--- net/can/gw.c | 7 ++++--- net/can/isotp.c | 5 +++-- net/can/raw.c | 4 ++-- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/net/can/af_can.c b/net/can/af_can.c index 6ebe9d3689ac..d97f85fc3232 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -224,11 +224,11 @@ int can_send(struct sk_buff *skb, int loop) if (unlikely(skb->len > READ_ONCE(skb->dev->mtu))) { err = -EMSGSIZE; goto inval_skb; } - if (unlikely(skb->dev->type != ARPHRD_CAN)) { + if (unlikely(!can_get_ml_priv(skb->dev))) { err = -EPERM; goto inval_skb; } if (unlikely(!(skb->dev->flags & IFF_UP))) { @@ -450,11 +450,11 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id, struct can_dev_rcv_lists *dev_rcv_lists; struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats; /* insert new receiver (dev,canid,mask) -> (func,data) */ - if (dev && (dev->type != ARPHRD_CAN || !can_get_ml_priv(dev))) + if (dev && !can_get_ml_priv(dev)) return -ENODEV; if (dev && !net_eq(net, dev_net(dev))) return -ENODEV; @@ -517,11 +517,11 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, struct receiver *rcv = NULL; struct hlist_head *rcv_list; struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats; struct can_dev_rcv_lists *dev_rcv_lists; - if (dev && dev->type != ARPHRD_CAN) + if (dev && !can_get_ml_priv(dev)) return; if (dev && !net_eq(net, dev_net(dev))) return; @@ -682,12 +682,11 @@ static void can_receive(struct sk_buff *skb, struct net_device *dev) static int can_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct can_skb_ext *csx = can_skb_ext_find(skb); - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || - !csx || !can_is_can_skb(skb))) { + if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_can_skb(skb))) { pr_warn_once("PF_CAN: dropped non conform CAN skbuff: dev type %d, len %d\n", dev->type, skb->len); kfree_skb_reason(skb, SKB_DROP_REASON_CAN_RX_INVALID_FRAME); return NET_RX_DROP; @@ -708,12 +707,11 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct can_skb_ext *csx = can_skb_ext_find(skb); - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || - !csx || !can_is_canfd_skb(skb))) { + if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canfd_skb(skb))) { pr_warn_once("PF_CAN: dropped non conform CAN FD skbuff: dev type %d, len %d\n", dev->type, skb->len); kfree_skb_reason(skb, SKB_DROP_REASON_CANFD_RX_INVALID_FRAME); return NET_RX_DROP; @@ -734,12 +732,11 @@ static int canfd_rcv(struct sk_buff *skb, struct net_device *dev, static int canxl_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { struct can_skb_ext *csx = can_skb_ext_find(skb); - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || - !csx || !can_is_canxl_skb(skb))) { + if (unlikely(!can_get_ml_priv(dev) || !csx || !can_is_canxl_skb(skb))) { pr_warn_once("PF_CAN: dropped non conform CAN XL skbuff: dev type %d, len %d\n", dev->type, skb->len); kfree_skb_reason(skb, SKB_DROP_REASON_CANXL_RX_INVALID_FRAME); return NET_RX_DROP; diff --git a/net/can/bcm.c b/net/can/bcm.c index 6c85a76477c3..6759662e024c 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -52,10 +52,11 @@ #include #include #include #include #include +#include #include #include #include #include #include @@ -1716,11 +1717,11 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) if (!dev) { ret = -ENODEV; goto out_release; } - if (dev->type != ARPHRD_CAN) { + if (!can_get_ml_priv(dev)) { dev_put(dev); ret = -ENODEV; goto out_release; } @@ -1864,11 +1865,11 @@ static void bcm_notify(struct bcm_sock *bo, unsigned long msg, static int bcm_notifier(struct notifier_block *nb, unsigned long msg, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - if (dev->type != ARPHRD_CAN) + if (!can_get_ml_priv(dev)) return NOTIFY_DONE; if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN) return NOTIFY_DONE; if (unlikely(bcm_busy_notifier)) /* Check for reentrant bug. */ return NOTIFY_DONE; @@ -2021,11 +2022,11 @@ static int bcm_connect(struct socket *sock, struct sockaddr_unsized *uaddr, int dev = dev_get_by_index(net, addr->can_ifindex); if (!dev) { ret = -ENODEV; goto fail; } - if (dev->type != ARPHRD_CAN) { + if (!can_get_ml_priv(dev)) { dev_put(dev); ret = -ENODEV; goto fail; } diff --git a/net/can/gw.c b/net/can/gw.c index 36f9aa0f7026..8a5327d8a00e 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -50,10 +50,11 @@ #include #include #include #include #include +#include #include #include #include #include #include @@ -610,11 +611,11 @@ static int cgw_notifier(struct notifier_block *nb, unsigned long msg, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct net *net = dev_net(dev); - if (dev->type != ARPHRD_CAN) + if (!can_get_ml_priv(dev)) return NOTIFY_DONE; if (msg == NETDEV_UNREGISTER) { struct cgw_job *gwj = NULL; struct hlist_node *nx; @@ -1161,19 +1162,19 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, gwj->src.dev = __dev_get_by_index(net, gwj->ccgw.src_idx); if (!gwj->src.dev) goto out; - if (gwj->src.dev->type != ARPHRD_CAN) + if (!can_get_ml_priv(gwj->src.dev)) goto out; gwj->dst.dev = __dev_get_by_index(net, gwj->ccgw.dst_idx); if (!gwj->dst.dev) goto out; - if (gwj->dst.dev->type != ARPHRD_CAN) + if (!can_get_ml_priv(gwj->dst.dev)) goto out; /* is sending the skb back to the incoming interface intended? */ if (gwj->src.dev == gwj->dst.dev && !(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK)) { diff --git a/net/can/isotp.c b/net/can/isotp.c index b239f4b45518..1a272ce6a2bd 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -63,10 +63,11 @@ #include #include #include #include #include +#include #include #include #include #include #include @@ -1608,11 +1609,11 @@ static int isotp_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int l dev = dev_get_by_index(net, addr->can_ifindex); if (!dev) { err = -ENODEV; goto out; } - if (dev->type != ARPHRD_CAN) { + if (!can_get_ml_priv(dev)) { err = -ENODEV; goto out_put_dev; } if (READ_ONCE(dev->mtu) < so->ll.mtu) { err = -EINVAL; @@ -1895,11 +1896,11 @@ static void isotp_notify(struct isotp_sock *so, unsigned long msg, static int isotp_notifier(struct notifier_block *nb, unsigned long msg, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - if (dev->type != ARPHRD_CAN) + if (!can_get_ml_priv(dev)) return NOTIFY_DONE; if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN) return NOTIFY_DONE; if (unlikely(isotp_busy_notifier)) /* Check for reentrant bug. */ return NOTIFY_DONE; diff --git a/net/can/raw.c b/net/can/raw.c index 3e57f72a3afe..dfea48768b23 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -346,11 +346,11 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg, static int raw_notifier(struct notifier_block *nb, unsigned long msg, void *ptr) { struct net_device *dev = netdev_notifier_info_to_dev(ptr); - if (dev->type != ARPHRD_CAN) + if (!can_get_ml_priv(dev)) return NOTIFY_DONE; if (msg != NETDEV_UNREGISTER && msg != NETDEV_DOWN) return NOTIFY_DONE; if (unlikely(raw_busy_notifier)) /* Check for reentrant bug. */ return NOTIFY_DONE; @@ -489,11 +489,11 @@ static int raw_bind(struct socket *sock, struct sockaddr_unsized *uaddr, int len dev = dev_get_by_index(sock_net(sk), addr->can_ifindex); if (!dev) { err = -ENODEV; goto out; } - if (dev->type != ARPHRD_CAN) { + if (!can_get_ml_priv(dev)) { err = -ENODEV; goto out_put_dev; } if (!(dev->flags & IFF_UP)) -- 2.43.0