diff options
author | kib <kib@FreeBSD.org> | 2007-05-04 14:23:29 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2007-05-04 14:23:29 +0000 |
commit | cef02547601ab1f28f733c9db913c8d052984fb4 (patch) | |
tree | 9ccabfdbf97166caf9e4f602b193dc0547a6e364 /sys/kern | |
parent | d4d6cc464d4dbff2d649d196d9119a99c07393e5 (diff) | |
download | FreeBSD-src-cef02547601ab1f28f733c9db913c8d052984fb4.zip FreeBSD-src-cef02547601ab1f28f733c9db913c8d052984fb4.tar.gz |
Mark the filedescriptor table entries with VOP_OPEN being performed for them
as UF_OPENING. Disable closing of that entries. This should fix the crashes
caused by devfs_open() (and fifo_open()) dereferencing struct file * by
index, while the filedescriptor is closed by parallel thread.
Idea by: tegge
Reviewed by: tegge (previous version of patch)
Tested by: Peter Holm
Approved by: re (kensmith)
MFC after: 3 weeks
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_descrip.c | 10 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 12 |
2 files changed, 19 insertions, 3 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 963b286..bc9cad8 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -666,7 +666,9 @@ do_dup(struct thread *td, enum dup_type type, int old, int new, * bad file descriptor. Userland should do its own locking to * avoid this case. */ - if (fdp->fd_ofiles[old] != fp) { + if (fdp->fd_ofiles[old] != fp || + (fdp->fd_ofileflags[old] & UF_OPENING) != 0 || + (fdp->fd_ofileflags[new] & UF_OPENING) != 0) { /* we've allocated a descriptor which we won't use */ if (fdp->fd_ofiles[new] == NULL) fdunused(fdp, new); @@ -990,7 +992,8 @@ kern_close(td, fd) FILEDESC_XLOCK(fdp); if ((unsigned)fd >= fdp->fd_nfiles || - (fp = fdp->fd_ofiles[fd]) == NULL) { + (fp = fdp->fd_ofiles[fd]) == NULL || + (fdp->fd_ofileflags[fd] & UF_OPENING) != 0) { FILEDESC_XUNLOCK(fdp); return (EBADF); } @@ -1504,7 +1507,8 @@ fdcopy(struct filedesc *fdp) newfdp->fd_freefile = -1; for (i = 0; i <= fdp->fd_lastfile; ++i) { if (fdisused(fdp, i) && - fdp->fd_ofiles[i]->f_type != DTYPE_KQUEUE) { + fdp->fd_ofiles[i]->f_type != DTYPE_KQUEUE && + (fdp->fd_ofileflags[i] & UF_OPENING) == 0) { newfdp->fd_ofiles[i] = fdp->fd_ofiles[i]; newfdp->fd_ofileflags[i] = fdp->fd_ofileflags[i]; fhold(newfdp->fd_ofiles[i]); diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 72a3f4e..fe9d99e 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -984,7 +984,19 @@ kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags, cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td); td->td_dupfd = -1; /* XXX check for fdopen */ + FILEDESC_XLOCK(fdp); + if (fp != fdp->fd_ofiles[indx]) { + FILEDESC_XUNLOCK(fdp); + fdrop(fp, td); + td->td_retval[0] = indx; + return (0); + } + fdp->fd_ofileflags[indx] |= UF_OPENING; + FILEDESC_XUNLOCK(fdp); error = vn_open(&nd, &flags, cmode, indx); + FILEDESC_XLOCK(fdp); + fdp->fd_ofileflags[indx] &= ~UF_OPENING; + FILEDESC_XUNLOCK(fdp); if (error) { /* * If the vn_open replaced the method vector, something |