mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-24 14:07:52 -04:00
Merge branch 'exec-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull execve updates from Eric Biederman: "Last cycle for the Nth time I ran into bugs and quality of implementation issues related to exec that could not be easily be fixed because of the way exec is implemented. So I have been digging into exec and cleanup up what I can. I don't think I have exec sorted out enough to fix the issues I started with but I have made some headway this cycle with 4 sets of changes. - promised cleanups after introducing exec_update_mutex - trivial cleanups for exec - control flow simplifications - remove the recomputation of bprm->cred The net result is code that is a bit easier to understand and work with and a decrease in the number of lines of code (if you don't count the added tests)" * 'exec-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace: (24 commits) exec: Compute file based creds only once exec: Add a per bprm->file version of per_clear binfmt_elf_fdpic: fix execfd build regression selftests/exec: Add binfmt_script regression test exec: Remove recursion from search_binary_handler exec: Generic execfd support exec/binfmt_script: Don't modify bprm->buf and then return -ENOEXEC exec: Move the call of prepare_binprm into search_binary_handler exec: Allow load_misc_binary to call prepare_binprm unconditionally exec: Convert security_bprm_set_creds into security_bprm_repopulate_creds exec: Factor security_bprm_creds_for_exec out of security_bprm_set_creds exec: Teach prepare_exec_creds how exec treats uids & gids exec: Set the point of no return sooner exec: Move handling of the point of no return to the top level exec: Run sync_mm_rss before taking exec_update_mutex exec: Fix spelling of search_binary_handler in a comment exec: Move the comment from above de_thread to above unshare_sighand exec: Rename flush_old_exec begin_new_exec exec: Move most of setup_new_exec into flush_old_exec exec: In setup_new_exec cache current in the local variable me ...
This commit is contained in:
commit
15a2bc4dbb
27 changed files with 501 additions and 387 deletions
316
fs/exec.c
316
fs/exec.c
|
@ -72,6 +72,8 @@
|
|||
|
||||
#include <trace/events/sched.h>
|
||||
|
||||
static int bprm_creds_from_file(struct linux_binprm *bprm);
|
||||
|
||||
int suid_dumpable = 0;
|
||||
|
||||
static LIST_HEAD(formats);
|
||||
|
@ -1051,13 +1053,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 +1096,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;
|
||||
|
@ -1236,6 +1233,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;
|
||||
|
@ -1292,13 +1295,23 @@ 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 flush_old_exec(struct linux_binprm * bprm)
|
||||
int begin_new_exec(struct linux_binprm * bprm)
|
||||
{
|
||||
struct task_struct *me = current;
|
||||
int retval;
|
||||
|
||||
/* Once we are committed compute the creds */
|
||||
retval = bprm_creds_from_file(bprm);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/*
|
||||
* Ensure all future errors are fatal.
|
||||
*/
|
||||
bprm->point_of_no_return = true;
|
||||
|
||||
/*
|
||||
* Make this the only thread in the thread group.
|
||||
*/
|
||||
|
@ -1313,7 +1326,10 @@ int flush_old_exec(struct linux_binprm * bprm)
|
|||
*/
|
||||
set_mm_exe_file(bprm->mm, bprm->file);
|
||||
|
||||
/* If the binary is not readable then enforce mm->dumpable=0 */
|
||||
would_dump(bprm, bprm->file);
|
||||
if (bprm->have_execfd)
|
||||
would_dump(bprm, bprm->executable);
|
||||
|
||||
/*
|
||||
* Release all of the old mmap stuff
|
||||
|
@ -1323,13 +1339,6 @@ int flush_old_exec(struct linux_binprm * bprm)
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* After setting bprm->called_exec_mmap (to mark that current is
|
||||
* using the prepared mm now), we have nothing left of the original
|
||||
* process. If anything from here on returns an error, the check
|
||||
* in search_binary_handler() will SEGV current.
|
||||
*/
|
||||
bprm->called_exec_mmap = 1;
|
||||
bprm->mm = NULL;
|
||||
|
||||
#ifdef CONFIG_POSIX_TIMERS
|
||||
|
@ -1342,7 +1351,7 @@ int flush_old_exec(struct linux_binprm * bprm)
|
|||
*/
|
||||
retval = unshare_sighand(me);
|
||||
if (retval)
|
||||
goto out;
|
||||
goto out_unlock;
|
||||
|
||||
set_fs(USER_DS);
|
||||
me->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
|
||||
|
@ -1357,12 +1366,84 @@ int flush_old_exec(struct linux_binprm * bprm)
|
|||
* undergoing exec(2).
|
||||
*/
|
||||
do_close_on_exec(me->files);
|
||||
|
||||
if (bprm->secureexec) {
|
||||
/* Make sure parent cannot signal privileged process. */
|
||||
me->pdeath_signal = 0;
|
||||
|
||||
/*
|
||||
* For secureexec, reset the stack limit to sane default to
|
||||
* avoid bad behavior from the prior rlimits. This has to
|
||||
* happen before arch_pick_mmap_layout(), which examines
|
||||
* RLIMIT_STACK, but after the point of no return to avoid
|
||||
* needing to clean up the change on failure.
|
||||
*/
|
||||
if (bprm->rlim_stack.rlim_cur > _STK_LIM)
|
||||
bprm->rlim_stack.rlim_cur = _STK_LIM;
|
||||
}
|
||||
|
||||
me->sas_ss_sp = me->sas_ss_size = 0;
|
||||
|
||||
/*
|
||||
* Figure out dumpability. Note that this checking only of current
|
||||
* is wrong, but userspace depends on it. This should be testing
|
||||
* bprm->secureexec instead.
|
||||
*/
|
||||
if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP ||
|
||||
!(uid_eq(current_euid(), current_uid()) &&
|
||||
gid_eq(current_egid(), current_gid())))
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
else
|
||||
set_dumpable(current->mm, SUID_DUMP_USER);
|
||||
|
||||
perf_event_exec();
|
||||
__set_task_comm(me, kbasename(bprm->filename), true);
|
||||
|
||||
/* An exec changes our domain. We are no longer part of the thread
|
||||
group */
|
||||
WRITE_ONCE(me->self_exec_id, me->self_exec_id + 1);
|
||||
flush_signal_handlers(me, 0);
|
||||
|
||||
/*
|
||||
* install the new credentials for this executable
|
||||
*/
|
||||
security_bprm_committing_creds(bprm);
|
||||
|
||||
commit_creds(bprm->cred);
|
||||
bprm->cred = NULL;
|
||||
|
||||
/*
|
||||
* Disable monitoring for regular users
|
||||
* when executing setuid binaries. Must
|
||||
* wait until new credentials are committed
|
||||
* by commit_creds() above
|
||||
*/
|
||||
if (get_dumpable(me->mm) != SUID_DUMP_USER)
|
||||
perf_event_exit_task(me);
|
||||
/*
|
||||
* cred_guard_mutex must be held at least to this point to prevent
|
||||
* ptrace_attach() from altering our determination of the task's
|
||||
* credentials; any time after this it may be unlocked.
|
||||
*/
|
||||
security_bprm_committed_creds(bprm);
|
||||
|
||||
/* Pass the opened binary to the interpreter. */
|
||||
if (bprm->have_execfd) {
|
||||
retval = get_unused_fd_flags(0);
|
||||
if (retval < 0)
|
||||
goto out_unlock;
|
||||
fd_install(retval, bprm->executable);
|
||||
bprm->executable = NULL;
|
||||
bprm->execfd = retval;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&me->signal->exec_update_mutex);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(flush_old_exec);
|
||||
EXPORT_SYMBOL(begin_new_exec);
|
||||
|
||||
void would_dump(struct linux_binprm *bprm, struct file *file)
|
||||
{
|
||||
|
@ -1387,58 +1468,20 @@ EXPORT_SYMBOL(would_dump);
|
|||
|
||||
void setup_new_exec(struct linux_binprm * bprm)
|
||||
{
|
||||
/*
|
||||
* Once here, prepare_binrpm() will not be called any more, so
|
||||
* the final state of setuid/setgid/fscaps can be merged into the
|
||||
* secureexec flag.
|
||||
*/
|
||||
bprm->secureexec |= bprm->cap_elevated;
|
||||
/* Setup things that can depend upon the personality */
|
||||
struct task_struct *me = current;
|
||||
|
||||
if (bprm->secureexec) {
|
||||
/* Make sure parent cannot signal privileged process. */
|
||||
current->pdeath_signal = 0;
|
||||
|
||||
/*
|
||||
* For secureexec, reset the stack limit to sane default to
|
||||
* avoid bad behavior from the prior rlimits. This has to
|
||||
* happen before arch_pick_mmap_layout(), which examines
|
||||
* RLIMIT_STACK, but after the point of no return to avoid
|
||||
* needing to clean up the change on failure.
|
||||
*/
|
||||
if (bprm->rlim_stack.rlim_cur > _STK_LIM)
|
||||
bprm->rlim_stack.rlim_cur = _STK_LIM;
|
||||
}
|
||||
|
||||
arch_pick_mmap_layout(current->mm, &bprm->rlim_stack);
|
||||
|
||||
current->sas_ss_sp = current->sas_ss_size = 0;
|
||||
|
||||
/*
|
||||
* Figure out dumpability. Note that this checking only of current
|
||||
* is wrong, but userspace depends on it. This should be testing
|
||||
* bprm->secureexec instead.
|
||||
*/
|
||||
if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP ||
|
||||
!(uid_eq(current_euid(), current_uid()) &&
|
||||
gid_eq(current_egid(), current_gid())))
|
||||
set_dumpable(current->mm, suid_dumpable);
|
||||
else
|
||||
set_dumpable(current->mm, SUID_DUMP_USER);
|
||||
arch_pick_mmap_layout(me->mm, &bprm->rlim_stack);
|
||||
|
||||
arch_setup_new_exec();
|
||||
perf_event_exec();
|
||||
__set_task_comm(current, kbasename(bprm->filename), true);
|
||||
|
||||
/* Set the new mm task size. We have to do that late because it may
|
||||
* depend on TIF_32BIT which is only updated in flush_thread() on
|
||||
* some architectures like powerpc
|
||||
*/
|
||||
current->mm->task_size = TASK_SIZE;
|
||||
|
||||
/* An exec changes our domain. We are no longer part of the thread
|
||||
group */
|
||||
WRITE_ONCE(current->self_exec_id, current->self_exec_id + 1);
|
||||
flush_signal_handlers(current, 0);
|
||||
me->mm->task_size = TASK_SIZE;
|
||||
mutex_unlock(&me->signal->exec_update_mutex);
|
||||
mutex_unlock(&me->signal->cred_guard_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(setup_new_exec);
|
||||
|
||||
|
@ -1454,7 +1497,7 @@ EXPORT_SYMBOL(finalize_exec);
|
|||
|
||||
/*
|
||||
* Prepare credentials and lock ->cred_guard_mutex.
|
||||
* install_exec_creds() commits the new creds and drops the lock.
|
||||
* setup_new_exec() commits the new creds and drops the lock.
|
||||
* Or, if exec fails before, free_bprm() should release ->cred and
|
||||
* and unlock.
|
||||
*/
|
||||
|
@ -1475,8 +1518,6 @@ static void free_bprm(struct linux_binprm *bprm)
|
|||
{
|
||||
free_arg_pages(bprm);
|
||||
if (bprm->cred) {
|
||||
if (bprm->called_exec_mmap)
|
||||
mutex_unlock(¤t->signal->exec_update_mutex);
|
||||
mutex_unlock(¤t->signal->cred_guard_mutex);
|
||||
abort_creds(bprm->cred);
|
||||
}
|
||||
|
@ -1484,6 +1525,8 @@ static void free_bprm(struct linux_binprm *bprm)
|
|||
allow_write_access(bprm->file);
|
||||
fput(bprm->file);
|
||||
}
|
||||
if (bprm->executable)
|
||||
fput(bprm->executable);
|
||||
/* If a binfmt changed the interp, free it. */
|
||||
if (bprm->interp != bprm->filename)
|
||||
kfree(bprm->interp);
|
||||
|
@ -1502,35 +1545,6 @@ int bprm_change_interp(const char *interp, struct linux_binprm *bprm)
|
|||
}
|
||||
EXPORT_SYMBOL(bprm_change_interp);
|
||||
|
||||
/*
|
||||
* install the new credentials for this executable
|
||||
*/
|
||||
void install_exec_creds(struct linux_binprm *bprm)
|
||||
{
|
||||
security_bprm_committing_creds(bprm);
|
||||
|
||||
commit_creds(bprm->cred);
|
||||
bprm->cred = NULL;
|
||||
|
||||
/*
|
||||
* Disable monitoring for regular users
|
||||
* when executing setuid binaries. Must
|
||||
* wait until new credentials are committed
|
||||
* by commit_creds() above
|
||||
*/
|
||||
if (get_dumpable(current->mm) != SUID_DUMP_USER)
|
||||
perf_event_exit_task(current);
|
||||
/*
|
||||
* cred_guard_mutex must be held at least to this point to prevent
|
||||
* ptrace_attach() from altering our determination of the task's
|
||||
* credentials; any time after this it may be unlocked.
|
||||
*/
|
||||
security_bprm_committed_creds(bprm);
|
||||
mutex_unlock(¤t->signal->exec_update_mutex);
|
||||
mutex_unlock(¤t->signal->cred_guard_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(install_exec_creds);
|
||||
|
||||
/*
|
||||
* determine how safe it is to execute the proposed program
|
||||
* - the caller must hold ->cred_guard_mutex to protect against
|
||||
|
@ -1568,29 +1582,21 @@ static void check_unsafe_exec(struct linux_binprm *bprm)
|
|||
spin_unlock(&p->fs->lock);
|
||||
}
|
||||
|
||||
static void bprm_fill_uid(struct linux_binprm *bprm)
|
||||
static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
|
||||
{
|
||||
/* Handle suid and sgid on files */
|
||||
struct inode *inode;
|
||||
unsigned int mode;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
|
||||
/*
|
||||
* Since this can be called multiple times (via prepare_binprm),
|
||||
* we must clear any previous work done when setting set[ug]id
|
||||
* bits from any earlier bprm->file uses (for example when run
|
||||
* first for a setuid script then again for its interpreter).
|
||||
*/
|
||||
bprm->cred->euid = current_euid();
|
||||
bprm->cred->egid = current_egid();
|
||||
|
||||
if (!mnt_may_suid(bprm->file->f_path.mnt))
|
||||
if (!mnt_may_suid(file->f_path.mnt))
|
||||
return;
|
||||
|
||||
if (task_no_new_privs(current))
|
||||
return;
|
||||
|
||||
inode = bprm->file->f_path.dentry->d_inode;
|
||||
inode = file->f_path.dentry->d_inode;
|
||||
mode = READ_ONCE(inode->i_mode);
|
||||
if (!(mode & (S_ISUID|S_ISGID)))
|
||||
return;
|
||||
|
@ -1620,31 +1626,32 @@ static void bprm_fill_uid(struct linux_binprm *bprm)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute brpm->cred based upon the final binary.
|
||||
*/
|
||||
static int bprm_creds_from_file(struct linux_binprm *bprm)
|
||||
{
|
||||
/* Compute creds based on which file? */
|
||||
struct file *file = bprm->execfd_creds ? bprm->executable : bprm->file;
|
||||
|
||||
bprm_fill_uid(bprm, file);
|
||||
return security_bprm_creds_from_file(bprm, file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill the binprm structure from the inode.
|
||||
* Check permissions, then read the first BINPRM_BUF_SIZE bytes
|
||||
* Read the first BINPRM_BUF_SIZE bytes
|
||||
*
|
||||
* This may be called multiple times for binary chains (scripts for example).
|
||||
*/
|
||||
int prepare_binprm(struct linux_binprm *bprm)
|
||||
static int prepare_binprm(struct linux_binprm *bprm)
|
||||
{
|
||||
int retval;
|
||||
loff_t pos = 0;
|
||||
|
||||
bprm_fill_uid(bprm);
|
||||
|
||||
/* fill in binprm security blob */
|
||||
retval = security_bprm_set_creds(bprm);
|
||||
if (retval)
|
||||
return retval;
|
||||
bprm->called_set_creds = 1;
|
||||
|
||||
memset(bprm->buf, 0, BINPRM_BUF_SIZE);
|
||||
return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(prepare_binprm);
|
||||
|
||||
/*
|
||||
* Arguments are '\0' separated strings found at the location bprm->p
|
||||
* points to; chop off the first by relocating brpm->p to right after
|
||||
|
@ -1690,15 +1697,15 @@ EXPORT_SYMBOL(remove_arg_zero);
|
|||
/*
|
||||
* cycle the list of binary formats handler, until one recognizes the image
|
||||
*/
|
||||
int search_binary_handler(struct linux_binprm *bprm)
|
||||
static int search_binary_handler(struct linux_binprm *bprm)
|
||||
{
|
||||
bool need_retry = IS_ENABLED(CONFIG_MODULES);
|
||||
struct linux_binfmt *fmt;
|
||||
int retval;
|
||||
|
||||
/* This allows 4 levels of binfmt rewrites before failing hard. */
|
||||
if (bprm->recursion_depth > 5)
|
||||
return -ELOOP;
|
||||
retval = prepare_binprm(bprm);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
retval = security_bprm_check(bprm);
|
||||
if (retval)
|
||||
|
@ -1712,19 +1719,11 @@ int search_binary_handler(struct linux_binprm *bprm)
|
|||
continue;
|
||||
read_unlock(&binfmt_lock);
|
||||
|
||||
bprm->recursion_depth++;
|
||||
retval = fmt->load_binary(bprm);
|
||||
bprm->recursion_depth--;
|
||||
|
||||
read_lock(&binfmt_lock);
|
||||
put_binfmt(fmt);
|
||||
if (retval < 0 && bprm->called_exec_mmap) {
|
||||
/* 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 || (retval != -ENOEXEC)) {
|
||||
read_unlock(&binfmt_lock);
|
||||
return retval;
|
||||
}
|
||||
|
@ -1743,12 +1742,11 @@ int search_binary_handler(struct linux_binprm *bprm)
|
|||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(search_binary_handler);
|
||||
|
||||
static int exec_binprm(struct linux_binprm *bprm)
|
||||
{
|
||||
pid_t old_pid, old_vpid;
|
||||
int ret;
|
||||
int ret, depth;
|
||||
|
||||
/* Need to fetch pid before load_binary changes it */
|
||||
old_pid = current->pid;
|
||||
|
@ -1756,15 +1754,38 @@ static int exec_binprm(struct linux_binprm *bprm)
|
|||
old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = search_binary_handler(bprm);
|
||||
if (ret >= 0) {
|
||||
audit_bprm(bprm);
|
||||
trace_sched_process_exec(current, old_pid, bprm);
|
||||
ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
|
||||
proc_exec_connector(current);
|
||||
/* This allows 4 levels of binfmt rewrites before failing hard. */
|
||||
for (depth = 0;; depth++) {
|
||||
struct file *exec;
|
||||
if (depth > 5)
|
||||
return -ELOOP;
|
||||
|
||||
ret = search_binary_handler(bprm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!bprm->interpreter)
|
||||
break;
|
||||
|
||||
exec = bprm->file;
|
||||
bprm->file = bprm->interpreter;
|
||||
bprm->interpreter = NULL;
|
||||
|
||||
allow_write_access(exec);
|
||||
if (unlikely(bprm->have_execfd)) {
|
||||
if (bprm->executable) {
|
||||
fput(exec);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
bprm->executable = exec;
|
||||
} else
|
||||
fput(exec);
|
||||
}
|
||||
|
||||
return ret;
|
||||
audit_bprm(bprm);
|
||||
trace_sched_process_exec(current, old_pid, bprm);
|
||||
ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
|
||||
proc_exec_connector(current);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1857,8 +1878,9 @@ static int __do_execve_file(int fd, struct filename *filename,
|
|||
if (retval < 0)
|
||||
goto out;
|
||||
|
||||
retval = prepare_binprm(bprm);
|
||||
if (retval < 0)
|
||||
/* Set the unchanging part of bprm->cred */
|
||||
retval = security_bprm_creds_for_exec(bprm);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = copy_strings_kernel(1, &bprm->filename, bprm);
|
||||
|
@ -1893,6 +1915,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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue