can: replace ARPHRD_CAN type checks with can_get_ml_priv()
Subsystems (2)
Oliver Hartkopp
maintainerPATCH v2 1/1 can: replace ARPHRD_CAN type checks with can_get_ml_priv()
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 and triggers a NULL pointer dereference when CAN filters are created and when they are removed, e.g. by the CAN protocols' netdevice notifier handlers. 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().
---
v2: rephrased the commit message due to sashiko-bot feedback
--- 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(-)
net/can/af_can.c +6 -9
@@ -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 ;
net/can/bcm.c +4 -3
@@ -52,10 +52,11 @@#include <linux/netdevice.h> #include <linux/socket.h> #include <linux/if_arp.h> #include <linux/skbuff.h> #include <linux/can.h> +#include <linux/can/can-ml.h> #include <linux/can/core.h> #include <linux/can/skb.h> #include <linux/can/bcm.h> #include <linux/slab.h> #include <linux/workqueue.h>
@@ -1717,11 +1718,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; }
@@ -1865,11 +1866,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 ;
@@ -2022,11 +2023,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; }
net/can/gw.c +4 -3
@@ -50,10 +50,11 @@#include <linux/net.h> #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/skbuff.h> #include <linux/can.h> +#include <linux/can/can-ml.h> #include <linux/can/core.h> #include <linux/can/skb.h> #include <linux/can/gw.h> #include <net/can.h> #include <net/rtnetlink.h>
@@ -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 )) {
net/can/isotp.c +3 -2
@@ -63,10 +63,11 @@#include <linux/netdevice.h> #include <linux/socket.h> #include <linux/if_arp.h> #include <linux/skbuff.h> #include <linux/can.h> +#include <linux/can/can-ml.h> #include <linux/can/core.h> #include <linux/can/skb.h> #include <linux/can/isotp.h> #include <linux/slab.h> #include <net/can.h>
@@ -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 ;
net/can/raw.c +2 -2
@@ -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 ))
Signature · 1 line
2.53.0
Marc Kleine-Budde
maintainerQuoted 20 lines · Oliver Hartkopp
Commit
4e096a18867a("net: introduce CAN specific pointer in the structnet_device") introduced an explicit way to assign the midlayer private pointer (dev->ml_priv) to named users likeML_PRIV_CAN. A valid pointer returned bycan_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_CANwhiledev->ml_privremains NULL. Such a repurposed netdevice passes theARPHRD_CANchecks and triggers a NULL pointer dereference when CAN filters are created and when they are removed, e.g. by the CAN protocols' netdevice notifier handlers. This only requires owning a TUN/TAP device orCAP_NET_ADMINin an unprivileged user namespace.Convert the remaining
ARPHRD_CANchecks inaf_can, bcm, gw, isotp and raw tocan_get_ml_priv().
Quoted 7 lines
Fixes 4e096a18867a ("net: introduce CAN specific pointer in the struct net_device")Cc Oleksij Rempel <[email protected]>Signed-off-by Oliver Hartkopp <[email protected]>---
v2: rephrased the commit message due to sashiko-bot feedback
---
Replaced patch.
Thanks,
Marc
pw-bot: accepted
Signature · 4 lines
Pengutronix e.K. | Marc Kleine-Budde | Embedded Linux | https://www.pengutronix.de | Vertretung Nürnberg | Phone: +49-5121-206917-129 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 |