netfilter: nf_nat_h323: fix crash in nf_ct_unlink_expect_report()
[cascardo/linux.git] / fs / exec.c
index 7ea097f..e1529b4 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -62,7 +62,6 @@
 
 #include <trace/events/task.h>
 #include "internal.h"
-#include "coredump.h"
 
 #include <trace/events/sched.h>
 
@@ -843,7 +842,6 @@ static int exec_mmap(struct mm_struct *mm)
        tsk->active_mm = mm;
        activate_mm(active_mm, mm);
        task_unlock(tsk);
-       arch_pick_mmap_layout(mm);
        if (old_mm) {
                up_read(&old_mm->mmap_sem);
                BUG_ON(active_mm != old_mm);
@@ -1088,8 +1086,8 @@ int flush_old_exec(struct linux_binprm * bprm)
        bprm->mm = NULL;                /* We're using it now */
 
        set_fs(USER_DS);
-       current->flags &=
-               ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | PF_NOFREEZE);
+       current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD |
+                                       PF_NOFREEZE | PF_NO_SETAFFINITY);
        flush_thread();
        current->personality &= ~bprm->per_clear;
 
@@ -1139,9 +1137,7 @@ void setup_new_exec(struct linux_binprm * bprm)
 
        /* An exec changes our domain. We are no longer part of the thread
           group */
-
        current->self_exec_id++;
-                       
        flush_signal_handlers(current, 0);
        do_close_on_exec(current->files);
 }
@@ -1173,6 +1169,10 @@ void free_bprm(struct linux_binprm *bprm)
                mutex_unlock(&current->signal->cred_guard_mutex);
                abort_creds(bprm->cred);
        }
+       if (bprm->file) {
+               allow_write_access(bprm->file);
+               fput(bprm->file);
+       }
        /* If a binfmt changed the interp, free it. */
        if (bprm->interp != bprm->filename)
                kfree(bprm->interp);
@@ -1224,11 +1224,10 @@ EXPORT_SYMBOL(install_exec_creds);
  * - the caller must hold ->cred_guard_mutex to protect against
  *   PTRACE_ATTACH
  */
-static int check_unsafe_exec(struct linux_binprm *bprm)
+static void check_unsafe_exec(struct linux_binprm *bprm)
 {
        struct task_struct *p = current, *t;
        unsigned n_fs;
-       int res = 0;
 
        if (p->ptrace) {
                if (p->ptrace & PT_PTRACE_CAP)
@@ -1244,31 +1243,25 @@ static int check_unsafe_exec(struct linux_binprm *bprm)
        if (current->no_new_privs)
                bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS;
 
+       t = p;
        n_fs = 1;
        spin_lock(&p->fs->lock);
        rcu_read_lock();
-       for (t = next_thread(p); t != p; t = next_thread(t)) {
+       while_each_thread(p, t) {
                if (t->fs == p->fs)
                        n_fs++;
        }
        rcu_read_unlock();
 
-       if (p->fs->users > n_fs) {
+       if (p->fs->users > n_fs)
                bprm->unsafe |= LSM_UNSAFE_SHARE;
-       } else {
-               res = -EAGAIN;
-               if (!p->fs->in_exec) {
-                       p->fs->in_exec = 1;
-                       res = 1;
-               }
-       }
+       else
+               p->fs->in_exec = 1;
        spin_unlock(&p->fs->lock);
-
-       return res;
 }
 
-/* 
- * Fill the binprm structure from the inode. 
+/*
+ * Fill the binprm structure from the inode.
  * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes
  *
  * This may be called multiple times for binary chains (scripts for example).
@@ -1430,14 +1423,7 @@ static int exec_binprm(struct linux_binprm *bprm)
                audit_bprm(bprm);
                trace_sched_process_exec(current, old_pid, bprm);
                ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
-               current->did_exec = 1;
                proc_exec_connector(current);
-
-               if (bprm->file) {
-                       allow_write_access(bprm->file);
-                       fput(bprm->file);
-                       bprm->file = NULL; /* to catch use-after-free */
-               }
        }
 
        return ret;
@@ -1453,7 +1439,6 @@ static int do_execve_common(const char *filename,
        struct linux_binprm *bprm;
        struct file *file;
        struct files_struct *displaced;
-       bool clear_in_exec;
        int retval;
 
        /*
@@ -1485,10 +1470,7 @@ static int do_execve_common(const char *filename,
        if (retval)
                goto out_free;
 
-       retval = check_unsafe_exec(bprm);
-       if (retval < 0)
-               goto out_free;
-       clear_in_exec = retval;
+       check_unsafe_exec(bprm);
        current->in_execve = 1;
 
        file = open_exec(filename);
@@ -1504,7 +1486,7 @@ static int do_execve_common(const char *filename,
 
        retval = bprm_mm_init(bprm);
        if (retval)
-               goto out_file;
+               goto out_unmark;
 
        bprm->argc = count(argv, MAX_ARG_STRINGS);
        if ((retval = bprm->argc) < 0)
@@ -1551,15 +1533,8 @@ out:
                mmput(bprm->mm);
        }
 
-out_file:
-       if (bprm->file) {
-               allow_write_access(bprm->file);
-               fput(bprm->file);
-       }
-
 out_unmark:
-       if (clear_in_exec)
-               current->fs->in_exec = 0;
+       current->fs->in_exec = 0;
        current->in_execve = 0;
 
 out_free:
@@ -1609,67 +1584,22 @@ void set_binfmt(struct linux_binfmt *new)
        if (new)
                __module_get(new->module);
 }
-
 EXPORT_SYMBOL(set_binfmt);
 
 /*
- * set_dumpable converts traditional three-value dumpable to two flags and
- * stores them into mm->flags.  It modifies lower two bits of mm->flags, but
- * these bits are not changed atomically.  So get_dumpable can observe the
- * intermediate state.  To avoid doing unexpected behavior, get get_dumpable
- * return either old dumpable or new one by paying attention to the order of
- * modifying the bits.
- *
- * dumpable |   mm->flags (binary)
- * old  new | initial interim  final
- * ---------+-----------------------
- *  0    1  |   00      01      01
- *  0    2  |   00      10(*)   11
- *  1    0  |   01      00      00
- *  1    2  |   01      11      11
- *  2    0  |   11      10(*)   00
- *  2    1  |   11      11      01
- *
- * (*) get_dumpable regards interim value of 10 as 11.
+ * set_dumpable stores three-value SUID_DUMP_* into mm->flags.
  */
 void set_dumpable(struct mm_struct *mm, int value)
 {
-       switch (value) {
-       case SUID_DUMP_DISABLE:
-               clear_bit(MMF_DUMPABLE, &mm->flags);
-               smp_wmb();
-               clear_bit(MMF_DUMP_SECURELY, &mm->flags);
-               break;
-       case SUID_DUMP_USER:
-               set_bit(MMF_DUMPABLE, &mm->flags);
-               smp_wmb();
-               clear_bit(MMF_DUMP_SECURELY, &mm->flags);
-               break;
-       case SUID_DUMP_ROOT:
-               set_bit(MMF_DUMP_SECURELY, &mm->flags);
-               smp_wmb();
-               set_bit(MMF_DUMPABLE, &mm->flags);
-               break;
-       }
-}
-
-int __get_dumpable(unsigned long mm_flags)
-{
-       int ret;
+       unsigned long old, new;
 
-       ret = mm_flags & MMF_DUMPABLE_MASK;
-       return (ret > SUID_DUMP_USER) ? SUID_DUMP_ROOT : ret;
-}
+       if (WARN_ON((unsigned)value > SUID_DUMP_ROOT))
+               return;
 
-/*
- * This returns the actual value of the suid_dumpable flag. For things
- * that are using this for checking for privilege transitions, it must
- * test against SUID_DUMP_USER rather than treating it as a boolean
- * value.
- */
-int get_dumpable(struct mm_struct *mm)
-{
-       return __get_dumpable(mm->flags);
+       do {
+               old = ACCESS_ONCE(mm->flags);
+               new = (old & ~MMF_DUMPABLE_MASK) | value;
+       } while (cmpxchg(&mm->flags, old, new) != old);
 }
 
 SYSCALL_DEFINE3(execve,