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

ipv6: annotate data-races around np->mcast_oif



np->mcast_oif is read locklessly in some contexts.

Make all accesses to this field lockless, adding appropriate
annotations.

This also makes setsockopt( IPV6_MULTICAST_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 9a64d4c9
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -669,7 +669,7 @@ static int dccp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
ipv6_pktoptions:
	if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) {
		if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo)
			np->mcast_oif = inet6_iif(opt_skb);
			WRITE_ONCE(np->mcast_oif, inet6_iif(opt_skb));
		if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim)
			WRITE_ONCE(np->mcast_hops, ipv6_hdr(opt_skb)->hop_limit);
		if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
+2 −2
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ static void ip6_datagram_flow_key_init(struct flowi6 *fl6,

	if (!oif) {
		if (ipv6_addr_is_multicast(&fl6->daddr))
			oif = np->mcast_oif;
			oif = READ_ONCE(np->mcast_oif);
		else
			oif = np->ucast_oif;
	}
@@ -229,7 +229,7 @@ int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr,
		}

		if (!sk->sk_bound_dev_if && (addr_type & IPV6_ADDR_MULTICAST))
			WRITE_ONCE(sk->sk_bound_dev_if, np->mcast_oif);
			WRITE_ONCE(sk->sk_bound_dev_if, READ_ONCE(np->mcast_oif));

		/* Connect to link-local address requires an interface */
		if (!sk->sk_bound_dev_if) {
+2 −2
Original line number Diff line number Diff line
@@ -584,7 +584,7 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
	tmp_hdr.icmp6_pointer = htonl(info);

	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
		fl6.flowi6_oif = np->mcast_oif;
		fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
	else if (!fl6.flowi6_oif)
		fl6.flowi6_oif = np->ucast_oif;

@@ -770,7 +770,7 @@ static enum skb_drop_reason icmpv6_echo_reply(struct sk_buff *skb)
	np = inet6_sk(sk);

	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
		fl6.flowi6_oif = np->mcast_oif;
		fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
	else if (!fl6.flowi6_oif)
		fl6.flowi6_oif = np->ucast_oif;

+38 −36
Original line number Diff line number Diff line
@@ -509,6 +509,34 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
		if (optlen < sizeof(int))
			return -EINVAL;
		return ip6_sock_set_addr_preferences(sk, val);
	case IPV6_MULTICAST_IF:
		if (sk->sk_type == SOCK_STREAM)
			return -ENOPROTOOPT;
		if (optlen < sizeof(int))
			return -EINVAL;
		if (val) {
			struct net_device *dev;
			int bound_dev_if, midx;

			rcu_read_lock();

			dev = dev_get_by_index_rcu(net, val);
			if (!dev) {
				rcu_read_unlock();
				return -ENODEV;
			}
			midx = l3mdev_master_ifindex_rcu(dev);

			rcu_read_unlock();

			bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
			if (bound_dev_if &&
			    bound_dev_if != val &&
			    (!midx || midx != bound_dev_if))
				return -EINVAL;
		}
		WRITE_ONCE(np->mcast_oif, val);
		return 0;
	}
	if (needs_rtnl)
		rtnl_lock();
@@ -860,36 +888,6 @@ int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
		break;
	}

	case IPV6_MULTICAST_IF:
		if (sk->sk_type == SOCK_STREAM)
			break;
		if (optlen < sizeof(int))
			goto e_inval;

		if (val) {
			struct net_device *dev;
			int midx;

			rcu_read_lock();

			dev = dev_get_by_index_rcu(net, val);
			if (!dev) {
				rcu_read_unlock();
				retv = -ENODEV;
				break;
			}
			midx = l3mdev_master_ifindex_rcu(dev);

			rcu_read_unlock();

			if (sk->sk_bound_dev_if &&
			    sk->sk_bound_dev_if != val &&
			    (!midx || midx != sk->sk_bound_dev_if))
				goto e_inval;
		}
		np->mcast_oif = val;
		retv = 0;
		break;
	case IPV6_ADD_MEMBERSHIP:
	case IPV6_DROP_MEMBERSHIP:
	{
@@ -1161,10 +1159,12 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
		sockopt_release_sock(sk);
		if (!skb) {
			if (np->rxopt.bits.rxinfo) {
				int mcast_oif = READ_ONCE(np->mcast_oif);
				struct in6_pktinfo src_info;
				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :

				src_info.ipi6_ifindex = mcast_oif ? :
					np->sticky_pktinfo.ipi6_ifindex;
				src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr;
				src_info.ipi6_addr = mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr;
				put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info);
			}
			if (np->rxopt.bits.rxhlim) {
@@ -1178,10 +1178,12 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
				put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass);
			}
			if (np->rxopt.bits.rxoinfo) {
				int mcast_oif = READ_ONCE(np->mcast_oif);
				struct in6_pktinfo src_info;
				src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif :

				src_info.ipi6_ifindex = mcast_oif ? :
					np->sticky_pktinfo.ipi6_ifindex;
				src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr :
				src_info.ipi6_addr = mcast_oif ? sk->sk_v6_daddr :
								 np->sticky_pktinfo.ipi6_addr;
				put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info);
			}
@@ -1359,7 +1361,7 @@ int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
		break;

	case IPV6_MULTICAST_IF:
		val = np->mcast_oif;
		val = READ_ONCE(np->mcast_oif);
		break;

	case IPV6_MULTICAST_ALL:
+2 −2
Original line number Diff line number Diff line
@@ -107,7 +107,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
		oif = np->sticky_pktinfo.ipi6_ifindex;

	if (!oif && ipv6_addr_is_multicast(daddr))
		oif = np->mcast_oif;
		oif = READ_ONCE(np->mcast_oif);
	else if (!oif)
		oif = np->ucast_oif;

@@ -157,7 +157,7 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
	rt = (struct rt6_info *) dst;

	if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr))
		fl6.flowi6_oif = np->mcast_oif;
		fl6.flowi6_oif = READ_ONCE(np->mcast_oif);
	else if (!fl6.flowi6_oif)
		fl6.flowi6_oif = np->ucast_oif;

Loading