summaryrefslogtreecommitdiff
path: root/kernel/fork.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2003-12-29 05:41:18 -0800
committerLinus Torvalds <torvalds@home.osdl.org>2003-12-29 05:41:18 -0800
commit02cda956de0b28eeb2f65185e9800191fced01c4 (patch)
tree9f5c4870dca18805635ffde9d7d9948ad232480a /kernel/fork.c
parent3a8d53478ed24a2d2df794986f7f1aab8e6c36b7 (diff)
[PATCH] unshare_files
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.
Diffstat (limited to 'kernel/fork.c')
-rw-r--r--kernel/fork.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/kernel/fork.c b/kernel/fork.c
index 381b80b510ba..0603f230146b 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -642,6 +642,11 @@ 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;
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;