+++ /dev/null
-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: can: raw: add missing refcount for memory leak fix
-
-From: Oliver Hartkopp <socketcan@hartkopp.net>
-
-commit c275a176e4b69868576e543409927ae75e3a3288 upstream.
-
-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>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- net/can/raw.c | 35 ++++++++++++++++++++++++++---------
- 1 file changed, 26 insertions(+), 9 deletions(-)
-
---- a/net/can/raw.c
-+++ b/net/can/raw.c
-@@ -84,6 +84,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;
-@@ -283,8 +284,10 @@ static void raw_notify(struct raw_sock *
- 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);
-@@ -388,10 +391,12 @@ static int raw_release(struct socket *so
-
- /* 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)
-@@ -442,10 +447,10 @@ static int raw_bind(struct socket *sock,
- 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;
-
-@@ -453,7 +458,9 @@ static int raw_bind(struct socket *sock,
-
- /* 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;
-
-@@ -464,18 +471,28 @@ static int raw_bind(struct socket *sock,
- 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;
-+ /* bind() ok -> hold a reference for new ro->dev */
- ro->dev = 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();
-