Commit 610a61e0 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] fix double mmdrop() on exec path

If load_elf_binary() (and the other binary handlers) fail after
flush_old_exec() (for example, in setup_arg_pages()) then do_execve() will go
through and do mmdrop(bprm.mm).

But bprm.mm is now current->mm.  We've just freed the current process's mm.
The kernel dies in a most ghastly manner.

Fix that up by nulling out bprm.mm in flush_old_exec(), at the point where we
consumed the mm.  Handle the null pointer in the do_execve() error path.

Also: don't open-code free_arg_pages() in do_execve(): call it instead.
parent 6501a85b
...@@ -441,7 +441,7 @@ static inline void free_arg_pages(struct linux_binprm *bprm) ...@@ -441,7 +441,7 @@ static inline void free_arg_pages(struct linux_binprm *bprm)
{ {
int i; int i;
for (i = 0 ; i < MAX_ARG_PAGES ; i++) { for (i = 0; i < MAX_ARG_PAGES; i++) {
if (bprm->page[i]) if (bprm->page[i])
__free_page(bprm->page[i]); __free_page(bprm->page[i]);
bprm->page[i] = NULL; bprm->page[i] = NULL;
...@@ -772,6 +772,8 @@ int flush_old_exec(struct linux_binprm * bprm) ...@@ -772,6 +772,8 @@ int flush_old_exec(struct linux_binprm * bprm)
if (retval) if (retval)
goto out; goto out;
bprm->mm = NULL; /* We're using it now */
/* This is the point of no return */ /* This is the point of no return */
current->sas_ss_sp = current->sas_ss_size = 0; current->sas_ss_sp = current->sas_ss_size = 0;
...@@ -999,7 +1001,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) ...@@ -999,7 +1001,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
} }
read_lock(&binfmt_lock); read_lock(&binfmt_lock);
put_binfmt(fmt); put_binfmt(fmt);
if (retval != -ENOEXEC) if (retval != -ENOEXEC || bprm->mm == NULL)
break; break;
if (!bprm->file) { if (!bprm->file) {
read_unlock(&binfmt_lock); read_unlock(&binfmt_lock);
...@@ -1007,7 +1009,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) ...@@ -1007,7 +1009,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
} }
} }
read_unlock(&binfmt_lock); read_unlock(&binfmt_lock);
if (retval != -ENOEXEC) { if (retval != -ENOEXEC || bprm->mm == NULL) {
break; break;
#ifdef CONFIG_KMOD #ifdef CONFIG_KMOD
}else{ }else{
...@@ -1035,7 +1037,6 @@ int do_execve(char * filename, ...@@ -1035,7 +1037,6 @@ int do_execve(char * filename,
struct linux_binprm bprm; struct linux_binprm bprm;
struct file *file; struct file *file;
int retval; int retval;
int i;
sched_balance_exec(); sched_balance_exec();
...@@ -1103,16 +1104,13 @@ int do_execve(char * filename, ...@@ -1103,16 +1104,13 @@ int do_execve(char * filename,
out: out:
/* Something went wrong, return the inode and free the argument pages*/ /* Something went wrong, return the inode and free the argument pages*/
for (i = 0 ; i < MAX_ARG_PAGES ; i++) { free_arg_pages(&bprm);
struct page * page = bprm.page[i];
if (page)
__free_page(page);
}
if (bprm.security) if (bprm.security)
security_bprm_free(&bprm); security_bprm_free(&bprm);
out_mm: out_mm:
if (bprm.mm)
mmdrop(bprm.mm); mmdrop(bprm.mm);
out_file: out_file:
......
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