[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>
diff --git a/fs/exec.c b/fs/exec.c
index 54a0a55..4755430 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -953,7 +953,6 @@
 {
 	char * name;
 	int i, ch, retval;
-	struct files_struct *files;
 	char tcomm[sizeof(current->comm)];
 
 	/*
@@ -965,26 +964,15 @@
 		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 @@
 
 	return 0;
 
-mmap_failed:
-	reset_files_struct(current, files);
 out:
 	return retval;
 }
@@ -1283,12 +1269,23 @@
 	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 @@
 		security_bprm_free(bprm);
 		acct_update_integrals(current);
 		kfree(bprm);
+		if (files)
+			put_files_struct(files);
 		return retval;
 	}
 
@@ -1363,6 +1362,9 @@
 out_kfree:
 	kfree(bprm);
 
+out_files:
+	if (files)
+		reset_files_struct(current, files);
 out_ret:
 	return retval;
 }