aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2021-09-11 14:15:21 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2022-02-22 22:47:28 +0000
commitaa16c2fcaf1d5e541fc91a66bbba352ba313429c (patch)
treec91f46d2c1df82b3c82433291496717dfa7de5c7 /sys/netinet/sctp_input.c
parent238e4a1179b0b03bf39bcc4e096f6771d2d82faa (diff)
sctp: Tighten up locking around sctp_aloc_assoc()
All callers of sctp_aloc_assoc() mark the PCB as connected after a successful call (for one-to-one-style sockets). In all cases this is done without the PCB lock, so the PCB's flags can be corrupted. We also do not atomically check whether a one-to-one-style socket is a listening socket, which violates various assumptions in solisten_proto(). We need to hold the PCB lock across all of sctp_aloc_assoc() to fix this. In order to do that without introducing lock order reversals, we have to hold the global info lock as well. So: - Convert sctp_aloc_assoc() so that the inp and info locks are consistently held. It returns with the association lock held, as before. - Fix an apparent bug where we failed to remove an association from a global hash if sctp_add_remote_addr() fails. - sctp_select_a_tag() is called when initializing an association, and it acquires the global info lock. To avoid lock recursion, push locking into its callers. - Introduce sctp_aloc_assoc_connected(), which atomically checks for a listening socket and sets SCTP_PCB_FLAGS_CONNECTED. There is still one edge case in sctp_process_cookie_new() where we do not update PCB/socket state correctly. Reviewed by: tuexen Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D31908 (cherry picked from commit 2d5c48eccd9f29b9df8020bb1c3a8ffda38df37b)
Diffstat (limited to 'sys/netinet/sctp_input.c')
-rw-r--r--sys/netinet/sctp_input.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index b257a62e02f8..84d2a303303d 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -679,7 +679,9 @@ sctp_handle_nat_colliding_state(struct sctp_tcb *stcb)
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
(SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_ECHOED)) {
+ SCTP_INP_INFO_RLOCK();
new_vtag = sctp_select_a_tag(stcb->sctp_ep, stcb->sctp_ep->sctp_lport, stcb->rport, 1);
+ SCTP_INP_INFO_RLOCK();
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
SCTP_INP_INFO_WLOCK();
@@ -2183,6 +2185,8 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
* INIT/INIT-ACK/COOKIE arrived. But of course then it
* should have went to the other code.. not here.. oh well..
* a bit of protection is worth having..
+ *
+ * XXXMJ unlocked
*/
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
soisconnected(stcb->sctp_socket);