diff options
author | Mark Johnston <markj@FreeBSD.org> | 2021-09-11 14:15:21 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2021-09-11 14:15:21 +0000 |
commit | 2d5c48eccd9f29b9df8020bb1c3a8ffda38df37b (patch) | |
tree | 3c34e084f7a5d72ee035df6fe39dae3e9ad3c361 /sys/netinet6 | |
parent | 895545d0e6664ad05fefe63ce46eb670be7e4957 (diff) | |
download | src-2d5c48eccd9f29b9df8020bb1c3a8ffda38df37b.tar.gz src-2d5c48eccd9f29b9df8020bb1c3a8ffda38df37b.zip |
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
MFC after: 1 week
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D31908
Diffstat (limited to 'sys/netinet6')
-rw-r--r-- | sys/netinet6/sctp6_usrreq.c | 7 |
1 files changed, 1 insertions, 6 deletions
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index fcbb566b53d3..516107caf408 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -945,7 +945,7 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) return (EALREADY); } /* We are GOOD to go */ - stcb = sctp_aloc_assoc(inp, addr, &error, 0, 0, vrf_id, + stcb = sctp_aloc_assoc_connected(inp, addr, &error, 0, 0, vrf_id, inp->sctp_ep.pre_open_stream_count, inp->sctp_ep.port, p, SCTP_INITIALIZE_AUTH_PARAMS); @@ -954,11 +954,6 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p) /* Gak! no memory */ return (error); } - if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { - stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; - /* Set the connected flag so we can queue data */ - soisconnecting(so); - } SCTP_SET_STATE(stcb, SCTP_STATE_COOKIE_WAIT); (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); NET_EPOCH_ENTER(et); |