diff -purN linux-2.4.21/fs/binfmt_elf.c linux-f/fs/binfmt_elf.c --- linux-2.4.21/fs/binfmt_elf.c 2002-08-03 02:39:45.000000000 +0200 +++ linux-f/fs/binfmt_elf.c 2003-07-14 22:10:29.000000000 +0200 @@ -375,7 +375,6 @@ static unsigned long load_aout_interp(st unsigned long text_data, elf_entry = ~0UL; char * addr; loff_t offset; - int retval; current->mm->end_code = interp_ex->a_text; text_data = interp_ex->a_text + interp_ex->a_data; @@ -397,11 +396,9 @@ static unsigned long load_aout_interp(st } do_brk(0, text_data); - retval = -ENOEXEC; if (!interpreter->f_op || !interpreter->f_op->read) goto out; - retval = interpreter->f_op->read(interpreter, addr, text_data, &offset); - if (retval < 0) + if (interpreter->f_op->read(interpreter, addr, text_data, &offset) < 0) goto out; flush_icache_range((unsigned long)addr, (unsigned long)addr + text_data); @@ -444,6 +441,7 @@ static int load_elf_binary(struct linux_ struct elfhdr interp_elf_ex; struct exec interp_ex; char passed_fileno[6]; + struct files_struct *files, *ftmp; /* Get the exec-header */ elf_ex = *((struct elfhdr *) bprm->buf); @@ -475,10 +473,17 @@ static int load_elf_binary(struct linux_ retval = kernel_read(bprm->file, elf_ex.e_phoff, (char *) elf_phdata, size); if (retval < 0) goto out_free_ph; + + files = current->files; /* Refcounted so ok */ + if(unshare_files() < 0) + goto out_free_ph; + /* exec will make our files private anyway, but for the a.out + loader stuff we need to do it earlier */ + retval = get_unused_fd(); if (retval < 0) - goto out_free_ph; + goto out_free_fh; get_file(bprm->file); fd_install(elf_exec_fileno = retval, bprm->file); @@ -593,6 +598,9 @@ static int load_elf_binary(struct linux_ if (retval) goto out_free_dentry; + /* Discard our unneeded old files struct */ + put_files_struct(files); + /* OK, This is the point of no return */ current->mm->start_data = 0; current->mm->end_data = 0; @@ -711,7 +719,8 @@ static int load_elf_binary(struct linux_ printk(KERN_ERR "Unable to load interpreter\n"); kfree(elf_phdata); send_sig(SIGSEGV, current, 0); - return 0; + retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + goto out; } } @@ -797,6 +806,10 @@ out_free_interp: kfree(elf_interpreter); out_free_file: sys_close(elf_exec_fileno); +out_free_fh: + ftmp = current->files; + current->files = files; + put_files_struct(ftmp); out_free_ph: kfree(elf_phdata); goto out; diff -purN linux-2.4.21/fs/exec.c linux-f/fs/exec.c --- linux-2.4.21/fs/exec.c 2003-06-13 16:51:37.000000000 +0200 +++ linux-f/fs/exec.c 2003-07-14 22:10:29.000000000 +0200 @@ -557,6 +570,7 @@ int flush_old_exec(struct linux_binprm * char * name; int i, ch, retval; struct signal_struct * oldsig; + struct files_struct * files; /* * Make sure we have a private signal table @@ -565,6 +579,18 @@ int flush_old_exec(struct linux_binprm * retval = make_private_signals(); if (retval) goto flush_failed; + /* + * Make sure we have private file handles. Ask the + * fork helper to do the work for us and the exit + * helper to do the cleanup of the old one. + */ + + files = current->files; /* refcounted so safe to hold */ + retval = unshare_files(); + if(retval) + goto flush_failed; + put_files_struct(files); + /* * Release all of the old mmap stuff */ diff -purN linux-2.4.21/include/linux/fs.h linux-f/include/linux/fs.h --- linux-2.4.21/include/linux/fs.h 2003-06-13 16:51:38.000000000 +0200 +++ linux-f/include/linux/fs.h 2003-07-14 22:10:31.000000000 +0200 @@ -1523,6 +1578,9 @@ extern int generic_osync_inode(struct in extern int inode_change_ok(struct inode *, struct iattr *); extern int inode_setattr(struct inode *, struct iattr *); +/* kernel/fork.c */ +extern int unshare_files(void); + /* * Common dentry functions for inclusion in the VFS * or in other stackable file systems. Some of these diff -purN linux-2.4.21/kernel/fork.c linux-f/kernel/fork.c --- linux-2.4.21/kernel/fork.c 2003-06-13 16:51:39.000000000 +0200 +++ linux-f/kernel/fork.c 2003-07-14 22:10:31.000000000 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -537,6 +555,33 @@ 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; +} + static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk) { struct signal_struct *sig;