Skip to content

Commit

Permalink
net/ipv6: avoid possible dead locking on addr_gen_mode sysctl
Browse files Browse the repository at this point in the history
The addr_gen_mode variable can be accessed by both sysctl and netlink.
Repleacd rtnl_lock() with rtnl_trylock() protect the sysctl operation to
avoid the possbile dead lock.`

Signed-off-by: Felix Jia <felix.jia@alliedtelesis.co.nz>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Felix Jia authored and David S. Miller committed Mar 1, 2017
1 parent a3695e9 commit 8c171d6
Showing 1 changed file with 15 additions and 7 deletions.
22 changes: 15 additions & 7 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -5692,13 +5692,18 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
struct inet6_dev *idev = (struct inet6_dev *)ctl->extra1;
struct net *net = (struct net *)ctl->extra2;

if (!rtnl_trylock())
return restart_syscall();

ret = proc_dointvec(ctl, write, buffer, lenp, ppos);

if (write) {
new_val = *((int *)ctl->data);

if (check_addr_gen_mode(new_val) < 0)
return -EINVAL;
if (check_addr_gen_mode(new_val) < 0) {
ret = -EINVAL;
goto out;
}

/* request for default */
if (&net->ipv6.devconf_dflt->addr_gen_mode == ctl->data) {
Expand All @@ -5707,20 +5712,23 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
/* request for individual net device */
} else {
if (!idev)
return ret;
goto out;

if (check_stable_privacy(idev, net, new_val) < 0)
return -EINVAL;
if (check_stable_privacy(idev, net, new_val) < 0) {
ret = -EINVAL;
goto out;
}

if (idev->cnf.addr_gen_mode != new_val) {
idev->cnf.addr_gen_mode = new_val;
rtnl_lock();
addrconf_dev_config(idev->dev);
rtnl_unlock();
}
}
}

out:
rtnl_unlock();

return ret;
}

Expand Down

0 comments on commit 8c171d6

Please sign in to comment.