summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2016-11-09 09:39:44 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2016-11-09 09:39:44 +0000
commitdfc2e9c36a8c5150afaf19a3b857c4f640cff933 (patch)
treebed15fa291e145dd6a78babdca3e4845a53005da
parent3846caa56f2e4a3de3ab9ea686dda34d758f9fd1 (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.c27
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);
}