CHROMIUM: config: re-sync kernel config after dma-buf kds separation
[cascardo/linux.git] / fs / exec.c
index b1fd202..e5b8c4b 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/file.h>
 #include <linux/fdtable.h>
+#include <linux/freezer.h>
 #include <linux/mm.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
@@ -56,6 +57,8 @@
 #include <linux/oom.h>
 #include <linux/compat.h>
 
+#include <trace/events/fs.h>
+
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/tlb.h>
@@ -785,6 +788,8 @@ struct file *open_exec(const char *name)
 
        fsnotify_open(file);
 
+       trace_open_exec(name);
+
        err = deny_write_access(file);
        if (err)
                goto exit;
@@ -1245,6 +1250,13 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
                        bprm->unsafe |= LSM_UNSAFE_PTRACE;
        }
 
+       /*
+        * This isn't strictly necessary, but it makes it harder for LSMs to
+        * mess up.
+        */
+       if (current->no_new_privs)
+               bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
+
        n_fs = 1;
        spin_lock(&p->fs->lock);
        rcu_read_lock();
@@ -1288,7 +1300,8 @@ int prepare_binprm(struct linux_binprm *bprm)
        bprm->cred->euid = current_euid();
        bprm->cred->egid = current_egid();
 
-       if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)) {
+       if (!(bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) &&
+           !current->no_new_privs) {
                /* Set-uid? */
                if (mode & S_ISUID) {
                        bprm->per_clear |= PER_CLEAR_ON_SETID;
@@ -1826,7 +1839,6 @@ static int zap_process(struct task_struct *start, int exit_code)
        struct task_struct *t;
        int nr = 0;
 
-       start->signal->flags = SIGNAL_GROUP_EXIT;
        start->signal->group_exit_code = exit_code;
        start->signal->group_stop_count = 0;
 
@@ -1843,8 +1855,8 @@ static int zap_process(struct task_struct *start, int exit_code)
        return nr;
 }
 
-static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
-                               struct core_state *core_state, int exit_code)
+static int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
+                       struct core_state *core_state, int exit_code)
 {
        struct task_struct *g, *p;
        unsigned long flags;
@@ -1854,6 +1866,10 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
        if (!signal_group_exit(tsk->signal)) {
                mm->core_state = core_state;
                nr = zap_process(tsk, exit_code);
+               tsk->signal->group_exit_task = tsk;
+               /* ignore all signals except SIGKILL, see prepare_signal() */
+               tsk->signal->flags = SIGNAL_GROUP_COREDUMP;
+               clear_tsk_thread_flag(tsk, TIF_SIGPENDING);
        }
        spin_unlock_irq(&tsk->sighand->siglock);
        if (unlikely(nr < 0))
@@ -1903,6 +1919,7 @@ static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm,
                                if (unlikely(p->mm == mm)) {
                                        lock_task_sighand(p, &flags);
                                        nr += zap_process(p, exit_code);
+                                       p->signal->flags = SIGNAL_GROUP_EXIT;
                                        unlock_task_sighand(p, &flags);
                                }
                                break;
@@ -1936,11 +1953,18 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
        return core_waiters;
 }
 
-static void coredump_finish(struct mm_struct *mm)
+static void coredump_finish(struct mm_struct *mm, bool core_dumped)
 {
        struct core_thread *curr, *next;
        struct task_struct *task;
 
+       spin_lock_irq(&current->sighand->siglock);
+       if (core_dumped && !__fatal_signal_pending(current))
+               current->signal->group_exit_code |= 0x80;
+       current->signal->group_exit_task = NULL;
+       current->signal->flags = SIGNAL_GROUP_EXIT;
+       spin_unlock_irq(&current->sighand->siglock);
+
        next = mm->core_state->dumper.next;
        while ((curr = next) != NULL) {
                next = curr->next;
@@ -2021,10 +2045,24 @@ static void wait_for_dump_helpers(struct file *file)
        pipe->readers++;
        pipe->writers--;
 
-       while ((pipe->readers > 1) && (!signal_pending(current))) {
+       while (pipe->readers > 1) {
+               unsigned long flags;
+
                wake_up_interruptible_sync(&pipe->wait);
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
                pipe_wait(pipe);
+
+               pipe_unlock(pipe);
+               try_to_freeze();
+               pipe_lock(pipe);
+
+               if (fatal_signal_pending(current))
+                       break;
+
+               /* Clear fake signal from freeze_task(). */
+               spin_lock_irqsave(&current->sighand->siglock, flags);
+               recalc_sigpending();
+               spin_unlock_irqrestore(&current->sighand->siglock, flags);
        }
 
        pipe->readers--;
@@ -2089,6 +2127,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        int retval = 0;
        int flag = 0;
        int ispipe;
+       bool core_dumped = false;
        static atomic_t core_dump_count = ATOMIC_INIT(0);
        struct coredump_params cprm = {
                .signr = signr,
@@ -2130,12 +2169,6 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
 
        old_cred = override_creds(cred);
 
-       /*
-        * Clear any false indication of pending signals that might
-        * be seen by the filesystem code called to write the core file.
-        */
-       clear_thread_flag(TIF_SIGPENDING);
-
        ispipe = format_corename(&cn, signr);
 
        if (ispipe) {
@@ -2230,9 +2263,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                        goto close_fail;
        }
 
-       retval = binfmt->core_dump(&cprm);
-       if (retval)
-               current->signal->group_exit_code |= 0x80;
+       core_dumped = binfmt->core_dump(&cprm);
 
        if (ispipe && core_pipe_limit)
                wait_for_dump_helpers(cprm.file);
@@ -2245,7 +2276,7 @@ fail_dropcount:
 fail_unlock:
        kfree(cn.corename);
 fail_corename:
-       coredump_finish(mm);
+       coredump_finish(mm, core_dumped);
        revert_creds(old_cred);
 fail_creds:
        put_cred(cred);