aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpravin shelar <pshelar@ovn.org>2016-10-28 12:59:15 -0400
committerDavid S. Miller <davem@davemloft.net>2016-10-29 20:56:31 -0400
commitc6fcc4fc5f8b592600c7409e769ab68da0fb1eca (patch)
tree4fafb69c92e2169209dfb66452b7d92e8abfb11c
parent087892d29b75c025086d99b29d385a3dac0169fc (diff)
vxlan: avoid using stale vxlan socket.
When vxlan device is closed vxlan socket is freed. This operation can race with vxlan-xmit function which dereferences vxlan socket. Following patch uses RCU mechanism to avoid this situation. Signed-off-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/vxlan.c80
-rw-r--r--include/net/vxlan.h4
2 files changed, 52 insertions, 32 deletions
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index c1639a3e95a4..f3c2fa3ab0d5 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -943,17 +943,20 @@ static bool vxlan_snoop(struct net_device *dev,
943static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev) 943static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev)
944{ 944{
945 struct vxlan_dev *vxlan; 945 struct vxlan_dev *vxlan;
946 struct vxlan_sock *sock4;
947 struct vxlan_sock *sock6 = NULL;
946 unsigned short family = dev->default_dst.remote_ip.sa.sa_family; 948 unsigned short family = dev->default_dst.remote_ip.sa.sa_family;
947 949
950 sock4 = rtnl_dereference(dev->vn4_sock);
951
948 /* The vxlan_sock is only used by dev, leaving group has 952 /* The vxlan_sock is only used by dev, leaving group has
949 * no effect on other vxlan devices. 953 * no effect on other vxlan devices.
950 */ 954 */
951 if (family == AF_INET && dev->vn4_sock && 955 if (family == AF_INET && sock4 && atomic_read(&sock4->refcnt) == 1)
952 atomic_read(&dev->vn4_sock->refcnt) == 1)
953 return false; 956 return false;
954#if IS_ENABLED(CONFIG_IPV6) 957#if IS_ENABLED(CONFIG_IPV6)
955 if (family == AF_INET6 && dev->vn6_sock && 958 sock6 = rtnl_dereference(dev->vn6_sock);
956 atomic_read(&dev->vn6_sock->refcnt) == 1) 959 if (family == AF_INET6 && sock6 && atomic_read(&sock6->refcnt) == 1)
957 return false; 960 return false;
958#endif 961#endif
959 962
@@ -961,10 +964,12 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev)
961 if (!netif_running(vxlan->dev) || vxlan == dev) 964 if (!netif_running(vxlan->dev) || vxlan == dev)
962 continue; 965 continue;
963 966
964 if (family == AF_INET && vxlan->vn4_sock != dev->vn4_sock) 967 if (family == AF_INET &&
968 rtnl_dereference(vxlan->vn4_sock) != sock4)
965 continue; 969 continue;
966#if IS_ENABLED(CONFIG_IPV6) 970#if IS_ENABLED(CONFIG_IPV6)
967 if (family == AF_INET6 && vxlan->vn6_sock != dev->vn6_sock) 971 if (family == AF_INET6 &&
972 rtnl_dereference(vxlan->vn6_sock) != sock6)
968 continue; 973 continue;
969#endif 974#endif
970 975
@@ -1005,22 +1010,25 @@ static bool __vxlan_sock_release_prep(struct vxlan_sock *vs)
1005 1010
1006static void vxlan_sock_release(struct vxlan_dev *vxlan) 1011static void vxlan_sock_release(struct vxlan_dev *vxlan)
1007{ 1012{
1008 bool ipv4 = __vxlan_sock_release_prep(vxlan->vn4_sock); 1013 struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
1009#if IS_ENABLED(CONFIG_IPV6) 1014#if IS_ENABLED(CONFIG_IPV6)
1010 bool ipv6 = __vxlan_sock_release_prep(vxlan->vn6_sock); 1015 struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
1016
1017 rcu_assign_pointer(vxlan->vn6_sock, NULL);
1011#endif 1018#endif
1012 1019
1020 rcu_assign_pointer(vxlan->vn4_sock, NULL);
1013 synchronize_net(); 1021 synchronize_net();
1014 1022
1015 if (ipv4) { 1023 if (__vxlan_sock_release_prep(sock4)) {
1016 udp_tunnel_sock_release(vxlan->vn4_sock->sock); 1024 udp_tunnel_sock_release(sock4->sock);
1017 kfree(vxlan->vn4_sock); 1025 kfree(sock4);
1018 } 1026 }
1019 1027
1020#if IS_ENABLED(CONFIG_IPV6) 1028#if IS_ENABLED(CONFIG_IPV6)
1021 if (ipv6) { 1029 if (__vxlan_sock_release_prep(sock6)) {
1022 udp_tunnel_sock_release(vxlan->vn6_sock->sock); 1030 udp_tunnel_sock_release(sock6->sock);
1023 kfree(vxlan->vn6_sock); 1031 kfree(sock6);
1024 } 1032 }
1025#endif 1033#endif
1026} 1034}
@@ -1036,18 +1044,21 @@ static int vxlan_igmp_join(struct vxlan_dev *vxlan)
1036 int ret = -EINVAL; 1044 int ret = -EINVAL;
1037 1045
1038 if (ip->sa.sa_family == AF_INET) { 1046 if (ip->sa.sa_family == AF_INET) {
1047 struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
1039 struct ip_mreqn mreq = { 1048 struct ip_mreqn mreq = {
1040 .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr, 1049 .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr,
1041 .imr_ifindex = ifindex, 1050 .imr_ifindex = ifindex,
1042 }; 1051 };
1043 1052
1044 sk = vxlan->vn4_sock->sock->sk; 1053 sk = sock4->sock->sk;
1045 lock_sock(sk); 1054 lock_sock(sk);
1046 ret = ip_mc_join_group(sk, &mreq); 1055 ret = ip_mc_join_group(sk, &mreq);
1047 release_sock(sk); 1056 release_sock(sk);
1048#if IS_ENABLED(CONFIG_IPV6) 1057#if IS_ENABLED(CONFIG_IPV6)
1049 } else { 1058 } else {
1050 sk = vxlan->vn6_sock->sock->sk; 1059 struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
1060
1061 sk = sock6->sock->sk;
1051 lock_sock(sk); 1062 lock_sock(sk);
1052 ret = ipv6_stub->ipv6_sock_mc_join(sk, ifindex, 1063 ret = ipv6_stub->ipv6_sock_mc_join(sk, ifindex,
1053 &ip->sin6.sin6_addr); 1064 &ip->sin6.sin6_addr);
@@ -1067,18 +1078,21 @@ static int vxlan_igmp_leave(struct vxlan_dev *vxlan)
1067 int ret = -EINVAL; 1078 int ret = -EINVAL;
1068 1079
1069 if (ip->sa.sa_family == AF_INET) { 1080 if (ip->sa.sa_family == AF_INET) {
1081 struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
1070 struct ip_mreqn mreq = { 1082 struct ip_mreqn mreq = {
1071 .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr, 1083 .imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr,
1072 .imr_ifindex = ifindex, 1084 .imr_ifindex = ifindex,
1073 }; 1085 };
1074 1086
1075 sk = vxlan->vn4_sock->sock->sk; 1087 sk = sock4->sock->sk;
1076 lock_sock(sk); 1088 lock_sock(sk);
1077 ret = ip_mc_leave_group(sk, &mreq); 1089 ret = ip_mc_leave_group(sk, &mreq);
1078 release_sock(sk); 1090 release_sock(sk);
1079#if IS_ENABLED(CONFIG_IPV6) 1091#if IS_ENABLED(CONFIG_IPV6)
1080 } else { 1092 } else {
1081 sk = vxlan->vn6_sock->sock->sk; 1093 struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
1094
1095 sk = sock6->sock->sk;
1082 lock_sock(sk); 1096 lock_sock(sk);
1083 ret = ipv6_stub->ipv6_sock_mc_drop(sk, ifindex, 1097 ret = ipv6_stub->ipv6_sock_mc_drop(sk, ifindex,
1084 &ip->sin6.sin6_addr); 1098 &ip->sin6.sin6_addr);
@@ -1828,11 +1842,15 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
1828 struct dst_cache *dst_cache, 1842 struct dst_cache *dst_cache,
1829 const struct ip_tunnel_info *info) 1843 const struct ip_tunnel_info *info)
1830{ 1844{
1845 struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
1831 bool use_cache = ip_tunnel_dst_cache_usable(skb, info); 1846 bool use_cache = ip_tunnel_dst_cache_usable(skb, info);
1832 struct dst_entry *ndst; 1847 struct dst_entry *ndst;
1833 struct flowi6 fl6; 1848 struct flowi6 fl6;
1834 int err; 1849 int err;
1835 1850
1851 if (!sock6)
1852 return ERR_PTR(-EIO);
1853
1836 if (tos && !info) 1854 if (tos && !info)
1837 use_cache = false; 1855 use_cache = false;
1838 if (use_cache) { 1856 if (use_cache) {
@@ -1850,7 +1868,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
1850 fl6.flowi6_proto = IPPROTO_UDP; 1868 fl6.flowi6_proto = IPPROTO_UDP;
1851 1869
1852 err = ipv6_stub->ipv6_dst_lookup(vxlan->net, 1870 err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
1853 vxlan->vn6_sock->sock->sk, 1871 sock6->sock->sk,
1854 &ndst, &fl6); 1872 &ndst, &fl6);
1855 if (err < 0) 1873 if (err < 0)
1856 return ERR_PTR(err); 1874 return ERR_PTR(err);
@@ -1995,9 +2013,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
1995 } 2013 }
1996 2014
1997 if (dst->sa.sa_family == AF_INET) { 2015 if (dst->sa.sa_family == AF_INET) {
1998 if (!vxlan->vn4_sock) 2016 struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
2017
2018 if (!sock4)
1999 goto drop; 2019 goto drop;
2000 sk = vxlan->vn4_sock->sock->sk; 2020 sk = sock4->sock->sk;
2001 2021
2002 rt = vxlan_get_route(vxlan, skb, 2022 rt = vxlan_get_route(vxlan, skb,
2003 rdst ? rdst->remote_ifindex : 0, tos, 2023 rdst ? rdst->remote_ifindex : 0, tos,
@@ -2050,12 +2070,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
2050 src_port, dst_port, xnet, !udp_sum); 2070 src_port, dst_port, xnet, !udp_sum);
2051#if IS_ENABLED(CONFIG_IPV6) 2071#if IS_ENABLED(CONFIG_IPV6)
2052 } else { 2072 } else {
2073 struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
2053 struct dst_entry *ndst; 2074 struct dst_entry *ndst;
2054 u32 rt6i_flags; 2075 u32 rt6i_flags;
2055 2076
2056 if (!vxlan->vn6_sock) 2077 if (!sock6)
2057 goto drop; 2078 goto drop;
2058 sk = vxlan->vn6_sock->sock->sk; 2079 sk = sock6->sock->sk;
2059 2080
2060 ndst = vxlan6_get_route(vxlan, skb, 2081 ndst = vxlan6_get_route(vxlan, skb,
2061 rdst ? rdst->remote_ifindex : 0, tos, 2082 rdst ? rdst->remote_ifindex : 0, tos,
@@ -2415,9 +2436,10 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
2415 dport = info->key.tp_dst ? : vxlan->cfg.dst_port; 2436 dport = info->key.tp_dst ? : vxlan->cfg.dst_port;
2416 2437
2417 if (ip_tunnel_info_af(info) == AF_INET) { 2438 if (ip_tunnel_info_af(info) == AF_INET) {
2439 struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
2418 struct rtable *rt; 2440 struct rtable *rt;
2419 2441
2420 if (!vxlan->vn4_sock) 2442 if (!sock4)
2421 return -EINVAL; 2443 return -EINVAL;
2422 rt = vxlan_get_route(vxlan, skb, 0, info->key.tos, 2444 rt = vxlan_get_route(vxlan, skb, 0, info->key.tos,
2423 info->key.u.ipv4.dst, 2445 info->key.u.ipv4.dst,
@@ -2429,8 +2451,6 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
2429#if IS_ENABLED(CONFIG_IPV6) 2451#if IS_ENABLED(CONFIG_IPV6)
2430 struct dst_entry *ndst; 2452 struct dst_entry *ndst;
2431 2453
2432 if (!vxlan->vn6_sock)
2433 return -EINVAL;
2434 ndst = vxlan6_get_route(vxlan, skb, 0, info->key.tos, 2454 ndst = vxlan6_get_route(vxlan, skb, 0, info->key.tos,
2435 info->key.label, &info->key.u.ipv6.dst, 2455 info->key.label, &info->key.u.ipv6.dst,
2436 &info->key.u.ipv6.src, NULL, info); 2456 &info->key.u.ipv6.src, NULL, info);
@@ -2740,10 +2760,10 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6)
2740 return PTR_ERR(vs); 2760 return PTR_ERR(vs);
2741#if IS_ENABLED(CONFIG_IPV6) 2761#if IS_ENABLED(CONFIG_IPV6)
2742 if (ipv6) 2762 if (ipv6)
2743 vxlan->vn6_sock = vs; 2763 rcu_assign_pointer(vxlan->vn6_sock, vs);
2744 else 2764 else
2745#endif 2765#endif
2746 vxlan->vn4_sock = vs; 2766 rcu_assign_pointer(vxlan->vn4_sock, vs);
2747 vxlan_vs_add_dev(vs, vxlan); 2767 vxlan_vs_add_dev(vs, vxlan);
2748 return 0; 2768 return 0;
2749} 2769}
@@ -2754,9 +2774,9 @@ static int vxlan_sock_add(struct vxlan_dev *vxlan)
2754 bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA; 2774 bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA;
2755 int ret = 0; 2775 int ret = 0;
2756 2776
2757 vxlan->vn4_sock = NULL; 2777 RCU_INIT_POINTER(vxlan->vn4_sock, NULL);
2758#if IS_ENABLED(CONFIG_IPV6) 2778#if IS_ENABLED(CONFIG_IPV6)
2759 vxlan->vn6_sock = NULL; 2779 RCU_INIT_POINTER(vxlan->vn6_sock, NULL);
2760 if (ipv6 || metadata) 2780 if (ipv6 || metadata)
2761 ret = __vxlan_sock_add(vxlan, true); 2781 ret = __vxlan_sock_add(vxlan, true);
2762#endif 2782#endif
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index 0255613a54a4..308adc4154f4 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -225,9 +225,9 @@ struct vxlan_config {
225struct vxlan_dev { 225struct vxlan_dev {
226 struct hlist_node hlist; /* vni hash table */ 226 struct hlist_node hlist; /* vni hash table */
227 struct list_head next; /* vxlan's per namespace list */ 227 struct list_head next; /* vxlan's per namespace list */
228 struct vxlan_sock *vn4_sock; /* listening socket for IPv4 */ 228 struct vxlan_sock __rcu *vn4_sock; /* listening socket for IPv4 */
229#if IS_ENABLED(CONFIG_IPV6) 229#if IS_ENABLED(CONFIG_IPV6)
230 struct vxlan_sock *vn6_sock; /* listening socket for IPv6 */ 230 struct vxlan_sock __rcu *vn6_sock; /* listening socket for IPv6 */
231#endif 231#endif
232 struct net_device *dev; 232 struct net_device *dev;
233 struct net *net; /* netns for packet i/o */ 233 struct net *net; /* netns for packet i/o */