Fix a locking issue in sctp_accept.

PR:			238520
Reported by:		pho@
MFC after:		1 week
This commit is contained in:
Michael Tuexen 2019-08-06 10:29:19 +00:00
parent 43ecbff2dc
commit cd2de8b735
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=350626

View File

@ -7226,28 +7226,56 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
SCTP_INP_RLOCK(inp);
SCTP_INP_WLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
SCTP_INP_RUNLOCK(inp);
SCTP_INP_WUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
return (EOPNOTSUPP);
}
if (so->so_state & SS_ISDISCONNECTED) {
SCTP_INP_RUNLOCK(inp);
SCTP_INP_WUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED);
return (ECONNABORTED);
}
stcb = LIST_FIRST(&inp->sctp_asoc_list);
if (stcb == NULL) {
SCTP_INP_RUNLOCK(inp);
SCTP_INP_WUNLOCK(inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
return (ECONNRESET);
}
SCTP_TCB_LOCK(stcb);
SCTP_INP_RUNLOCK(inp);
store = stcb->asoc.primary_destination->ro._l_addr;
SCTP_CLEAR_SUBSTATE(stcb, SCTP_STATE_IN_ACCEPT_QUEUE);
SCTP_TCB_UNLOCK(stcb);
/* Wake any delayed sleep action */
if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
if (sowriteable(inp->sctp_socket)) {
sowwakeup_locked(inp->sctp_socket);
} else {
SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
}
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
if (soreadable(inp->sctp_socket)) {
sctp_defered_wakeup_cnt++;
sorwakeup_locked(inp->sctp_socket);
} else {
SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
}
}
}
SCTP_INP_WUNLOCK(inp);
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19);
} else {
SCTP_TCB_UNLOCK(stcb);
}
switch (store.sa.sa_family) {
#ifdef INET
case AF_INET:
@ -7289,40 +7317,6 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
/* TSNH */
break;
}
/* Wake any delayed sleep action */
if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) {
SCTP_INP_WLOCK(inp);
inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE;
if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
SCTP_INP_WUNLOCK(inp);
SOCKBUF_LOCK(&inp->sctp_socket->so_snd);
if (sowriteable(inp->sctp_socket)) {
sowwakeup_locked(inp->sctp_socket);
} else {
SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd);
}
SCTP_INP_WLOCK(inp);
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
SCTP_INP_WUNLOCK(inp);
SOCKBUF_LOCK(&inp->sctp_socket->so_rcv);
if (soreadable(inp->sctp_socket)) {
sctp_defered_wakeup_cnt++;
sorwakeup_locked(inp->sctp_socket);
} else {
SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv);
}
SCTP_INP_WLOCK(inp);
}
SCTP_INP_WUNLOCK(inp);
}
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
SCTP_TCB_LOCK(stcb);
sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_19);
}
return (0);
}