aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorFelix Jia <felix.jia@alliedtelesis.co.nz>2017-02-26 18:41:23 -0500
committerDavid S. Miller <davem@davemloft.net>2017-03-01 13:22:48 -0500
commit8c171d6ca56c6891372a97af26b58b2cfad7fd9a (patch)
tree13aaa3cbaebb1e12014a986f9f5e2c7c944501b1 /net
parenta3695e9751b3c616170b552f8561b5a7c5b7a3ca (diff)
net/ipv6: avoid possible dead locking on addr_gen_mode sysctl
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>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 3a2025f5bf2c..cfc485a8e1c0 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -5692,13 +5692,18 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
5692 struct inet6_dev *idev = (struct inet6_dev *)ctl->extra1; 5692 struct inet6_dev *idev = (struct inet6_dev *)ctl->extra1;
5693 struct net *net = (struct net *)ctl->extra2; 5693 struct net *net = (struct net *)ctl->extra2;
5694 5694
5695 if (!rtnl_trylock())
5696 return restart_syscall();
5697
5695 ret = proc_dointvec(ctl, write, buffer, lenp, ppos); 5698 ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
5696 5699
5697 if (write) { 5700 if (write) {
5698 new_val = *((int *)ctl->data); 5701 new_val = *((int *)ctl->data);
5699 5702
5700 if (check_addr_gen_mode(new_val) < 0) 5703 if (check_addr_gen_mode(new_val) < 0) {
5701 return -EINVAL; 5704 ret = -EINVAL;
5705 goto out;
5706 }
5702 5707
5703 /* request for default */ 5708 /* request for default */
5704 if (&net->ipv6.devconf_dflt->addr_gen_mode == ctl->data) { 5709 if (&net->ipv6.devconf_dflt->addr_gen_mode == ctl->data) {
@@ -5707,20 +5712,23 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
5707 /* request for individual net device */ 5712 /* request for individual net device */
5708 } else { 5713 } else {
5709 if (!idev) 5714 if (!idev)
5710 return ret; 5715 goto out;
5711 5716
5712 if (check_stable_privacy(idev, net, new_val) < 0) 5717 if (check_stable_privacy(idev, net, new_val) < 0) {
5713 return -EINVAL; 5718 ret = -EINVAL;
5719 goto out;
5720 }
5714 5721
5715 if (idev->cnf.addr_gen_mode != new_val) { 5722 if (idev->cnf.addr_gen_mode != new_val) {
5716 idev->cnf.addr_gen_mode = new_val; 5723 idev->cnf.addr_gen_mode = new_val;
5717 rtnl_lock();
5718 addrconf_dev_config(idev->dev); 5724 addrconf_dev_config(idev->dev);
5719 rtnl_unlock();
5720 } 5725 }
5721 } 5726 }
5722 } 5727 }
5723 5728
5729out:
5730 rtnl_unlock();
5731
5724 return ret; 5732 return ret;
5725} 5733}
5726 5734