diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-11-09 09:39:44 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-11-09 09:39:44 +0000 |
commit | dfc2e9c36a8c5150afaf19a3b857c4f640cff933 (patch) | |
tree | bed15fa291e145dd6a78babdca3e4845a53005da | |
parent | 3846caa56f2e4a3de3ab9ea686dda34d758f9fd1 (diff) |
Do not call splsoftnet() recursively, this won't work with a lock.
closef() on a socket will call soclose() which call splsoftnet(). So
make sure we release the IPL level first in error paths.
Found by Nils Frohberg while testing another diff.
ok mikeb@, bluhm@
-rw-r--r-- | sys/kern/uipc_syscalls.c | 27 |
1 files changed, 13 insertions, 14 deletions
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c index e064bc9fc7a..3ae8670b0e0 100644 --- a/sys/kern/uipc_syscalls.c +++ b/sys/kern/uipc_syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uipc_syscalls.c,v 1.138 2016/10/23 17:06:40 naddy Exp $ */ +/* $OpenBSD: uipc_syscalls.c,v 1.139 2016/11/09 09:39:43 mpi Exp $ */ /* $NetBSD: uipc_syscalls.c,v 1.19 1996/02/09 19:00:48 christos Exp $ */ /* @@ -276,16 +276,11 @@ doaccept(struct proc *p, int sock, struct sockaddr *name, socklen_t *anamelen, if ((error = getsock(p, sock, &fp)) != 0) return (error); - s = splsoftnet(); headfp = fp; - head = fp->f_data; - - if (isdnssocket((struct socket *)fp->f_data)) { - error = EINVAL; - goto bad; - } redo: - if ((head->so_options & SO_ACCEPTCONN) == 0) { + s = splsoftnet(); + head = headfp->f_data; + if (isdnssocket(head) || (head->so_options & SO_ACCEPTCONN) == 0) { error = EINVAL; goto bad; } @@ -311,7 +306,7 @@ redo: head->so_error = 0; goto bad; } - + /* Figure out whether the new socket should be non-blocking. */ nflag = flags & SOCK_NONBLOCK_INHERIT ? (headfp->f_flag & FNONBLOCK) : (flags & SOCK_NONBLOCK ? FNONBLOCK : 0); @@ -338,6 +333,7 @@ redo: * or another thread or process to accept it. If so, start over. */ if (head->so_qlen == 0) { + splx(s); m_freem(nam); fdplock(fdp); fdremove(fdp, tmpfd); @@ -366,18 +362,21 @@ redo: if (error) { /* if an error occurred, free the file descriptor */ + splx(s); + m_freem(nam); fdplock(fdp); fdremove(fdp, tmpfd); closef(fp, p); fdpunlock(fdp); - } else { - (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&nflag, p); - FILE_SET_MATURE(fp, p); - *retval = tmpfd; + goto out; } + (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&nflag, p); + FILE_SET_MATURE(fp, p); + *retval = tmpfd; m_freem(nam); bad: splx(s); +out: FRELE(headfp, p); return (error); } |