From: Chris Wright 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; _