aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-04-22 04:45:46 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-25 09:23:48 -0400
commit6b335d9c80d7f3c2a3f6545f664ae9007a0f3821 (patch)
treefa9ab80e1fddc05b79a76bd10922b3328fe6c3e6 /kernel
parent42faad99658eed7ca8bd328ffa4bcb7d78c9bcca (diff)
[PATCH] close race in unshare_files()
updating current->files requires task_lock Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/fork.c20
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)
805 goto out; 805 goto out;
806 } 806 }
807 807
808 /*
809 * Note: we may be using current for both targets (See exec.c)
810 * This works because we cache current->files (old) as oldf. Don't
811 * break this.
812 */
813 tsk->files = NULL;
814 newf = dup_fd(oldf, &error); 808 newf = dup_fd(oldf, &error);
815 if (!newf) 809 if (!newf)
816 goto out; 810 goto out;
@@ -855,7 +849,8 @@ static int copy_io(unsigned long clone_flags, struct task_struct *tsk)
855int unshare_files(void) 849int unshare_files(void)
856{ 850{
857 struct files_struct *files = current->files; 851 struct files_struct *files = current->files;
858 int rc; 852 struct files_struct *newf;
853 int error = 0;
859 854
860 BUG_ON(!files); 855 BUG_ON(!files);
861 856
@@ -866,10 +861,13 @@ int unshare_files(void)
866 atomic_inc(&files->count); 861 atomic_inc(&files->count);
867 return 0; 862 return 0;
868 } 863 }
869 rc = copy_files(0, current); 864 newf = dup_fd(files, &error);
870 if(rc) 865 if (newf) {
871 current->files = files; 866 task_lock(current);
872 return rc; 867 current->files = newf;
868 task_unlock(current);
869 }
870 return error;
873} 871}
874 872
875EXPORT_SYMBOL(unshare_files); 873EXPORT_SYMBOL(unshare_files);