diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-02-15 04:26:28 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-02-15 04:26:28 +0000 |
commit | b861cd7b54c3de28426491f9752a022262f3dc88 (patch) | |
tree | 1d33033d095b99ded617a883d8dd5c8770958218 /sys/kern | |
parent | 9db6da3ecdf09727884dc8eb4e22146c7707b98b (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.c | 9 | ||||
-rw-r--r-- | sys/kern/kern_descrip.c | 34 | ||||
-rw-r--r-- | sys/kern/kern_event.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 15 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 11 |
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); } |