Hello Greg,
the dev_tracker including netdev_put() and netdev_hold() has been introduced in Linux 6.0.
I send out a stable backport patch to this group of people for 5.15 :
"[PATCH stable < v6.0] can: raw: add missing refcount for memory leak fix"
Best regards, Oliver
On 27.08.23 12:32, gregkh@linuxfoundation.org wrote:
The patch below does not apply to the 5.15-stable tree. If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to stable@vger.kernel.org.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y git checkout FETCH_HEAD git cherry-pick -x c275a176e4b69868576e543409927ae75e3a3288 # <resolve conflicts, build, test, etc.> git commit -s git send-email --to 'stable@vger.kernel.org' --in-reply-to '2023082737-cavity-bloating-1779@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
c275a176e4b6 ("can: raw: add missing refcount for memory leak fix") ee8b94c8510c ("can: raw: fix receiver memory leak")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From c275a176e4b69868576e543409927ae75e3a3288 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp socketcan@hartkopp.net Date: Mon, 21 Aug 2023 16:45:47 +0200 Subject: [PATCH] can: raw: add missing refcount for memory leak fix
Commit ee8b94c8510c ("can: raw: fix receiver memory leak") introduced a new reference to the CAN netdevice that has assigned CAN filters. But this new ro->dev reference did not maintain its own refcount which lead to another KASAN use-after-free splat found by Eric Dumazet.
This patch ensures a proper refcount for the CAN nedevice.
Fixes: ee8b94c8510c ("can: raw: fix receiver memory leak") Reported-by: Eric Dumazet edumazet@google.com Cc: Ziyang Xuan william.xuanziyang@huawei.com Signed-off-by: Oliver Hartkopp socketcan@hartkopp.net Link: https://lore.kernel.org/r/20230821144547.6658-3-socketcan@hartkopp.net Signed-off-by: Jakub Kicinski kuba@kernel.org
diff --git a/net/can/raw.c b/net/can/raw.c index e10f59375659..d50c3f3d892f 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -85,6 +85,7 @@ struct raw_sock { int bound; int ifindex; struct net_device *dev;
- netdevice_tracker dev_tracker; struct list_head notifier; int loopback; int recv_own_msgs;
@@ -285,8 +286,10 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg, case NETDEV_UNREGISTER: lock_sock(sk); /* remove current filters & unregister */
if (ro->bound)
if (ro->bound) { raw_disable_allfilters(dev_net(dev), dev, sk);
netdev_put(dev, &ro->dev_tracker);
}
if (ro->count > 1) kfree(ro->filter); @@ -391,10 +394,12 @@ static int raw_release(struct socket *sock) /* remove current filters & unregister */ if (ro->bound) {
if (ro->dev)
if (ro->dev) { raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
else
netdev_put(ro->dev, &ro->dev_tracker);
} else { raw_disable_allfilters(sock_net(sk), NULL, sk);
}}
if (ro->count > 1) @@ -445,10 +450,10 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) goto out; } if (dev->type != ARPHRD_CAN) {
dev_put(dev); err = -ENODEV;
goto out;
}goto out_put_dev;
- if (!(dev->flags & IFF_UP)) notify_enetdown = 1;
@@ -456,7 +461,9 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) /* filters set by default/setsockopt */ err = raw_enable_allfilters(sock_net(sk), dev, sk);
dev_put(dev);
if (err)
goto out_put_dev;
- } else { ifindex = 0;
@@ -467,18 +474,28 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) if (!err) { if (ro->bound) { /* unregister old filters */
if (ro->dev)
if (ro->dev) { raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
else
/* drop reference to old ro->dev */
netdev_put(ro->dev, &ro->dev_tracker);
} else { raw_disable_allfilters(sock_net(sk), NULL, sk);
} ro->ifindex = ifindex; ro->bound = 1;}
ro->dev = dev;/* bind() ok -> hold a reference for new ro->dev */
if (ro->dev)
}netdev_hold(ro->dev, &ro->dev_tracker, GFP_KERNEL);
- out:
+out_put_dev:
- /* remove potential reference from dev_get_by_index() */
- if (dev)
dev_put(dev);
+out: release_sock(sk); rtnl_unlock();