diff options
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r-- | sys/kern/kern_descrip.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 4e46b056e04..cd6385c1066 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_descrip.c,v 1.96 2012/05/21 16:41:03 matthew Exp $ */ +/* $OpenBSD: kern_descrip.c,v 1.97 2012/07/08 10:55:10 guenther Exp $ */ /* $NetBSD: kern_descrip.c,v 1.42 1996/03/30 22:24:38 christos Exp $ */ /* @@ -1196,9 +1196,11 @@ filedescopen(dev_t dev, int mode, int type, struct proc *p) * Duplicate the specified descriptor to a free descriptor. */ int -dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode) +dupfdopen(struct proc *p, int indx, struct file *fp, int mode) { + struct filedesc *fdp = p->p_fd; struct file *wfp; + int dfd = p->p_dupfd; fdpassertlocked(fdp); @@ -1206,10 +1208,10 @@ dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode) * Assume that the filename was user-specified; applications do * not tend to open /dev/fd/# when they can just call dup() */ - if ((curproc->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) { - if (curproc->p_descfd == 255) + if ((p->p_p->ps_flags & (PS_SUGIDEXEC | PS_SUGID))) { + if (p->p_descfd == 255) return (EPERM); - if (curproc->p_descfd != curproc->p_dupfd) + if (p->p_descfd != dfd) return (EPERM); } @@ -1232,10 +1234,23 @@ dupfdopen(struct filedesc *fdp, int indx, int dfd, int mode) if (wfp->f_count == LONG_MAX-2) return (EDEADLK); + FREF(wfp); + + /* + * Check whether the larval fd was close behind our back. + * If it was, we act like the open() completed before the + * close(): fake up a closef(), to provide POSIX lock semantics, + * then return success. + */ + if (fdp->fd_ofiles[indx] != fp) { + FREF(wfp); /* yes, again: closef() decrements it twice */ + closef(wfp, p); + return (0); + } + fdp->fd_ofiles[indx] = wfp; fdp->fd_ofileflags[indx] = (fdp->fd_ofileflags[indx] & UF_EXCLOSE) | (fdp->fd_ofileflags[dfd] & ~UF_EXCLOSE); - wfp->f_count++; fd_used(fdp, indx); return (0); } |