mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2024-12-29 17:23:36 +00:00
ipv6: annotate data-races around np->ucast_oif
np->ucast_oif is read locklessly in some contexts. Make all accesses to this field lockless, adding appropriate annotations. This also makes setsockopt( IPV6_UNICAST_IF ) lockless. Signed-off-by: Eric Dumazet <edumazet@google.com> Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
d2f011a0bf
commit
1ac13efd61
@ -62,7 +62,7 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6,
|
||||
if (ipv6_addr_is_multicast(&fl6->daddr))
|
||||
oif = READ_ONCE(np->mcast_oif);
|
||||
else
|
||||
oif = np->ucast_oif;
|
||||
oif = READ_ONCE(np->ucast_oif);
|
||||
}
|
||||
|
||||
fl6->flowi6_oif = oif;
|
||||
|
@ -586,7 +586,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
|
||||
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||
else if (!fl6.flowi6_oif)
|
||||
fl6.flowi6_oif = np->ucast_oif;
|
||||
fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
|
||||
|
||||
ipcm6_init_sk(&ipc6, sk);
|
||||
ipc6.sockc.mark = mark;
|
||||
@ -772,7 +772,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
|
||||
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||
else if (!fl6.flowi6_oif)
|
||||
fl6.flowi6_oif = np->ucast_oif;
|
||||
fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
|
||||
|
||||
if (ip6_dst_lookup(net, sk, &dst, &fl6))
|
||||
goto out;
|
||||
|
@ -537,6 +537,31 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
||||
}
|
||||
WRITE_ONCE(np->mcast_oif, val);
|
||||
return 0;
|
||||
case IPV6_UNICAST_IF:
|
||||
{
|
||||
struct net_device *dev;
|
||||
int ifindex;
|
||||
|
||||
if (optlen != sizeof(int))
|
||||
return -EINVAL;
|
||||
|
||||
ifindex = (__force int)ntohl((__force __be32)val);
|
||||
if (!ifindex) {
|
||||
WRITE_ONCE(np->ucast_oif, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev = dev_get_by_index(net, ifindex);
|
||||
if (!dev)
|
||||
return -EADDRNOTAVAIL;
|
||||
dev_put(dev);
|
||||
|
||||
if (READ_ONCE(sk->sk_bound_dev_if))
|
||||
return -EINVAL;
|
||||
|
||||
WRITE_ONCE(np->ucast_oif, ifindex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (needs_rtnl)
|
||||
rtnl_lock();
|
||||
@ -857,37 +882,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case IPV6_UNICAST_IF:
|
||||
{
|
||||
struct net_device *dev = NULL;
|
||||
int ifindex;
|
||||
|
||||
if (optlen != sizeof(int))
|
||||
goto e_inval;
|
||||
|
||||
ifindex = (__force int)ntohl((__force __be32)val);
|
||||
if (ifindex == 0) {
|
||||
np->ucast_oif = 0;
|
||||
retv = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
dev = dev_get_by_index(net, ifindex);
|
||||
retv = -EADDRNOTAVAIL;
|
||||
if (!dev)
|
||||
break;
|
||||
dev_put(dev);
|
||||
|
||||
retv = -EINVAL;
|
||||
if (sk->sk_bound_dev_if)
|
||||
break;
|
||||
|
||||
np->ucast_oif = ifindex;
|
||||
retv = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case IPV6_ADD_MEMBERSHIP:
|
||||
case IPV6_DROP_MEMBERSHIP:
|
||||
{
|
||||
@ -1369,7 +1363,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
||||
break;
|
||||
|
||||
case IPV6_UNICAST_IF:
|
||||
val = (__force int)htonl((__u32) np->ucast_oif);
|
||||
val = (__force int)htonl((__u32) READ_ONCE(np->ucast_oif));
|
||||
break;
|
||||
|
||||
case IPV6_MTU_DISCOVER:
|
||||
|
@ -109,7 +109,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
if (!oif && ipv6_addr_is_multicast(daddr))
|
||||
oif = READ_ONCE(np->mcast_oif);
|
||||
else if (!oif)
|
||||
oif = np->ucast_oif;
|
||||
oif = READ_ONCE(np->ucast_oif);
|
||||
|
||||
addr_type = ipv6_addr_type(daddr);
|
||||
if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) ||
|
||||
@ -159,7 +159,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||
else if (!fl6.flowi6_oif)
|
||||
fl6.flowi6_oif = np->ucast_oif;
|
||||
fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
|
||||
|
||||
pfh.icmph.type = user_icmph.icmp6_type;
|
||||
pfh.icmph.code = user_icmph.icmp6_code;
|
||||
|
@ -878,7 +878,7 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||
else if (!fl6.flowi6_oif)
|
||||
fl6.flowi6_oif = np->ucast_oif;
|
||||
fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
|
||||
security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
|
||||
|
||||
if (hdrincl)
|
||||
|
@ -1544,7 +1544,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
fl6->flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||
connected = false;
|
||||
} else if (!fl6->flowi6_oif)
|
||||
fl6->flowi6_oif = np->ucast_oif;
|
||||
fl6->flowi6_oif = READ_ONCE(np->ucast_oif);
|
||||
|
||||
security_sk_classify_flow(sk, flowi6_to_flowi_common(fl6));
|
||||
|
||||
|
@ -601,7 +601,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
|
||||
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||
else if (!fl6.flowi6_oif)
|
||||
fl6.flowi6_oif = np->ucast_oif;
|
||||
fl6.flowi6_oif = READ_ONCE(np->ucast_oif);
|
||||
|
||||
security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user