Commit 1ac13efd authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

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: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarDavid Ahern <dsahern@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d2f011a0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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;
+26 −32
Original line number Diff line number Diff line
@@ -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:
+2 −2
Original line number Diff line number Diff line
@@ -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;
+1 −1
Original line number Diff line number Diff line
@@ -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)
Loading