Don't take solock() in soreceive() for udp(4) sockets.
authormvs <mvs@openbsd.org>
Mon, 15 Apr 2024 21:31:29 +0000 (21:31 +0000)
committermvs <mvs@openbsd.org>
Mon, 15 Apr 2024 21:31:29 +0000 (21:31 +0000)
commit62ce95a7e5577c30c23ee0e49ec92608a1d9b172
treea6e86a5b97809ff870f1b89a146ed54f16e9bd5b
parent667565e9bc8e470581eb340e70806f7beb34dd45
Don't take solock() in soreceive() for udp(4) sockets.

These sockets are not connection oriented, they don't call pru_rcvd(),
but they have splicing ability and they set `so_error'.

Splicing ability is the most problem. However, we can hold `sb_mtx'
around `ssp_socket' modifications together with solock(). So the
`sb_mtx' is pretty enough to isspiced() check in soreceive(). The
unlocked `so_sp' dereference is fine, because we set it only once for
the whole socket life-time and we do this before `ssp_socket'
assignment.

We also need to take sblock() before splice sockets, so the sosplice()
and soreceive() are both serialized. Since `sb_mtx' required to unsplice
sockets too, it also serializes somove() with soreceive() regardless on
somove() caller.

The sosplice() was reworked to accept standalone sblock() for udp(4)
sockets.

soreceive() performs unlocked `so_error' check and modification.
Previously, we have no ability to predict which concurrent soreceive()
or sosend() thread will fail and clean `so_error'. With this unlocked
access we could have sosend() and soreceive() threads which fails
together.

`so_error' stored to local `error2' variable because `so_error' could be
overwritten by concurrent sosend() thread.

Tested and ok bluhm
sys/kern/uipc_socket.c