]>
Commit | Line | Data |
---|---|---|
18a2513c GKH |
1 | From foo@baz Tue Nov 28 10:56:34 CET 2017 |
2 | From: David Ahern <dsa@cumulusnetworks.com> | |
3 | Date: Thu, 29 Dec 2016 15:39:37 -0800 | |
4 | Subject: net: Allow IP_MULTICAST_IF to set index to L3 slave | |
5 | ||
6 | From: David Ahern <dsa@cumulusnetworks.com> | |
7 | ||
8 | ||
9 | [ Upstream commit 7bb387c5ab12aeac3d5eea28686489ff46b53ca9 ] | |
10 | ||
11 | IP_MULTICAST_IF fails if sk_bound_dev_if is already set and the new index | |
12 | does not match it. e.g., | |
13 | ||
14 | ntpd[15381]: setsockopt IP_MULTICAST_IF 192.168.1.23 fails: Invalid argument | |
15 | ||
16 | Relax the check in setsockopt to allow setting mc_index to an L3 slave if | |
17 | sk_bound_dev_if points to an L3 master. | |
18 | ||
19 | Make a similar change for IPv6. In this case change the device lookup to | |
20 | take the rcu_read_lock avoiding a refcnt. The rcu lock is also needed for | |
21 | the lookup of a potential L3 master device. | |
22 | ||
23 | This really only silences a setsockopt failure since uses of mc_index are | |
24 | secondary to sk_bound_dev_if if it is set. In both cases, if either index | |
25 | is an L3 slave or master, lookups are directed to the same FIB table so | |
26 | relaxing the check at setsockopt time causes no harm. | |
27 | ||
28 | Patch is based on a suggested change by Darwin for a problem noted in | |
29 | their code base. | |
30 | ||
31 | Suggested-by: Darwin Dingel <darwin.dingel@alliedtelesis.co.nz> | |
32 | Signed-off-by: David Ahern <dsa@cumulusnetworks.com> | |
33 | Signed-off-by: David S. Miller <davem@davemloft.net> | |
34 | Signed-off-by: Sasha Levin <alexander.levin@verizon.com> | |
35 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
36 | --- | |
37 | net/ipv4/ip_sockglue.c | 7 ++++++- | |
38 | net/ipv6/ipv6_sockglue.c | 16 ++++++++++++---- | |
39 | 2 files changed, 18 insertions(+), 5 deletions(-) | |
40 | ||
41 | --- a/net/ipv4/ip_sockglue.c | |
42 | +++ b/net/ipv4/ip_sockglue.c | |
43 | @@ -808,6 +808,7 @@ static int do_ip_setsockopt(struct sock | |
44 | { | |
45 | struct ip_mreqn mreq; | |
46 | struct net_device *dev = NULL; | |
47 | + int midx; | |
48 | ||
49 | if (sk->sk_type == SOCK_STREAM) | |
50 | goto e_inval; | |
51 | @@ -852,11 +853,15 @@ static int do_ip_setsockopt(struct sock | |
52 | err = -EADDRNOTAVAIL; | |
53 | if (!dev) | |
54 | break; | |
55 | + | |
56 | + midx = l3mdev_master_ifindex(dev); | |
57 | + | |
58 | dev_put(dev); | |
59 | ||
60 | err = -EINVAL; | |
61 | if (sk->sk_bound_dev_if && | |
62 | - mreq.imr_ifindex != sk->sk_bound_dev_if) | |
63 | + mreq.imr_ifindex != sk->sk_bound_dev_if && | |
64 | + (!midx || midx != sk->sk_bound_dev_if)) | |
65 | break; | |
66 | ||
67 | inet->mc_index = mreq.imr_ifindex; | |
68 | --- a/net/ipv6/ipv6_sockglue.c | |
69 | +++ b/net/ipv6/ipv6_sockglue.c | |
70 | @@ -583,16 +583,24 @@ done: | |
71 | ||
72 | if (val) { | |
73 | struct net_device *dev; | |
74 | + int midx; | |
75 | ||
76 | - if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) | |
77 | - goto e_inval; | |
78 | + rcu_read_lock(); | |
79 | ||
80 | - dev = dev_get_by_index(net, val); | |
81 | + dev = dev_get_by_index_rcu(net, val); | |
82 | if (!dev) { | |
83 | + rcu_read_unlock(); | |
84 | retv = -ENODEV; | |
85 | break; | |
86 | } | |
87 | - dev_put(dev); | |
88 | + midx = l3mdev_master_ifindex_rcu(dev); | |
89 | + | |
90 | + rcu_read_unlock(); | |
91 | + | |
92 | + if (sk->sk_bound_dev_if && | |
93 | + sk->sk_bound_dev_if != val && | |
94 | + (!midx || midx != sk->sk_bound_dev_if)) | |
95 | + goto e_inval; | |
96 | } | |
97 | np->mcast_oif = val; | |
98 | retv = 0; |