Unverified Commit 40541580 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!2961 can: raw: fix memory leak

Merge Pull Request from: @ci-robot 
 
PR sync from: Ziyang Xuan <william.xuanziyang@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/46A4N7DDK6CD75JIGNDRI3GJXTXNB3LI/ 
Patchset for memory leak fix.

Eric Dumazet (1):
  can: raw: fix lockdep issue in raw_release()

Oliver Hartkopp (1):
  can: raw: add missing refcount for memory leak fix

Ziyang Xuan (1):
  can: raw: fix receiver memory leak


-- 
2.25.1
 
https://gitee.com/openeuler/kernel/issues/I7PM10 
 
Link:https://gitee.com/openeuler/kernel/pulls/2961

 

Reviewed-by: default avatarYue Haibing <yuehaibing@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 8edbf4ae 6edd27d2
Loading
Loading
Loading
Loading
+42 −38
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ struct raw_sock {
	struct sock sk;
	int bound;
	int ifindex;
	struct net_device *dev;
	struct list_head notifier;
	int loopback;
	int recv_own_msgs;
@@ -275,21 +276,24 @@ static void raw_notify(struct raw_sock *ro, unsigned long msg,
	if (!net_eq(dev_net(dev), sock_net(sk)))
		return;

	if (ro->ifindex != dev->ifindex)
	if (ro->dev != dev)
		return;

	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);
			dev_put(dev);
		}

		if (ro->count > 1)
			kfree(ro->filter);

		ro->ifindex = 0;
		ro->bound = 0;
		ro->dev = NULL;
		ro->count = 0;
		release_sock(sk);

@@ -335,6 +339,7 @@ static int raw_init(struct sock *sk)

	ro->bound            = 0;
	ro->ifindex          = 0;
	ro->dev              = NULL;

	/* set default filter to single entry dfilter */
	ro->dfilter.can_id   = 0;
@@ -380,18 +385,14 @@ static int raw_release(struct socket *sock)
	list_del(&ro->notifier);
	spin_unlock(&raw_notifier_lock);

	rtnl_lock();
	lock_sock(sk);

	/* remove current filters & unregister */
	if (ro->bound) {
		if (ro->ifindex) {
			struct net_device *dev;

			dev = dev_get_by_index(sock_net(sk), ro->ifindex);
			if (dev) {
				raw_disable_allfilters(dev_net(dev), dev, sk);
				dev_put(dev);
			}
		if (ro->dev) {
			raw_disable_allfilters(dev_net(ro->dev), ro->dev, sk);
			dev_put(ro->dev);
		} else {
			raw_disable_allfilters(sock_net(sk), NULL, sk);
		}
@@ -402,6 +403,7 @@ static int raw_release(struct socket *sock)

	ro->ifindex = 0;
	ro->bound = 0;
	ro->dev = NULL;
	ro->count = 0;
	free_percpu(ro->uniq);

@@ -409,6 +411,8 @@ static int raw_release(struct socket *sock)
	sock->sk = NULL;

	release_sock(sk);
	rtnl_unlock();

	sock_put(sk);

	return 0;
@@ -419,6 +423,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
	struct sockaddr_can *addr = (struct sockaddr_can *)uaddr;
	struct sock *sk = sock->sk;
	struct raw_sock *ro = raw_sk(sk);
	struct net_device *dev = NULL;
	int ifindex;
	int err = 0;
	int notify_enetdown = 0;
@@ -428,24 +433,23 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
	if (addr->can_family != AF_CAN)
		return -EINVAL;

	rtnl_lock();
	lock_sock(sk);

	if (ro->bound && addr->can_ifindex == ro->ifindex)
		goto out;

	if (addr->can_ifindex) {
		struct net_device *dev;

		dev = dev_get_by_index(sock_net(sk), addr->can_ifindex);
		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;

@@ -453,7 +457,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;

@@ -464,26 +470,30 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
	if (!err) {
		if (ro->bound) {
			/* unregister old filters */
			if (ro->ifindex) {
				struct net_device *dev;

				dev = dev_get_by_index(sock_net(sk),
						       ro->ifindex);
				if (dev) {
					raw_disable_allfilters(dev_net(dev),
							       dev, sk);
					dev_put(dev);
				}
			if (ro->dev) {
				raw_disable_allfilters(dev_net(ro->dev),
						       ro->dev, sk);
				/* drop reference to old ro->dev */
				dev_put(ro->dev);
			} 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)
			dev_hold(ro->dev);
	}

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;
@@ -549,9 +559,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		rtnl_lock();
		lock_sock(sk);

		if (ro->bound && ro->ifindex) {
			dev = dev_get_by_index(sock_net(sk), ro->ifindex);
			if (!dev) {
		dev = ro->dev;
		if (ro->bound && dev) {
			if (dev->reg_state != NETREG_REGISTERED) {
				if (count > 1)
					kfree(filter);
				err = -ENODEV;
@@ -592,9 +602,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		ro->count  = count;

 out_fil:
		if (dev)
			dev_put(dev);

		release_sock(sk);
		rtnl_unlock();

@@ -612,9 +619,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		rtnl_lock();
		lock_sock(sk);

		if (ro->bound && ro->ifindex) {
			dev = dev_get_by_index(sock_net(sk), ro->ifindex);
			if (!dev) {
		dev = ro->dev;
		if (ro->bound && dev) {
			if (dev->reg_state != NETREG_REGISTERED) {
				err = -ENODEV;
				goto out_err;
			}
@@ -638,9 +645,6 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
		ro->err_mask = err_mask;

 out_err:
		if (dev)
			dev_put(dev);

		release_sock(sk);
		rtnl_unlock();