Fix a locking issue in sctp_accept.
PR: 238520 Reported by: pho@ MFC after: 1 week
This commit is contained in:
parent
43ecbff2dc
commit
cd2de8b735
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=350626
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user