Commit fd8328be authored by Al Viro's avatar Al Viro

[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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6b335d9c
...@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -543,7 +543,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
unsigned long interp_load_addr = 0; unsigned long interp_load_addr = 0;
unsigned long start_code, end_code, start_data, end_data; unsigned long start_code, end_code, start_data, end_data;
unsigned long reloc_func_desc = 0; unsigned long reloc_func_desc = 0;
struct files_struct *files;
int executable_stack = EXSTACK_DEFAULT; int executable_stack = EXSTACK_DEFAULT;
unsigned long def_flags = 0; unsigned long def_flags = 0;
struct { struct {
...@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -593,20 +592,9 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto out_free_ph; goto out_free_ph;
} }
files = current->files; /* Refcounted so ok */
retval = unshare_files();
if (retval < 0)
goto out_free_ph;
if (files == current->files) {
put_files_struct(files);
files = NULL;
}
/* exec will make our files private anyway, but for the a.out
loader stuff we need to do it earlier */
retval = get_unused_fd(); retval = get_unused_fd();
if (retval < 0) if (retval < 0)
goto out_free_fh; goto out_free_ph;
get_file(bprm->file); get_file(bprm->file);
fd_install(elf_exec_fileno = retval, bprm->file); fd_install(elf_exec_fileno = retval, bprm->file);
...@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -728,12 +716,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval) if (retval)
goto out_free_dentry; goto out_free_dentry;
/* Discard our unneeded old files struct */
if (files) {
put_files_struct(files);
files = NULL;
}
/* OK, This is the point of no return */ /* OK, This is the point of no return */
current->flags &= ~PF_FORKNOEXEC; current->flags &= ~PF_FORKNOEXEC;
current->mm->def_flags = def_flags; current->mm->def_flags = def_flags;
...@@ -1016,9 +998,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -1016,9 +998,6 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs)
kfree(elf_interpreter); kfree(elf_interpreter);
out_free_file: out_free_file:
sys_close(elf_exec_fileno); sys_close(elf_exec_fileno);
out_free_fh:
if (files)
reset_files_struct(current, files);
out_free_ph: out_free_ph:
kfree(elf_phdata); kfree(elf_phdata);
goto out; goto out;
......
...@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -110,7 +110,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
char *iname_addr = iname; char *iname_addr = iname;
int retval; int retval;
int fd_binary = -1; int fd_binary = -1;
struct files_struct *files = NULL;
retval = -ENOEXEC; retval = -ENOEXEC;
if (!enabled) if (!enabled)
...@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -133,21 +132,13 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (fmt->flags & MISC_FMT_OPEN_BINARY) { if (fmt->flags & MISC_FMT_OPEN_BINARY) {
files = current->files;
retval = unshare_files();
if (retval < 0)
goto _ret;
if (files == current->files) {
put_files_struct(files);
files = NULL;
}
/* if the binary should be opened on behalf of the /* if the binary should be opened on behalf of the
* interpreter than keep it open and assign descriptor * interpreter than keep it open and assign descriptor
* to it */ * to it */
fd_binary = get_unused_fd(); fd_binary = get_unused_fd();
if (fd_binary < 0) { if (fd_binary < 0) {
retval = fd_binary; retval = fd_binary;
goto _unshare; goto _ret;
} }
fd_install(fd_binary, bprm->file); fd_install(fd_binary, bprm->file);
...@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -205,10 +196,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval < 0) if (retval < 0)
goto _error; goto _error;
if (files) {
put_files_struct(files);
files = NULL;
}
_ret: _ret:
return retval; return retval;
_error: _error:
...@@ -216,9 +203,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs) ...@@ -216,9 +203,6 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
sys_close(fd_binary); sys_close(fd_binary);
bprm->interp_flags = 0; bprm->interp_flags = 0;
bprm->interp_data = 0; bprm->interp_data = 0;
_unshare:
if (files)
reset_files_struct(current, files);
goto _ret; goto _ret;
} }
......
...@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -194,7 +194,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned long som_entry; unsigned long som_entry;
struct som_hdr *som_ex; struct som_hdr *som_ex;
struct som_exec_auxhdr *hpuxhdr; struct som_exec_auxhdr *hpuxhdr;
struct files_struct *files;
/* Get the exec-header */ /* Get the exec-header */
som_ex = (struct som_hdr *) bprm->buf; som_ex = (struct som_hdr *) bprm->buf;
...@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) ...@@ -221,15 +220,6 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
goto out_free; goto out_free;
} }
files = current->files; /* Refcounted so ok */
retval = unshare_files();
if (retval < 0)
goto out_free;
if (files == current->files) {
put_files_struct(files);
files = NULL;
}
retval = get_unused_fd(); retval = get_unused_fd();
if (retval < 0) if (retval < 0)
goto out_free; goto out_free;
......
...@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -953,7 +953,6 @@ int flush_old_exec(struct linux_binprm * bprm)
{ {
char * name; char * name;
int i, ch, retval; int i, ch, retval;
struct files_struct *files;
char tcomm[sizeof(current->comm)]; char tcomm[sizeof(current->comm)];
/* /*
...@@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -964,27 +963,16 @@ int flush_old_exec(struct linux_binprm * bprm)
if (retval) if (retval)
goto out; 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 * Release all of the old mmap stuff
*/ */
retval = exec_mmap(bprm->mm); retval = exec_mmap(bprm->mm);
if (retval) if (retval)
goto mmap_failed; goto out;
bprm->mm = NULL; /* We're using it now */ bprm->mm = NULL; /* We're using it now */
/* This is the point of no return */ /* This is the point of no return */
put_files_struct(files);
current->sas_ss_sp = current->sas_ss_size = 0; current->sas_ss_sp = current->sas_ss_size = 0;
if (current->euid == current->uid && current->egid == current->gid) if (current->euid == current->uid && current->egid == current->gid)
...@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -1034,8 +1022,6 @@ int flush_old_exec(struct linux_binprm * bprm)
return 0; return 0;
mmap_failed:
reset_files_struct(current, files);
out: out:
return retval; return retval;
} }
...@@ -1283,12 +1269,23 @@ int do_execve(char * filename, ...@@ -1283,12 +1269,23 @@ int do_execve(char * filename,
struct linux_binprm *bprm; struct linux_binprm *bprm;
struct file *file; struct file *file;
unsigned long env_p; unsigned long env_p;
struct files_struct *files;
int retval; 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; retval = -ENOMEM;
bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); bprm = kzalloc(sizeof(*bprm), GFP_KERNEL);
if (!bprm) if (!bprm)
goto out_ret; goto out_files;
file = open_exec(filename); file = open_exec(filename);
retval = PTR_ERR(file); retval = PTR_ERR(file);
...@@ -1343,6 +1340,8 @@ int do_execve(char * filename, ...@@ -1343,6 +1340,8 @@ int do_execve(char * filename,
security_bprm_free(bprm); security_bprm_free(bprm);
acct_update_integrals(current); acct_update_integrals(current);
kfree(bprm); kfree(bprm);
if (files)
put_files_struct(files);
return retval; return retval;
} }
...@@ -1363,6 +1362,9 @@ int do_execve(char * filename, ...@@ -1363,6 +1362,9 @@ int do_execve(char * filename,
out_kfree: out_kfree:
kfree(bprm); kfree(bprm);
out_files:
if (files)
reset_files_struct(current, files);
out_ret: out_ret:
return retval; return retval;
} }
......
...@@ -507,8 +507,6 @@ void put_files_struct(struct files_struct *files) ...@@ -507,8 +507,6 @@ void put_files_struct(struct files_struct *files)
} }
} }
EXPORT_SYMBOL(put_files_struct);
void reset_files_struct(struct task_struct *tsk, struct files_struct *files) void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
{ {
struct files_struct *old; struct files_struct *old;
...@@ -519,7 +517,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files) ...@@ -519,7 +517,6 @@ void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
task_unlock(tsk); task_unlock(tsk);
put_files_struct(old); put_files_struct(old);
} }
EXPORT_SYMBOL(reset_files_struct);
void exit_files(struct task_struct *tsk) void exit_files(struct task_struct *tsk)
{ {
......
...@@ -870,8 +870,6 @@ int unshare_files(void) ...@@ -870,8 +870,6 @@ int unshare_files(void)
return error; return error;
} }
EXPORT_SYMBOL(unshare_files);
static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)
{ {
struct sighand_struct *sig; struct sighand_struct *sig;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment