diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-22 12:45:46 +0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-25 17:23:48 +0400 |
commit | 6b335d9c80d7f3c2a3f6545f664ae9007a0f3821 (patch) | |
tree | fa9ab80e1fddc05b79a76bd10922b3328fe6c3e6 | |
parent | 42faad99658eed7ca8bd328ffa4bcb7d78c9bcca (diff) | |
download | linux-6b335d9c80d7f3c2a3f6545f664ae9007a0f3821.tar.xz |
[PATCH] close race in unshare_files()
updating current->files requires task_lock
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | kernel/fork.c | 20 |
1 files changed, 9 insertions, 11 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index 89fe414645e9..76f05a08062b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -805,12 +805,6 @@ static int copy_files(unsigned long clone_flags, struct task_struct * tsk) goto out; } - /* - * Note: we may be using current for both targets (See exec.c) - * This works because we cache current->files (old) as oldf. Don't - * break this. - */ - tsk->files = NULL; newf = dup_fd(oldf, &error); if (!newf) goto out; @@ -855,7 +849,8 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk) int unshare_files(void) { struct files_struct *files = current->files; - int rc; + struct files_struct *newf; + int error = 0; BUG_ON(!files); @@ -866,10 +861,13 @@ int unshare_files(void) atomic_inc(&files->count); return 0; } - rc = copy_files(0, current); - if(rc) - current->files = files; - return rc; + newf = dup_fd(files, &error); + if (newf) { + task_lock(current); + current->files = newf; + task_unlock(current); + } + return error; } EXPORT_SYMBOL(unshare_files); |