

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.


 fs/exec.c |   20 +++++++++-----------
 1 files changed, 9 insertions(+), 11 deletions(-)

diff -puN fs/exec.c~double-mmdrop-fix fs/exec.c
--- 25/fs/exec.c~double-mmdrop-fix	2003-07-01 01:45:51.000000000 -0700
+++ 25-akpm/fs/exec.c	2003-07-01 01:45:51.000000000 -0700
@@ -441,9 +441,9 @@ static inline void free_arg_pages(struct
 {
 	int i;
 
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+	for (i = 0; i < MAX_ARG_PAGES; i++) {
 		if (bprm->page[i])
-		__free_page(bprm->page[i]);
+			__free_page(bprm->page[i]);
 		bprm->page[i] = NULL;
 	}
 }
@@ -773,6 +773,8 @@ int flush_old_exec(struct linux_binprm *
 	if (retval)
 		goto out;
 
+	bprm->mm = NULL;		/* We're using it now */
+
 	/* This is the point of no return */
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
@@ -1000,7 +1002,7 @@ int search_binary_handler(struct linux_b
 			}
 			read_lock(&binfmt_lock);
 			put_binfmt(fmt);
-			if (retval != -ENOEXEC)
+			if (retval != -ENOEXEC || bprm->mm == NULL)
 				break;
 			if (!bprm->file) {
 				read_unlock(&binfmt_lock);
@@ -1008,7 +1010,7 @@ int search_binary_handler(struct linux_b
 			}
 		}
 		read_unlock(&binfmt_lock);
-		if (retval != -ENOEXEC) {
+		if (retval != -ENOEXEC || bprm->mm == NULL) {
 			break;
 #ifdef CONFIG_KMOD
 		}else{
@@ -1036,7 +1038,6 @@ int do_execve(char * filename,
 	struct linux_binprm bprm;
 	struct file *file;
 	int retval;
-	int i;
 
 	sched_balance_exec();
 
@@ -1104,17 +1105,14 @@ int do_execve(char * filename,
 
 out:
 	/* Something went wrong, return the inode and free the argument pages*/
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page * page = bprm.page[i];
-		if (page)
-			__free_page(page);
-	}
+	free_arg_pages(&bprm);
 
 	if (bprm.security)
 		security_bprm_free(&bprm);
 
 out_mm:
-	mmdrop(bprm.mm);
+	if (bprm.mm)
+		mmdrop(bprm.mm);
 
 out_file:
 	if (bprm.file) {

_
