mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-21 12:11:49 +08: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))
|
if (ipv6_addr_is_multicast(&fl6->daddr))
|
||||||
oif = READ_ONCE(np->mcast_oif);
|
oif = READ_ONCE(np->mcast_oif);
|
||||||
else
|
else
|
||||||
oif = np->ucast_oif;
|
oif = READ_ONCE(np->ucast_oif);
|
||||||
}
|
}
|
||||||
|
|
||||||
fl6->flowi6_oif = 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))
|
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||||
else if (!fl6.flowi6_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);
|
ipcm6_init_sk(&ipc6, sk);
|
||||||
ipc6.sockc.mark = mark;
|
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))
|
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||||
else if (!fl6.flowi6_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))
|
if (ip6_dst_lookup(net, sk, &dst, &fl6))
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -537,6 +537,31 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
|
|||||||
}
|
}
|
||||||
WRITE_ONCE(np->mcast_oif, val);
|
WRITE_ONCE(np->mcast_oif, val);
|
||||||
return 0;
|
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)
|
if (needs_rtnl)
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
@ -857,37 +882,6 @@ done:
|
|||||||
break;
|
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_ADD_MEMBERSHIP:
|
||||||
case IPV6_DROP_MEMBERSHIP:
|
case IPV6_DROP_MEMBERSHIP:
|
||||||
{
|
{
|
||||||
@ -1369,7 +1363,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case IPV6_UNICAST_IF:
|
case IPV6_UNICAST_IF:
|
||||||
val = (__force int)htonl((__u32) np->ucast_oif);
|
val = (__force int)htonl((__u32) READ_ONCE(np->ucast_oif));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IPV6_MTU_DISCOVER:
|
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))
|
if (!oif && ipv6_addr_is_multicast(daddr))
|
||||||
oif = READ_ONCE(np->mcast_oif);
|
oif = READ_ONCE(np->mcast_oif);
|
||||||
else if (!oif)
|
else if (!oif)
|
||||||
oif = np->ucast_oif;
|
oif = READ_ONCE(np->ucast_oif);
|
||||||
|
|
||||||
addr_type = ipv6_addr_type(daddr);
|
addr_type = ipv6_addr_type(daddr);
|
||||||
if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) ||
|
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))
|
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||||
else if (!fl6.flowi6_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.type = user_icmph.icmp6_type;
|
||||||
pfh.icmph.code = user_icmph.icmp6_code;
|
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))
|
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||||
else if (!fl6.flowi6_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));
|
security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
|
||||||
|
|
||||||
if (hdrincl)
|
if (hdrincl)
|
||||||
|
@ -1544,7 +1544,7 @@ do_udp_sendmsg:
|
|||||||
fl6->flowi6_oif = READ_ONCE(np->mcast_oif);
|
fl6->flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||||
connected = false;
|
connected = false;
|
||||||
} else if (!fl6->flowi6_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));
|
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))
|
if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
|
||||||
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
|
||||||
else if (!fl6.flowi6_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));
|
security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user