From: Chris Wright <chrisw@osdl.org>

Introduce unshare_files as a helper for use during execve to eliminate
potential leak of the execve'd binary's fd.



 25-akpm/include/linux/fs.h |    3 +++
 25-akpm/kernel/fork.c      |   34 ++++++++++++++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff -puN include/linux/fs.h~unshare_files include/linux/fs.h
--- 25/include/linux/fs.h~unshare_files	Thu Dec 18 13:56:54 2003
+++ 25-akpm/include/linux/fs.h	Thu Dec 18 13:56:54 2003
@@ -1410,5 +1410,8 @@ static inline ino_t parent_ino(struct de
 	return res;
 }
 
+/* kernel/fork.c */
+extern int unshare_files(void);
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_FS_H */
diff -puN kernel/fork.c~unshare_files kernel/fork.c
--- 25/kernel/fork.c~unshare_files	Thu Dec 18 13:56:54 2003
+++ 25-akpm/kernel/fork.c	Thu Dec 18 13:56:54 2003
@@ -642,6 +642,11 @@ static int copy_files(unsigned long clon
 		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;
 	error = -ENOMEM;
 	newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
@@ -731,6 +736,35 @@ out_release:
 	goto out;
 }
 
+/*
+ *	Helper to unshare the files of the current task.
+ *	We don't want to expose copy_files internals to
+ *	the exec layer of the kernel.
+ */
+
+int unshare_files(void)
+{
+	struct files_struct *files  = current->files;
+	int rc;
+
+	if(!files)
+		BUG();
+
+	/* This can race but the race causes us to copy when we don't
+	   need to and drop the copy */
+	if(atomic_read(&files->count) == 1)
+	{
+		atomic_inc(&files->count);
+		return 0;
+	}
+	rc = copy_files(0, current);
+	if(rc)
+		current->files = files;
+	return rc;
+}
+
+EXPORT_SYMBOL(unshare_files);
+
 static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
 {
 	struct sighand_struct *sig;

_