can: raw: add missing refcount for memory leak fix
Subsystems (2)
Oliver Hartkopp
maintainerPATCH 1/1 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 <[email protected]>
Cc Ziyang Xuan <[email protected]>
Signed-off-by Oliver Hartkopp <[email protected]>
--- net/can/raw.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-)
net/can/raw.c +26 -9
@@ -83,10 +83,11 @@ struct uniqframe {struct raw_sock {struct sock sk;int bound;int ifindex;struct net_device *dev; +netdevice_tracker dev_tracker;struct list_head notifier;int loopback;int recv_own_msgs;int fd_frames;int xl_frames;
@@ -283,12 +284,14 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,switch (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); ro->ifindex =0 ;
@@ -389,14 +392,16 @@ static int raw_release(struct socket *sock)rtnl_lock ();lock_sock (sk);/* 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 )kfree (ro->filter);
@@ -443,44 +448,56 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)if (!dev) { err = -ENODEV ; 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 ; ifindex = dev->ifindex;/* 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 ;/* filters set by default/setsockopt */ err =raw_enable_allfilters (sock_net (sk),NULL , sk); }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 ();if (notify_enetdown) { sk->sk_err =ENETDOWN ;
Signature · 1 line
2.39.2