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.