summaryrefslogtreecommitdiff
path: root/kernel/fork.c
diff options
context:
space:
mode:
authorGregory Kurz <gkurz@meiosys.com>2004-10-18 08:55:24 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-10-18 08:55:24 -0700
commit2dbc57298d84fe37d855c8bfa3b280dfd47ded4b (patch)
treea3bb3e0fc30cd6e7e20e1f8c9b9ca6bea85b1a70 /kernel/fork.c
parent0105467f1b4a7545f2a2c38a82e0b283bb3bc9b1 (diff)
[PATCH] fork() bug invalidates file descriptors
Take a process P1 that spawns a thread T (aka. a clone with CLONE_FILES). If P1 forks another process P2 (aka. not a clone) while T is blocked in a open() that should return file descriptor FD, then FD will be unusable in P2. This leads to strange behaviors in the context of P2: close(FD) returns EBADF, while dup2(a_valid_fd, FD) returns EBUSY and of course FD is never returned again by any syscall... testcase: #include <errno.h> #include <fcntl.h> #include <sched.h> #include <signal.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <asm/page.h> #define FIFO "/tmp/bug_fifo" #define FD 0 /* * This program is meant to show that calling fork() while a clone spawned * with CLONE_FILES is blocked in open() makes a fd number unusable in the * child. * * * Parent Clone Child * | * clone(CLONE_FILES)-
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index 6fd57c2d22cc..bd33d8a507d7 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -762,8 +762,17 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
for (i = open_files; i != 0; i--) {
struct file *f = *old_fds++;
- if (f)
+ if (f) {
get_file(f);
+ } else {
+ /*
+ * The fd may be claimed in the fd bitmap but not yet
+ * instantiated in the files array if a sibling thread
+ * is partway through open(). So make sure that this
+ * fd is available to the new process.
+ */
+ FD_CLR(open_files - i, newf->open_fds);
+ }
*new_fds++ = f;
}
spin_unlock(&oldf->file_lock);