From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794590518; b=EIqnq/RZshXIQjXsLeY+0ARHAgxADEJni21qJl/eBxeXrrvx0lv1FcvJf0OqW9mE8+fW qpCa8sdfxk5NrM2gwRrSydx5z6A6aaOR6bu+A9TwJgpTaslkdVqq8svGc3VtCH+Zsj5MM hz2Isw9zi4AJs44yGyAMI7Bu6tTVO+b2uM/AAxLpQupFfDzQY1xBAZu1FQiDgBSEkTyzL yVWynchqzsl3FZZwTPKacXBbG+oCD1jP2DYttWvZGPwjPhAXQbvymk5oWc1aGoHaSkc1m ypVxsNiELN33ypPD+mI03C7uoBzT3HHTHFsL2lyuyu6a/J9GLrdpcgJZdjCSzPmV/dg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794590518; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=fU1KNVq2T5BgTMtN3shgLidrDtHlqADz1kju3BErwAM=; b=Ct6RoATsAqKiqbiewOyMaVruIHFY91wxOD5goz5nLyYSQoPUzqNtMayBXB7EaoMwF42B W4vanMg7oZzhkQOZx9gD0o/mnR2Af4kxUEyRev/MWrmbEl8bdPlkGZoQrgcQ4qw6g7fQh fek/XB+kaW0dUM2VAKRm/YXuh4AzSrWks6gXg1zphEmzO9LZgqWl5icUQoOiLU1yIEGuV vw1kKqmCwGmjhD0CNcoLJDuS5kuacuVYIbjuC8iFba3pkkW3N3BEQWDwoDMCR12sB05yD paSrwdEamA3tXIDBP+BaMqnA5Ztyg247mcg++Iii51A9cxqHCT01M3lY5UZaJFr6z2w== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=bgUO3s83; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CC2DC606A8A7; Fri, 13 Nov 2026 17:21:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=bgUO3s83 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 783491F000C8; Fri, 13 Nov 2026 17:21:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794590518; bh=fU1KNVq2T5BgTMtN3shgLidrDtHlqADz1kju3BErwAM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=bgUO3s83nIuIkVITXAU1xkgP4c0Ag0Y4E49azG+pkX6QWYk/SJ7caYvsx8JwtjY+O s80vUngOz2Gva4Uj2Vh/D+hx7te1zJBXgSUg2V/GatZOfk4x4SDOr2ajad7oUJjpGr GMpvbgTBdwvhY2ctdt1wrqR3f/J8pIoMhYuLMmmI= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Oleksij Rempel , Oliver Hartkopp , Marc Kleine-Budde , Sasha Levin Subject: [PATCH 6.18 464/686] can: replace ARPHRD_CAN type checks with can_get_ml_priv() Date: Fri, 13 Nov 2026 10:49:57 -0500 Message-ID: <20261113153836.598615510@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261113153820.902362109@linuxfoundation.org> References: <20261113153820.902362109@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: stable@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 6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Oliver Hartkopp commit 962947b69589881167054bae5accc8abfd5aa4b6 upstream. 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@vger.kernel.org Cc: Oleksij Rempel Signed-off-by: Oliver Hartkopp Link: https://patch.msgid.link/20261027-can-rx-lock-v12-1-eb5afc2d8b9b@hartkopp.net Signed-off-by: Marc Kleine-Budde [ backport to 6.18: This tree has no can_skb_ext, so only the ARPHRD_CAN check is removed from the conditions in can_rcv(), canfd_rcv() and canxl_rcv(). Add the include to raw.c, which upstream got with commit faba5860fcf9 ("can: raw: instantly reject disabled CAN frames"). ] Signed-off-by: Oliver Hartkopp Signed-off-by: Sasha Levin --- net/can/af_can.c | 12 ++++++------ net/can/bcm.c | 7 ++++--- net/can/gw.c | 7 ++++--- net/can/isotp.c | 5 +++-- net/can/raw.c | 5 +++-- 5 files changed, 20 insertions(+), 16 deletions(-) diff --git a/net/can/af_can.c b/net/can/af_can.c index 52d72d56f2dd3..539e9ba06ccc9 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -226,7 +226,7 @@ int can_send(struct sk_buff *skb, int loop) goto inval_skb; } - if (unlikely(skb->dev->type != ARPHRD_CAN)) { + if (unlikely(!can_get_ml_priv(skb->dev))) { err = -EPERM; goto inval_skb; } @@ -452,7 +452,7 @@ int can_rx_register(struct net *net, struct net_device *dev, canid_t can_id, /* 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))) @@ -519,7 +519,7 @@ void can_rx_unregister(struct net *net, struct net_device *dev, canid_t can_id, 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))) @@ -685,7 +685,7 @@ 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) { - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_can_skb(skb))) { + if (unlikely(!can_get_ml_priv(dev) || !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); @@ -700,7 +700,7 @@ 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) { - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_canfd_skb(skb))) { + if (unlikely(!can_get_ml_priv(dev) || !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); @@ -715,7 +715,7 @@ 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) { - if (unlikely(dev->type != ARPHRD_CAN || !can_get_ml_priv(dev) || !can_is_canxl_skb(skb))) { + if (unlikely(!can_get_ml_priv(dev) || !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); diff --git a/net/can/bcm.c b/net/can/bcm.c index 6d67af0a3b141..5f3321ede5208 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -1706,7 +1707,7 @@ static int bcm_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) goto out_release; } - if (dev->type != ARPHRD_CAN) { + if (!can_get_ml_priv(dev)) { dev_put(dev); ret = -ENODEV; goto out_release; @@ -1854,7 +1855,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg, { 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; @@ -2011,7 +2012,7 @@ static int bcm_connect(struct socket *sock, struct sockaddr *uaddr, int len, 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 79fa58cb232ed..de222fa93d6c3 100644 --- a/net/can/gw.c +++ b/net/can/gw.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -603,7 +604,7 @@ static int cgw_notifier(struct notifier_block *nb, 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) { @@ -1154,7 +1155,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, 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); @@ -1162,7 +1163,7 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh, 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? */ diff --git a/net/can/isotp.c b/net/can/isotp.c index e3261fb4663af..dfe3fd47e220e 100644 --- a/net/can/isotp.c +++ b/net/can/isotp.c @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -1595,7 +1596,7 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len) err = -ENODEV; goto out; } - if (dev->type != ARPHRD_CAN) { + if (!can_get_ml_priv(dev)) { err = -ENODEV; goto out_put_dev; } @@ -1895,7 +1896,7 @@ static int isotp_notifier(struct notifier_block *nb, unsigned long msg, { 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; diff --git a/net/can/raw.c b/net/can/raw.c index 9f0fa8baff85a..26c8cf15d60ed 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include /* for can_is_canxl_dev_mtu() */ #include @@ -343,7 +344,7 @@ static int raw_notifier(struct notifier_block *nb, unsigned long msg, { 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; @@ -486,7 +487,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) err = -ENODEV; goto out; } - if (dev->type != ARPHRD_CAN) { + if (!can_get_ml_priv(dev)) { err = -ENODEV; goto out_put_dev; } -- 2.53.0