diff options
| author | Felix Jia <felix.jia@alliedtelesis.co.nz> | 2017-02-26 18:41:23 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2017-03-01 13:22:48 -0500 |
| commit | 8c171d6ca56c6891372a97af26b58b2cfad7fd9a (patch) | |
| tree | 13aaa3cbaebb1e12014a986f9f5e2c7c944501b1 /net | |
| parent | a3695e9751b3c616170b552f8561b5a7c5b7a3ca (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.c | 22 |
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 | ||
| 5729 | out: | ||
| 5730 | rtnl_unlock(); | ||
| 5731 | |||
| 5724 | return ret; | 5732 | return ret; |
| 5725 | } | 5733 | } |
| 5726 | 5734 | ||
