diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2020-05-11 19:10:25 +0200 |
---|---|---|
committer | Eric W. Biederman <ebiederm@xmission.com> | 2020-05-11 19:12:22 +0200 |
commit | 27e68f086393b34ada9d5e2bb255f74abe7dc19a (patch) | |
tree | 5b6a67f79400fd6868e5debdc16dfa1811f40225 | |
parent | exec: Promised cleanups after introducing exec_update_mutex (diff) | |
parent | exec: Set the point of no return sooner (diff) | |
download | linux-27e68f086393b34ada9d5e2bb255f74abe7dc19a.tar.xz linux-27e68f086393b34ada9d5e2bb255f74abe7dc19a.zip |
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: "Eric W. Biederman" <ebiederm@xmission.com>
-rw-r--r-- | fs/exec.c | 46 |
1 files changed, 24 insertions, 22 deletions
diff --git a/fs/exec.c b/fs/exec.c index 3cc40048cc65..9aa08ce2ffcc 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -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,7 +1297,7 @@ 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) { @@ -1304,6 +1305,11 @@ int begin_new_exec(struct linux_binprm * bprm) int retval; /* + * Ensure all future errors are fatal. + */ + bprm->point_of_no_return = true; + + /* * Make this the only thread in the thread group. */ retval = de_thread(me); @@ -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); |