udp: Save original protocol processing port for later synchronizing.
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Fri, 23 Oct 2015 13:37:46 +0000 (21:37 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 29 Oct 2015 01:26:02 +0000 (09:26 +0800)
Unlike TCP, user could send data w/ address to a UDP socket that
connect(2) is being called (those data messages will be on the
original protocol processing port and forwarded to the new protocol
processing port later), and then close the UDP socket (the detach
message could be sent to the new protocol processing port before
the inflight data messages).  The inflight data messages will cause
later panic, since the socket/inp has been destroyed by the detach
message.  I will have to say this probably will never happen for any
real world applications.

We fix this by recording the original message port, and synchronize
inflight data messages on it upon detaching.  If the connect(2) moves
between protocol processing ports more than once, we will go though
all UDP processing netisrs to synchronize all possible inflight data
messages.

sys/netinet/udp_usrreq.c
sys/sys/socketvar.h

index fbb30d4..1a08491 100644 (file)
@@ -1484,6 +1484,25 @@ udp_connect(netmsg_t msg)
                        udp_remwildcardhash(inp);
                }
 
+               if (so->so_orig_port == NULL) {
+                       /*
+                        * First time change protocol processing port.
+                        * Save the current port for synchronization upon
+                        * udp_detach.
+                        */
+                       so->so_orig_port = &curthread->td_msgport;
+               } else {
+                       /*
+                        * We have changed protocol processing port more
+                        * than once.  We could not do direct detach
+                        * anymore, because we lose the track of the
+                        * original protocol processing ports to perform
+                        * synchronization upon udp_detach.  This should
+                        * be rare though.
+                        */
+                       inp->inp_flags &= ~INP_DIRECT_DETACH;
+               }
+
                /*
                 * We are moving the protocol processing port the socket
                 * is on, we have to unlink here and re-link on the
@@ -1631,6 +1650,21 @@ udp_detach_oncpu_dispatch(netmsg_t msg)
        }
 }
 
+static void
+udp_detach_syncorig_dispatch(netmsg_t msg)
+{
+       struct netmsg_base *clomsg = &msg->base;
+       struct socket *so = clomsg->nm_so;
+
+       /*
+        * Original protocol processing port is synchronized;
+        * destroy this inpcb in its owner netisr.
+        */
+       netmsg_init(clomsg, so, &netisr_apanic_rport, 0,
+           udp_detach_final_dispatch);
+       lwkt_sendmsg(so->so_port, &clomsg->lmsg);
+}
+
 static void
 udp_detach(netmsg_t msg)
 {
@@ -1669,7 +1703,22 @@ udp_detach(netmsg_t msg)
                KASSERT((inp->inp_flags & INP_WILDCARD) == 0,
                    ("in the wildcardhash"));
                KASSERT(inp->inp_moptions == NULL, ("has mcast options"));
-               udp_detach2(so);
+               if (so->so_orig_port == NULL) {
+                       udp_detach2(so);
+               } else {
+                       /*
+                        * Protocol processing port changed once, so
+                        * we need to make sure that there are nothing
+                        * left on the original protocol processing
+                        * port before we destroy this socket and inpcb.
+                        * This is more lightweight than going through
+                        * all UDP processing netisrs.
+                        */
+                       clomsg = &so->so_clomsg;
+                       netmsg_init(clomsg, so, &netisr_apanic_rport,
+                           MSGF_IGNSOPORT, udp_detach_syncorig_dispatch);
+                       lwkt_sendmsg(so->so_orig_port, &clomsg->lmsg);
+               }
                return;
        }
 
index 204c979..e4fe6b3 100644 (file)
@@ -166,6 +166,8 @@ struct socket {
 
        struct spinlock so_rcvd_spin;
        struct netmsg_pru_rcvd so_rcvd_msg;
+
+       lwkt_port_t so_orig_port;
 };
 
 #endif