From: Timmons C. Player <[email protected]>
Committer: Nadav Har'El <[email protected]>
Branch: master

uipc_socket.cc: prevent use after free bug in soisdisconnected

Simultaneously closing a socket from both the network and user
space sides can trigger a use after free bug in soisdisconnected.
This change uses the existing socket reference counting mechanism
to prevent the socket from being freed until after this function
has completed.

Signed-off-by: Timmons C. Player <[email protected]>
Message-Id: <[email protected]>

---
diff --git a/bsd/sys/kern/uipc_socket.cc b/bsd/sys/kern/uipc_socket.cc
--- a/bsd/sys/kern/uipc_socket.cc
+++ b/bsd/sys/kern/uipc_socket.cc
@@ -3469,20 +3469,45 @@ void
 soisdisconnected(struct socket *so)
 {

+       bool do_release = false;
        /*
         * Note: This code assumes that SOCK_LOCK(so) and
         * SOCKBUF_LOCK(&so->so_rcv) are the same.
         */
        SOCK_LOCK(so);
+       /*
+        * If user space has already closed the socket, then it's possible
+        * for some of these wakeups to trigger soclose.  We need to prevent
+        * the socket from getting freed in the middle of this function, so
+        * bump the reference count.
+        */
+       soref(so);
        so->so_state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
        so->so_state |= SS_ISDISCONNECTED;
        so->so_rcv.sb_state |= SBS_CANTRCVMORE;
        sorwakeup_locked(so);
        so->so_snd.sb_state |= SBS_CANTSENDMORE;
        sbdrop_locked(so, &so->so_snd, so->so_snd.sb_cc);
        sowwakeup_locked(so);
+       /*
+        * If we have the only reference, then we need to call sorele to
+        * free the socket.  If not, then we just quietly drop the ref
+        * count ourselves to avoid taking the accept lock and possibly
+        * deadlocking.
+        */
+       if (so->so_count == 1) {
+               do_release = true;
+       } else {
+               so->so_count--;
+       }
        SOCK_UNLOCK(so);
        wakeup(&so->so_timeo);
+
+       if (do_release) {
+               ACCEPT_LOCK();
+               SOCK_LOCK(so);
+               sorele(so);
+       }
 }

 /*

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to