aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>2015-03-18 13:50:42 -0400
committerDavid S. Miller <davem@davemloft.net>2015-03-18 22:05:09 -0400
commitbaf606d9c9b12517e47e0d1370e8aa9f7323f210 (patch)
tree77bcd9602f772e50f509f8f28e0156aa7acdbf4c
parentfdf9ef8999c0758bf622899e049f2be45ab1f4da (diff)
ipv4,ipv6: grab rtnl before locking the socket
There are some setsockopt operations in ipv4 and ipv6 that are grabbing rtnl after having grabbed the socket lock. Yet this makes it impossible to do operations that have to lock the socket when already within a rtnl protected scope, like ndo dev_open and dev_stop. We normally take coarse grained locks first but setsockopt inverted that. So this patch invert the lock logic for these operations and makes setsockopt grab rtnl if it will be needed prior to grabbing socket lock. Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/ip_sockglue.c31
-rw-r--r--net/ipv6/ipv6_sockglue.c35
2 files changed, 52 insertions, 14 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 5cd99271d3a6..5171709199f4 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -536,12 +536,25 @@ out:
536 * Socket option code for IP. This is the end of the line after any 536 * Socket option code for IP. This is the end of the line after any
537 * TCP,UDP etc options on an IP socket. 537 * TCP,UDP etc options on an IP socket.
538 */ 538 */
539static bool setsockopt_needs_rtnl(int optname)
540{
541 switch (optname) {
542 case IP_ADD_MEMBERSHIP:
543 case IP_ADD_SOURCE_MEMBERSHIP:
544 case IP_DROP_MEMBERSHIP:
545 case MCAST_JOIN_GROUP:
546 case MCAST_LEAVE_GROUP:
547 return true;
548 }
549 return false;
550}
539 551
540static int do_ip_setsockopt(struct sock *sk, int level, 552static int do_ip_setsockopt(struct sock *sk, int level,
541 int optname, char __user *optval, unsigned int optlen) 553 int optname, char __user *optval, unsigned int optlen)
542{ 554{
543 struct inet_sock *inet = inet_sk(sk); 555 struct inet_sock *inet = inet_sk(sk);
544 int val = 0, err; 556 int val = 0, err;
557 bool needs_rtnl = setsockopt_needs_rtnl(optname);
545 558
546 switch (optname) { 559 switch (optname) {
547 case IP_PKTINFO: 560 case IP_PKTINFO:
@@ -584,6 +597,8 @@ static int do_ip_setsockopt(struct sock *sk, int level,
584 return ip_mroute_setsockopt(sk, optname, optval, optlen); 597 return ip_mroute_setsockopt(sk, optname, optval, optlen);
585 598
586 err = 0; 599 err = 0;
600 if (needs_rtnl)
601 rtnl_lock();
587 lock_sock(sk); 602 lock_sock(sk);
588 603
589 switch (optname) { 604 switch (optname) {
@@ -846,9 +861,9 @@ static int do_ip_setsockopt(struct sock *sk, int level,
846 } 861 }
847 862
848 if (optname == IP_ADD_MEMBERSHIP) 863 if (optname == IP_ADD_MEMBERSHIP)
849 err = ip_mc_join_group(sk, &mreq); 864 err = __ip_mc_join_group(sk, &mreq);
850 else 865 else
851 err = ip_mc_leave_group(sk, &mreq); 866 err = __ip_mc_leave_group(sk, &mreq);
852 break; 867 break;
853 } 868 }
854 case IP_MSFILTER: 869 case IP_MSFILTER:
@@ -913,7 +928,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
913 mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr; 928 mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
914 mreq.imr_address.s_addr = mreqs.imr_interface; 929 mreq.imr_address.s_addr = mreqs.imr_interface;
915 mreq.imr_ifindex = 0; 930 mreq.imr_ifindex = 0;
916 err = ip_mc_join_group(sk, &mreq); 931 err = __ip_mc_join_group(sk, &mreq);
917 if (err && err != -EADDRINUSE) 932 if (err && err != -EADDRINUSE)
918 break; 933 break;
919 omode = MCAST_INCLUDE; 934 omode = MCAST_INCLUDE;
@@ -945,9 +960,9 @@ static int do_ip_setsockopt(struct sock *sk, int level,
945 mreq.imr_ifindex = greq.gr_interface; 960 mreq.imr_ifindex = greq.gr_interface;
946 961
947 if (optname == MCAST_JOIN_GROUP) 962 if (optname == MCAST_JOIN_GROUP)
948 err = ip_mc_join_group(sk, &mreq); 963 err = __ip_mc_join_group(sk, &mreq);
949 else 964 else
950 err = ip_mc_leave_group(sk, &mreq); 965 err = __ip_mc_leave_group(sk, &mreq);
951 break; 966 break;
952 } 967 }
953 case MCAST_JOIN_SOURCE_GROUP: 968 case MCAST_JOIN_SOURCE_GROUP:
@@ -990,7 +1005,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
990 mreq.imr_multiaddr = psin->sin_addr; 1005 mreq.imr_multiaddr = psin->sin_addr;
991 mreq.imr_address.s_addr = 0; 1006 mreq.imr_address.s_addr = 0;
992 mreq.imr_ifindex = greqs.gsr_interface; 1007 mreq.imr_ifindex = greqs.gsr_interface;
993 err = ip_mc_join_group(sk, &mreq); 1008 err = __ip_mc_join_group(sk, &mreq);
994 if (err && err != -EADDRINUSE) 1009 if (err && err != -EADDRINUSE)
995 break; 1010 break;
996 greqs.gsr_interface = mreq.imr_ifindex; 1011 greqs.gsr_interface = mreq.imr_ifindex;
@@ -1118,10 +1133,14 @@ mc_msf_out:
1118 break; 1133 break;
1119 } 1134 }
1120 release_sock(sk); 1135 release_sock(sk);
1136 if (needs_rtnl)
1137 rtnl_unlock();
1121 return err; 1138 return err;
1122 1139
1123e_inval: 1140e_inval:
1124 release_sock(sk); 1141 release_sock(sk);
1142 if (needs_rtnl)
1143 rtnl_unlock();
1125 return -EINVAL; 1144 return -EINVAL;
1126} 1145}
1127 1146
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 8d766d9100cb..f2b731df8d77 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -117,6 +117,18 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
117 return opt; 117 return opt;
118} 118}
119 119
120static bool setsockopt_needs_rtnl(int optname)
121{
122 switch (optname) {
123 case IPV6_ADD_MEMBERSHIP:
124 case IPV6_DROP_MEMBERSHIP:
125 case MCAST_JOIN_GROUP:
126 case MCAST_LEAVE_GROUP:
127 return true;
128 }
129 return false;
130}
131
120static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, 132static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
121 char __user *optval, unsigned int optlen) 133 char __user *optval, unsigned int optlen)
122{ 134{
@@ -124,6 +136,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
124 struct net *net = sock_net(sk); 136 struct net *net = sock_net(sk);
125 int val, valbool; 137 int val, valbool;
126 int retv = -ENOPROTOOPT; 138 int retv = -ENOPROTOOPT;
139 bool needs_rtnl = setsockopt_needs_rtnl(optname);
127 140
128 if (optval == NULL) 141 if (optval == NULL)
129 val = 0; 142 val = 0;
@@ -140,6 +153,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
140 if (ip6_mroute_opt(optname)) 153 if (ip6_mroute_opt(optname))
141 return ip6_mroute_setsockopt(sk, optname, optval, optlen); 154 return ip6_mroute_setsockopt(sk, optname, optval, optlen);
142 155
156 if (needs_rtnl)
157 rtnl_lock();
143 lock_sock(sk); 158 lock_sock(sk);
144 159
145 switch (optname) { 160 switch (optname) {
@@ -582,9 +597,9 @@ done:
582 break; 597 break;
583 598
584 if (optname == IPV6_ADD_MEMBERSHIP) 599 if (optname == IPV6_ADD_MEMBERSHIP)
585 retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); 600 retv = __ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
586 else 601 else
587 retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); 602 retv = __ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr);
588 break; 603 break;
589 } 604 }
590 case IPV6_JOIN_ANYCAST: 605 case IPV6_JOIN_ANYCAST:
@@ -623,11 +638,11 @@ done:
623 } 638 }
624 psin6 = (struct sockaddr_in6 *)&greq.gr_group; 639 psin6 = (struct sockaddr_in6 *)&greq.gr_group;
625 if (optname == MCAST_JOIN_GROUP) 640 if (optname == MCAST_JOIN_GROUP)
626 retv = ipv6_sock_mc_join(sk, greq.gr_interface, 641 retv = __ipv6_sock_mc_join(sk, greq.gr_interface,
627 &psin6->sin6_addr); 642 &psin6->sin6_addr);
628 else 643 else
629 retv = ipv6_sock_mc_drop(sk, greq.gr_interface, 644 retv = __ipv6_sock_mc_drop(sk, greq.gr_interface,
630 &psin6->sin6_addr); 645 &psin6->sin6_addr);
631 break; 646 break;
632 } 647 }
633 case MCAST_JOIN_SOURCE_GROUP: 648 case MCAST_JOIN_SOURCE_GROUP:
@@ -659,8 +674,8 @@ done:
659 struct sockaddr_in6 *psin6; 674 struct sockaddr_in6 *psin6;
660 675
661 psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; 676 psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
662 retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, 677 retv = __ipv6_sock_mc_join(sk, greqs.gsr_interface,
663 &psin6->sin6_addr); 678 &psin6->sin6_addr);
664 /* prior join w/ different source is ok */ 679 /* prior join w/ different source is ok */
665 if (retv && retv != -EADDRINUSE) 680 if (retv && retv != -EADDRINUSE)
666 break; 681 break;
@@ -837,11 +852,15 @@ pref_skip_coa:
837 } 852 }
838 853
839 release_sock(sk); 854 release_sock(sk);
855 if (needs_rtnl)
856 rtnl_unlock();
840 857
841 return retv; 858 return retv;
842 859
843e_inval: 860e_inval:
844 release_sock(sk); 861 release_sock(sk);
862 if (needs_rtnl)
863 rtnl_unlock();
845 return -EINVAL; 864 return -EINVAL;
846} 865}
847 866