From 6b335d9c80d7f3c2a3f6545f664ae9007a0f3821 Mon Sep 17 00:00:00 2001
From: Al Viro <viro@zeniv.linux.org.uk>
Date: Tue, 22 Apr 2008 04:45:46 -0400
Subject: [PATCH] [PATCH] close race in unshare_files()

updating current->files requires task_lock

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 kernel/fork.c | 20 +++++++++-----------
 1 file 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);