From fd8328be874f4190a811c58cd4778ec2c74d2c05 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 22 Apr 2008 05:11:59 -0400 Subject: [PATCH] sanitize handling of shared descriptor tables in failing execve() * unshare_files() can fail; doing it after irreversible actions is wrong and de_thread() is certainly irreversible. * since we do it unconditionally anyway, we might as well do it in do_execve() and save ourselves the PITA in binfmt handlers, etc. * while we are at it, binfmt_som actually leaked files_struct on failure. As a side benefit, unshare_files(), put_files_struct() and reset_files_struct() become unexported. Signed-off-by: Al Viro --- fs/exec.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) (limited to 'fs/exec.c') diff --git a/fs/exec.c b/fs/exec.c index 54a0a557b67..475543002f1 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm) { char * name; int i, ch, retval; - struct files_struct *files; char tcomm[sizeof(current->comm)]; /* @@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm) if (retval) goto out; - /* - * 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 out; /* * Release all of the old mmap stuff */ retval = exec_mmap(bprm->mm); if (retval) - goto mmap_failed; + goto out; bprm->mm = NULL; /* We're using it now */ /* This is the point of no return */ - put_files_struct(files); - current->sas_ss_sp = current->sas_ss_size = 0; if (current->euid == current->uid && current->egid == current->gid) @@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm) return 0; -mmap_failed: - reset_files_struct(current, files); out: return retval; } @@ -1283,12 +1269,23 @@ int do_execve(char * filename, struct linux_binprm *bprm; struct file *file; unsigned long env_p; + struct files_struct *files; int retval; + files = current->files; + retval = unshare_files(); + if (retval) + goto out_ret; + + if (files == current->files) { + put_files_struct(files); + files = NULL; + } + retval = -ENOMEM; bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); if (!bprm) - goto out_ret; + goto out_files; file = open_exec(filename); retval = PTR_ERR(file); @@ -1343,6 +1340,8 @@ int do_execve(char * filename, security_bprm_free(bprm); acct_update_integrals(current); kfree(bprm); + if (files) + put_files_struct(files); return retval; } @@ -1363,6 +1362,9 @@ out_file: out_kfree: kfree(bprm); +out_files: + if (files) + reset_files_struct(current, files); out_ret: return retval; } -- cgit v1.2.3