CVSROOT:        /cvs
Module name:    src
Changes by:     be...@cvs.openbsd.org   2021/10/30 12:11:56

Modified files:
        sys/kern       : Tag: OPENBSD_7_0 uipc_usrreq.c 

Log message:
The kernel could leak memory when closing unix sockets.

Commit in -current:
m...@cvs.openbsd.org     2021/10/30 10:24:18

Modified files:
sys/kern       : uipc_usrreq.c

Log message:
Fix the UNIX domain sockets leak in soclose().

Each listening socket has two queues, the `so_q0' where partial connected
sockets linked and the `so_q' where connected but not yet accept(2)ed
sockets linked. Such sockets has no file descriptor allocated, so they
have no access from the userland. When the socket linked to `so_q0' or
`so_q' it has it's `so_head' pointed to the listening socket. The userland
receive sockets from `so_q' by accept(2) which allocates the file
descriptor to the socket.

When userland close(2) listening socket, soclose() should release the
sockets linked to `so_q0' and `so_q' because it's the only place where
they are referenced. It removes the socket from the queue by soqremque().
Since socket is not in the queue it's `so_head' is NULL. Then the socket
passed to soabort() which should destroy it by (*pr_usrreq)() call with
'PRU_ABORT' request.

In UNIX domain sockets layer the unp_drop() only disconnects passed socket
and doesn't destroy it because it's `so_head' is NULL. This socket has the
only access by the UNIX domain sockets garbage collector which leaves it
alive, so the socket is permanently leaked.

This leak was introduced in the revision 1.26 of sys/uipc_socket.c when
soqremque() was placed before soabort(). To fix this the unp_drop() was
replaced by unp_detach() and sofree() in the 'PRU_ABORT' path. unp_drop()
only sets the error and disconnects passed socket. We don't expose this
error and unp_detach() also disconnects the socket before destroy it's
protocol control block. sofree() destroys the rest.

The socket passed to soabort() has no vnode(9) associated, so unp_detach()
don't release `unp_lock'. Also this socket never had associated file
descriptor so it already has 'SS_NOFDREF' flag set.

This diff was also applied to 6.9 and 7.0 branches as errata.

This is patches/7.0/common/003_uipc.patch.sig

Reply via email to