summaryrefslogtreecommitdiff
path: root/fs/exec.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2008-04-22 05:11:59 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2008-04-25 09:23:53 -0400
commitfd8328be874f4190a811c58cd4778ec2c74d2c05 (patch)
treeb44ae8e99ce96a1a4739b04d4d1a23c40ab8b163 /fs/exec.c
parent6b335d9c80d7f3c2a3f6545f664ae9007a0f3821 (diff)
downloadlwn-fd8328be874f4190a811c58cd4778ec2c74d2c05.tar.gz
lwn-fd8328be874f4190a811c58cd4778ec2c74d2c05.zip
[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 <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c34
1 files changed, 18 insertions, 16 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 54a0a557b678..475543002f13 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)];
/*
@@ -965,26 +964,15 @@ int flush_old_exec(struct linux_binprm * bprm)
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;
}