Commit 27e68f08 authored by Eric W. Biederman's avatar Eric W. Biederman
Browse files

exec: Trivial cleanups for exec

This is a continuation of my work to clean up exec so it's more
difficult problems are approachable.

The changes correct some comments, and moves the point_of_no_return
variable up to when the point_of_no_return actually occurs.

Eric W. Biederman (5):
      exec: Move the comment from above de_thread to above unshare_sighand
      exec: Fix spelling of search_binary_handler in a comment
      exec: Run sync_mm_rss before taking exec_update_mutex
      exec: Move handling of the point of no return to the top level
      exec: Set the point of no return sooner

 fs/exec.c | 46 ++++++++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 22 deletions(-)

Link: https://lkml.kernel.org/r/87sgga6ze4.fsf@x220.int.ebiederm.org


Signed-off-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
parents b213c2dc 6834e0bb
Loading
Loading
Loading
Loading
+24 −22
Original line number Diff line number Diff line
@@ -1051,13 +1051,14 @@ static int exec_mmap(struct mm_struct *mm)
	tsk = current;
	old_mm = current->mm;
	exec_mm_release(tsk, old_mm);
	if (old_mm)
		sync_mm_rss(old_mm);

	ret = mutex_lock_killable(&tsk->signal->exec_update_mutex);
	if (ret)
		return ret;

	if (old_mm) {
		sync_mm_rss(old_mm);
		/*
		 * Make sure that if there is a core dump in progress
		 * for the old mm, we get out and die instead of going
@@ -1093,12 +1094,6 @@ static int exec_mmap(struct mm_struct *mm)
	return 0;
}

/*
 * This function makes sure the current process has its own signal table,
 * so that flush_signal_handlers can later reset the handlers without
 * disturbing other processes.  (Other processes might share the signal
 * table via the CLONE_SIGHAND option to clone().)
 */
static int de_thread(struct task_struct *tsk)
{
	struct signal_struct *sig = tsk->signal;
@@ -1240,6 +1235,12 @@ killed:
}


/*
 * This function makes sure the current process has its own signal table,
 * so that flush_signal_handlers can later reset the handlers without
 * disturbing other processes.  (Other processes might share the signal
 * table via the CLONE_SIGHAND option to clone().)
 */
static int unshare_sighand(struct task_struct *me)
{
	struct sighand_struct *oldsighand = me->sighand;
@@ -1296,13 +1297,18 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
 * Calling this is the point of no return. None of the failures will be
 * seen by userspace since either the process is already taking a fatal
 * signal (via de_thread() or coredump), or will have SEGV raised
 * (after exec_mmap()) by search_binary_handlers (see below).
 * (after exec_mmap()) by search_binary_handler (see below).
 */
int begin_new_exec(struct linux_binprm * bprm)
{
	struct task_struct *me = current;
	int retval;

	/*
	 * Ensure all future errors are fatal.
	 */
	bprm->point_of_no_return = true;

	/*
	 * Make this the only thread in the thread group.
	 */
@@ -1325,13 +1331,6 @@ int begin_new_exec(struct linux_binprm * bprm)
	if (retval)
		goto out;

	/*
	 * With the new mm installed it is completely impossible to
	 * fail and return to the original process.  If anything from
	 * here on returns an error, the check in
	 * search_binary_handler() will SEGV current.
	 */
	bprm->point_of_no_return = true;
	bprm->mm = NULL;

#ifdef CONFIG_POSIX_TIMERS
@@ -1720,13 +1719,8 @@ int search_binary_handler(struct linux_binprm *bprm)

		read_lock(&binfmt_lock);
		put_binfmt(fmt);
		if (retval < 0 && bprm->point_of_no_return) {
			/* we got to flush_old_exec() and failed after it */
			read_unlock(&binfmt_lock);
			force_sigsegv(SIGSEGV);
			return retval;
		}
		if (retval != -ENOEXEC || !bprm->file) {
		if (bprm->point_of_no_return || !bprm->file ||
		    (retval != -ENOEXEC)) {
			read_unlock(&binfmt_lock);
			return retval;
		}
@@ -1897,6 +1891,14 @@ static int __do_execve_file(int fd, struct filename *filename,
	return retval;

out:
	/*
	 * If past the point of no return ensure the the code never
	 * returns to the userspace process.  Use an existing fatal
	 * signal if present otherwise terminate the process with
	 * SIGSEGV.
	 */
	if (bprm->point_of_no_return && !fatal_signal_pending(current))
		force_sigsegv(SIGSEGV);
	if (bprm->mm) {
		acct_arg_size(bprm, 0);
		mmput(bprm->mm);