Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
d2f011a0 9a64d4c9

+51 -49
+1 -1
net/dccp/ipv6.c
··· 669 669 ipv6_pktoptions: 670 670 if (!((1 << sk->sk_state) & (DCCPF_CLOSED | DCCPF_LISTEN))) { 671 671 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) 672 - np->mcast_oif = inet6_iif(opt_skb); 672 + WRITE_ONCE(np->mcast_oif, inet6_iif(opt_skb)); 673 673 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) 674 674 WRITE_ONCE(np->mcast_hops, ipv6_hdr(opt_skb)->hop_limit); 675 675 if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass)
+2 -2
net/ipv6/datagram.c
··· 60 60 61 61 if (!oif) { 62 62 if (ipv6_addr_is_multicast(&fl6->daddr)) 63 - oif = np->mcast_oif; 63 + oif = READ_ONCE(np->mcast_oif); 64 64 else 65 65 oif = np->ucast_oif; 66 66 } ··· 229 229 } 230 230 231 231 if (!sk->sk_bound_dev_if && (addr_type & IPV6_ADDR_MULTICAST)) 232 - WRITE_ONCE(sk->sk_bound_dev_if, np->mcast_oif); 232 + WRITE_ONCE(sk->sk_bound_dev_if, READ_ONCE(np->mcast_oif)); 233 233 234 234 /* Connect to link-local address requires an interface */ 235 235 if (!sk->sk_bound_dev_if) {
+2 -2
net/ipv6/icmp.c
··· 584 584 tmp_hdr.icmp6_pointer = htonl(info); 585 585 586 586 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 587 - fl6.flowi6_oif = np->mcast_oif; 587 + fl6.flowi6_oif = READ_ONCE(np->mcast_oif); 588 588 else if (!fl6.flowi6_oif) 589 589 fl6.flowi6_oif = np->ucast_oif; 590 590 ··· 770 770 np = inet6_sk(sk); 771 771 772 772 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 773 - fl6.flowi6_oif = np->mcast_oif; 773 + fl6.flowi6_oif = READ_ONCE(np->mcast_oif); 774 774 else if (!fl6.flowi6_oif) 775 775 fl6.flowi6_oif = np->ucast_oif; 776 776
+38 -36
net/ipv6/ipv6_sockglue.c
··· 509 509 if (optlen < sizeof(int)) 510 510 return -EINVAL; 511 511 return ip6_sock_set_addr_preferences(sk, val); 512 + case IPV6_MULTICAST_IF: 513 + if (sk->sk_type == SOCK_STREAM) 514 + return -ENOPROTOOPT; 515 + if (optlen < sizeof(int)) 516 + return -EINVAL; 517 + if (val) { 518 + struct net_device *dev; 519 + int bound_dev_if, midx; 520 + 521 + rcu_read_lock(); 522 + 523 + dev = dev_get_by_index_rcu(net, val); 524 + if (!dev) { 525 + rcu_read_unlock(); 526 + return -ENODEV; 527 + } 528 + midx = l3mdev_master_ifindex_rcu(dev); 529 + 530 + rcu_read_unlock(); 531 + 532 + bound_dev_if = READ_ONCE(sk->sk_bound_dev_if); 533 + if (bound_dev_if && 534 + bound_dev_if != val && 535 + (!midx || midx != bound_dev_if)) 536 + return -EINVAL; 537 + } 538 + WRITE_ONCE(np->mcast_oif, val); 539 + return 0; 512 540 } 513 541 if (needs_rtnl) 514 542 rtnl_lock(); ··· 888 860 break; 889 861 } 890 862 891 - case IPV6_MULTICAST_IF: 892 - if (sk->sk_type == SOCK_STREAM) 893 - break; 894 - if (optlen < sizeof(int)) 895 - goto e_inval; 896 - 897 - if (val) { 898 - struct net_device *dev; 899 - int midx; 900 - 901 - rcu_read_lock(); 902 - 903 - dev = dev_get_by_index_rcu(net, val); 904 - if (!dev) { 905 - rcu_read_unlock(); 906 - retv = -ENODEV; 907 - break; 908 - } 909 - midx = l3mdev_master_ifindex_rcu(dev); 910 - 911 - rcu_read_unlock(); 912 - 913 - if (sk->sk_bound_dev_if && 914 - sk->sk_bound_dev_if != val && 915 - (!midx || midx != sk->sk_bound_dev_if)) 916 - goto e_inval; 917 - } 918 - np->mcast_oif = val; 919 - retv = 0; 920 - break; 921 863 case IPV6_ADD_MEMBERSHIP: 922 864 case IPV6_DROP_MEMBERSHIP: 923 865 { ··· 1159 1161 sockopt_release_sock(sk); 1160 1162 if (!skb) { 1161 1163 if (np->rxopt.bits.rxinfo) { 1164 + int mcast_oif = READ_ONCE(np->mcast_oif); 1162 1165 struct in6_pktinfo src_info; 1163 - src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : 1166 + 1167 + src_info.ipi6_ifindex = mcast_oif ? : 1164 1168 np->sticky_pktinfo.ipi6_ifindex; 1165 - src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr; 1169 + src_info.ipi6_addr = mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr; 1166 1170 put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); 1167 1171 } 1168 1172 if (np->rxopt.bits.rxhlim) { ··· 1178 1178 put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); 1179 1179 } 1180 1180 if (np->rxopt.bits.rxoinfo) { 1181 + int mcast_oif = READ_ONCE(np->mcast_oif); 1181 1182 struct in6_pktinfo src_info; 1182 - src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : 1183 + 1184 + src_info.ipi6_ifindex = mcast_oif ? : 1183 1185 np->sticky_pktinfo.ipi6_ifindex; 1184 - src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : 1185 - np->sticky_pktinfo.ipi6_addr; 1186 + src_info.ipi6_addr = mcast_oif ? sk->sk_v6_daddr : 1187 + np->sticky_pktinfo.ipi6_addr; 1186 1188 put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); 1187 1189 } 1188 1190 if (np->rxopt.bits.rxohlim) { ··· 1361 1359 break; 1362 1360 1363 1361 case IPV6_MULTICAST_IF: 1364 - val = np->mcast_oif; 1362 + val = READ_ONCE(np->mcast_oif); 1365 1363 break; 1366 1364 1367 1365 case IPV6_MULTICAST_ALL:
+2 -2
net/ipv6/ping.c
··· 107 107 oif = np->sticky_pktinfo.ipi6_ifindex; 108 108 109 109 if (!oif && ipv6_addr_is_multicast(daddr)) 110 - oif = np->mcast_oif; 110 + oif = READ_ONCE(np->mcast_oif); 111 111 else if (!oif) 112 112 oif = np->ucast_oif; 113 113 ··· 157 157 rt = (struct rt6_info *) dst; 158 158 159 159 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 160 - fl6.flowi6_oif = np->mcast_oif; 160 + fl6.flowi6_oif = READ_ONCE(np->mcast_oif); 161 161 else if (!fl6.flowi6_oif) 162 162 fl6.flowi6_oif = np->ucast_oif; 163 163
+1 -1
net/ipv6/raw.c
··· 876 876 final_p = fl6_update_dst(&fl6, opt, &final); 877 877 878 878 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 879 - fl6.flowi6_oif = np->mcast_oif; 879 + fl6.flowi6_oif = READ_ONCE(np->mcast_oif); 880 880 else if (!fl6.flowi6_oif) 881 881 fl6.flowi6_oif = np->ucast_oif; 882 882 security_sk_classify_flow(sk, flowi6_to_flowi_common(&fl6));
+1 -1
net/ipv6/tcp_ipv6.c
··· 1702 1702 if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt && 1703 1703 !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { 1704 1704 if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) 1705 - np->mcast_oif = tcp_v6_iif(opt_skb); 1705 + WRITE_ONCE(np->mcast_oif, tcp_v6_iif(opt_skb)); 1706 1706 if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) 1707 1707 WRITE_ONCE(np->mcast_hops, 1708 1708 ipv6_hdr(opt_skb)->hop_limit);
+1 -1
net/ipv6/udp.c
··· 1541 1541 connected = false; 1542 1542 1543 1543 if (!fl6->flowi6_oif && ipv6_addr_is_multicast(&fl6->daddr)) { 1544 - fl6->flowi6_oif = np->mcast_oif; 1544 + fl6->flowi6_oif = READ_ONCE(np->mcast_oif); 1545 1545 connected = false; 1546 1546 } else if (!fl6->flowi6_oif) 1547 1547 fl6->flowi6_oif = np->ucast_oif;
+1 -1
net/l2tp/l2tp_ip6.c
··· 599 599 final_p = fl6_update_dst(&fl6, opt, &final); 600 600 601 601 if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) 602 - fl6.flowi6_oif = np->mcast_oif; 602 + fl6.flowi6_oif = READ_ONCE(np->mcast_oif); 603 603 else if (!fl6.flowi6_oif) 604 604 fl6.flowi6_oif = np->ucast_oif; 605 605
+1 -1
net/netfilter/ipvs/ip_vs_sync.c
··· 1365 1365 struct ipv6_pinfo *np = inet6_sk(sk); 1366 1366 1367 1367 /* IPV6_MULTICAST_IF */ 1368 - np->mcast_oif = dev->ifindex; 1368 + WRITE_ONCE(np->mcast_oif, dev->ifindex); 1369 1369 } 1370 1370 #endif 1371 1371 release_sock(sk);
+1 -1
net/rds/tcp_listen.c
··· 165 165 struct ipv6_pinfo *inet6; 166 166 167 167 inet6 = inet6_sk(new_sock->sk); 168 - dev_if = inet6->mcast_oif; 168 + dev_if = READ_ONCE(inet6->mcast_oif); 169 169 } else { 170 170 dev_if = new_sock->sk->sk_bound_dev_if; 171 171 }