From: Timmons C. Player <timmons.pla...@spirent.com>
Committer: Nadav Har'El <n...@scylladb.com>
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 <timmons.pla...@spirent.com>
Message-Id: <1473445171-17551-1-git-send-email-timmons.pla...@spirent.com>

---
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 osv-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to