[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>
This commit is contained in:
34
fs/exec.c
34
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user