summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2007-05-04 14:23:29 +0000
committerkib <kib@FreeBSD.org>2007-05-04 14:23:29 +0000
commitcef02547601ab1f28f733c9db913c8d052984fb4 (patch)
tree9ccabfdbf97166caf9e4f602b193dc0547a6e364 /sys/kern
parentd4d6cc464d4dbff2d649d196d9119a99c07393e5 (diff)
downloadFreeBSD-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.c10
-rw-r--r--sys/kern/vfs_syscalls.c12
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
OpenPOWER on IntegriCloud