summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2012-02-15 04:26:28 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2012-02-15 04:26:28 +0000
commitb861cd7b54c3de28426491f9752a022262f3dc88 (patch)
tree1d33033d095b99ded617a883d8dd5c8770958218 /sys/kern
parent9db6da3ecdf09727884dc8eb4e22146c7707b98b (diff)
Hold struct filedesc's fd_lock when writing to the fd_ofiles, fd_ofileflags,
or fd_{lo,hi}maps members, or when doing a read for a write. Fixes hangs when an rthreaded processes sleeps while copying the fd table for fork() and catches another thread with the lock. ok jsing@ tedu@
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/exec_script.c9
-rw-r--r--sys/kern/kern_descrip.c34
-rw-r--r--sys/kern/kern_event.c4
-rw-r--r--sys/kern/kern_exec.c15
-rw-r--r--sys/kern/sys_generic.c11
5 files changed, 53 insertions, 20 deletions
diff --git a/sys/kern/exec_script.c b/sys/kern/exec_script.c
index dc1cc381b84..a6d730f8ece 100644
--- a/sys/kern/exec_script.c
+++ b/sys/kern/exec_script.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_script.c,v 1.26 2011/07/07 23:45:00 matthew Exp $ */
+/* $OpenBSD: exec_script.c,v 1.27 2012/02/15 04:26:27 guenther Exp $ */
/* $NetBSD: exec_script.c,v 1.13 1996/02/04 02:15:06 christos Exp $ */
/*
@@ -187,7 +187,10 @@ check_shell:
panic("exec_script_makecmds: epp already has a fd");
#endif
- if ((error = falloc(p, &fp, &epp->ep_fd)))
+ fdplock(p->p_fd);
+ error = falloc(p, &fp, &epp->ep_fd);
+ fdpunlock(p->p_fd);
+ if (error)
goto fail;
epp->ep_flags |= EXEC_HASFD;
@@ -298,7 +301,9 @@ fail:
/* kill the opened file descriptor, else close the file */
if (epp->ep_flags & EXEC_HASFD) {
epp->ep_flags &= ~EXEC_HASFD;
+ fdplock(p->p_fd);
(void) fdrelease(p, epp->ep_fd);
+ fdpunlock(p->p_fd);
} else
vn_close(scriptvp, FREAD, p->p_ucred, p);
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index cb4b4143361..519074b6340 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_descrip.c,v 1.88 2011/07/08 21:26:27 matthew Exp $ */
+/* $OpenBSD: kern_descrip.c,v 1.89 2012/02/15 04:26:27 guenther Exp $ */
/* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */
/*
@@ -322,21 +322,19 @@ restart:
}
fdplock(fdp);
if ((error = fdalloc(p, newmin, &i)) != 0) {
+ FRELE(fp);
if (error == ENOSPC) {
fdexpand(p);
- FRELE(fp);
fdpunlock(fdp);
goto restart;
}
- }
- /* finishdup will FRELE for us. */
- if (!error)
+ } else {
+ /* finishdup will FRELE for us. */
error = finishdup(p, fp, fd, i, retval);
- else
- FRELE(fp);
- if (!error && SCARG(uap, cmd) == F_DUPFD_CLOEXEC)
- fdp->fd_ofileflags[i] |= UF_EXCLOSE;
+ if (!error && SCARG(uap, cmd) == F_DUPFD_CLOEXEC)
+ fdp->fd_ofileflags[i] |= UF_EXCLOSE;
+ }
fdpunlock(fdp);
return (error);
@@ -346,10 +344,12 @@ restart:
break;
case F_SETFD:
+ fdplock(fdp);
if ((long)SCARG(uap, arg) & 1)
fdp->fd_ofileflags[fd] |= UF_EXCLOSE;
else
fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE;
+ fdpunlock(fdp);
break;
case F_GETFL:
@@ -523,6 +523,7 @@ finishdup(struct proc *p, struct file *fp, int old, int new, register_t *retval)
struct file *oldfp;
struct filedesc *fdp = p->p_fd;
+ fdpassertlocked(fdp);
if (fp->f_count == LONG_MAX-2) {
FRELE(fp);
return (EDEADLK);
@@ -556,6 +557,7 @@ finishdup(struct proc *p, struct file *fp, int old, int new, register_t *retval)
void
fdremove(struct filedesc *fdp, int fd)
{
+ fdpassertlocked(fdp);
fdp->fd_ofiles[fd] = NULL;
fd_unused(fdp, fd);
}
@@ -566,6 +568,8 @@ fdrelease(struct proc *p, int fd)
struct filedesc *fdp = p->p_fd;
struct file **fpp, *fp;
+ fdpassertlocked(fdp);
+
/*
* Don't fd_getfile here. We want to closef LARVAL files and closef
* can deal with that.
@@ -749,6 +753,8 @@ fdexpand(struct proc *p)
char *newofileflags;
u_int *newhimap, *newlomap;
+ fdpassertlocked(fdp);
+
/*
* No space in current array.
*/
@@ -812,6 +818,7 @@ falloc(struct proc *p, struct file **resultfp, int *resultfd)
struct file *fp, *fq;
int error, i;
+ fdpassertlocked(p->p_fd);
restart:
if ((error = fdalloc(p, 0, &i)) != 0) {
if (error == ENOSPC) {
@@ -908,6 +915,7 @@ fdcopy(struct proc *p)
struct file **fpp;
int i;
+ fdplock(fdp);
newfdp = pool_get(&fdesc_pool, PR_WAITOK);
bcopy(fdp, newfdp, sizeof(struct filedesc));
if (newfdp->fd_cdir)
@@ -915,6 +923,7 @@ fdcopy(struct proc *p)
if (newfdp->fd_rdir)
vref(newfdp->fd_rdir);
newfdp->fd_refcnt = 1;
+ rw_init(&newfdp->fd_lock, "fdlock");
/*
* If the number of open files fits in the internal arrays
@@ -955,10 +964,12 @@ fdcopy(struct proc *p)
bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
bcopy(fdp->fd_himap, newfdp->fd_himap, NDHISLOTS(i) * sizeof(u_int));
bcopy(fdp->fd_lomap, newfdp->fd_lomap, NDLOSLOTS(i) * sizeof(u_int));
+ fdpunlock(fdp);
/*
* kq descriptors cannot be copied.
*/
+ fdplock(newfdp);
if (newfdp->fd_knlistsize != -1) {
fpp = newfdp->fd_ofiles;
for (i = 0; i <= newfdp->fd_lastfile; i++, fpp++)
@@ -983,6 +994,7 @@ fdcopy(struct proc *p)
else
(*fpp)->f_count++;
}
+ fdpunlock(newfdp);
return (newfdp);
}
@@ -1197,6 +1209,8 @@ dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode, int error)
{
struct file *wfp;
+ fdpassertlocked(fdp);
+
/*
* Assume that the filename was user-specified; applications do
* not tend to open /dev/fd/# when they can just call dup()
@@ -1277,9 +1291,11 @@ fdcloseexec(struct proc *p)
struct filedesc *fdp = p->p_fd;
int fd;
+ fdplock(fdp);
for (fd = 0; fd <= fdp->fd_lastfile; fd++)
if (fdp->fd_ofileflags[fd] & UF_EXCLOSE)
(void) fdrelease(p, fd);
+ fdpunlock(fdp);
}
int
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index d43c013d4c2..d247058b9b0 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_event.c,v 1.41 2011/07/02 22:20:08 nicm Exp $ */
+/* $OpenBSD: kern_event.c,v 1.42 2012/02/15 04:26:27 guenther Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -423,7 +423,9 @@ sys_kqueue(struct proc *p, void *v, register_t *retval)
struct file *fp;
int fd, error;
+ fdplock(fdp);
error = falloc(p, &fp, &fd);
+ fdpunlock(fdp);
if (error)
return (error);
fp->f_flag = FREAD | FWRITE;
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index c72d2fcdead..1b1ac0d84d2 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exec.c,v 1.122 2011/12/14 07:32:16 guenther Exp $ */
+/* $OpenBSD: kern_exec.c,v 1.123 2012/02/15 04:26:27 guenther Exp $ */
/* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */
/*-
@@ -529,6 +529,8 @@ sys_execve(struct proc *p, void *v, register_t *retval)
* For set[ug]id processes, a few caveats apply to
* stdin, stdout, and stderr.
*/
+ error = 0;
+ fdplock(p->p_fd);
for (i = 0; i < 3; i++) {
struct file *fp = NULL;
@@ -562,7 +564,7 @@ sys_execve(struct proc *p, void *v, register_t *retval)
int indx;
if ((error = falloc(p, &fp, &indx)) != 0)
- goto exec_abort;
+ break;
#ifdef DIAGNOSTIC
if (indx != i)
panic("sys_execve: falloc indx != i");
@@ -570,13 +572,13 @@ sys_execve(struct proc *p, void *v, register_t *retval)
if ((error = cdevvp(getnulldev(), &vp)) != 0) {
fdremove(p->p_fd, indx);
closef(fp, p);
- goto exec_abort;
+ break;
}
if ((error = VOP_OPEN(vp, flags, p->p_ucred, p)) != 0) {
fdremove(p->p_fd, indx);
closef(fp, p);
vrele(vp);
- goto exec_abort;
+ break;
}
if (flags & FWRITE)
vp->v_writecount++;
@@ -587,6 +589,9 @@ sys_execve(struct proc *p, void *v, register_t *retval)
FILE_SET_MATURE(fp);
}
}
+ fdpunlock(p->p_fd);
+ if (error)
+ goto exec_abort;
} else
atomic_clearbits_int(&pr->ps_flags, PS_SUGID);
p->p_cred->p_svuid = p->p_ucred->cr_uid;
@@ -695,7 +700,9 @@ bad:
/* kill any opened file descriptor, if necessary */
if (pack.ep_flags & EXEC_HASFD) {
pack.ep_flags &= ~EXEC_HASFD;
+ fdplock(p->p_fd);
(void) fdrelease(p, pack.ep_fd);
+ fdpunlock(p->p_fd);
}
if (pack.ep_interp != NULL)
pool_put(&namei_pool, pack.ep_interp);
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 962645dba50..4fbc127dae0 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_generic.c,v 1.73 2011/11/06 12:10:04 guenther Exp $ */
+/* $OpenBSD: sys_generic.c,v 1.74 2012/02/15 04:26:27 guenther Exp $ */
/* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */
/*
@@ -408,10 +408,13 @@ sys_ioctl(struct proc *p, void *v, register_t *retval)
switch (com = SCARG(uap, com)) {
case FIONCLEX:
- fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
- return (0);
case FIOCLEX:
- fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
+ fdplock(fdp);
+ if (com == FIONCLEX)
+ fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE;
+ else
+ fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE;
+ fdpunlock(fdp);
return (0);
}