Merge branch 'work.set_fs' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / fs / exec.c
index 15fb4d56cc4306221728d5a29c878df8cd955140..69a543259aa527033010f8ff347f7c26084e0db2 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1240,6 +1240,12 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec)
        perf_event_comm(tsk, 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).
+ */
 int flush_old_exec(struct linux_binprm * bprm)
 {
        int retval;
@@ -1267,7 +1273,13 @@ int flush_old_exec(struct linux_binprm * bprm)
        if (retval)
                goto out;
 
-       bprm->mm = NULL;                /* We're using it now */
+       /*
+        * After clearing bprm->mm (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->mm = NULL;
 
        set_fs(USER_DS);
        current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
@@ -1312,15 +1324,38 @@ 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;
+
+       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 (current->signal->rlim[RLIMIT_STACK].rlim_cur > _STK_LIM)
+                       current->signal->rlim[RLIMIT_STACK].rlim_cur = _STK_LIM;
+       }
+
        arch_pick_mmap_layout(current->mm);
 
-       /* This is the point of no return */
        current->sas_ss_sp = current->sas_ss_size = 0;
 
-       if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid()))
-               set_dumpable(current->mm, SUID_DUMP_USER);
-       else
+       /* Figure out dumpability. */
+       if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP ||
+           bprm->secureexec)
                set_dumpable(current->mm, suid_dumpable);
+       else
+               set_dumpable(current->mm, SUID_DUMP_USER);
 
        arch_setup_new_exec();
        perf_event_exec();
@@ -1332,15 +1367,6 @@ void setup_new_exec(struct linux_binprm * bprm)
         */
        current->mm->task_size = TASK_SIZE;
 
-       /* install the new credentials */
-       if (!uid_eq(bprm->cred->uid, current_euid()) ||
-           !gid_eq(bprm->cred->gid, current_egid())) {
-               current->pdeath_signal = 0;
-       } else {
-               if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)
-                       set_dumpable(current->mm, suid_dumpable);
-       }
-
        /* An exec changes our domain. We are no longer part of the thread
           group */
        current->self_exec_id++;
@@ -1530,7 +1556,7 @@ int prepare_binprm(struct linux_binprm *bprm)
        retval = security_bprm_set_creds(bprm);
        if (retval)
                return retval;
-       bprm->cred_prepared = 1;
+       bprm->called_set_creds = 1;
 
        memset(bprm->buf, 0, BINPRM_BUF_SIZE);
        return kernel_read(bprm->file, bprm->buf, BINPRM_BUF_SIZE, &pos);
@@ -1719,9 +1745,9 @@ static int do_execveat_common(int fd, struct filename *filename,
                bprm->filename = filename->name;
        } else {
                if (filename->name[0] == '\0')
-                       pathbuf = kasprintf(GFP_TEMPORARY, "/dev/fd/%d", fd);
+                       pathbuf = kasprintf(GFP_KERNEL, "/dev/fd/%d", fd);
                else
-                       pathbuf = kasprintf(GFP_TEMPORARY, "/dev/fd/%d/%s",
+                       pathbuf = kasprintf(GFP_KERNEL, "/dev/fd/%d/%s",
                                            fd, filename->name);
                if (!pathbuf) {
                        retval = -ENOMEM;