Commit 2dbc5729 authored by Gregory Kurz's avatar Gregory Kurz Committed by Linus Torvalds

[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)-
parent 0105467f
...@@ -762,8 +762,17 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) ...@@ -762,8 +762,17 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk)
for (i = open_files; i != 0; i--) { for (i = open_files; i != 0; i--) {
struct file *f = *old_fds++; struct file *f = *old_fds++;
if (f) if (f) {
get_file(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; *new_fds++ = f;
} }
spin_unlock(&oldf->file_lock); spin_unlock(&oldf->file_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment