Intel FB: obvious changes and corrections
[safe/jmp/linux-2.6] / fs / exec.c
index 498f2b3..073b0b8 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,7 +50,6 @@
 #include <linux/tsacct_kern.h>
 #include <linux/cn_proc.h>
 #include <linux/audit.h>
-#include <linux/signalfd.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -780,18 +779,10 @@ static int de_thread(struct task_struct *tsk)
        int count;
 
        /*
-        * Tell all the sighand listeners that this sighand has
-        * been detached. The signalfd_detach() function grabs the
-        * sighand lock, if signal listeners are present on the sighand.
-        */
-       signalfd_detach(tsk);
-
-       /*
         * If we don't share sighandlers, then we aren't sharing anything
         * and we can just re-use it all.
         */
        if (atomic_read(&oldsighand->count) <= 1) {
-               BUG_ON(atomic_read(&sig->count) != 1);
                exit_itimers(sig);
                return 0;
        }
@@ -934,8 +925,6 @@ no_thread_group:
        if (leader)
                release_task(leader);
 
-       BUG_ON(atomic_read(&sig->count) != 1);
-
        if (atomic_read(&oldsighand->count) == 1) {
                /*
                 * Now that we nuked the rest of the thread group,
@@ -1058,9 +1047,9 @@ int flush_old_exec(struct linux_binprm * bprm)
        current->sas_ss_sp = current->sas_ss_size = 0;
 
        if (current->euid == current->uid && current->egid == current->gid)
-               current->mm->dumpable = 1;
+               set_dumpable(current->mm, 1);
        else
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
 
        name = bprm->filename;
 
@@ -1084,11 +1073,14 @@ int flush_old_exec(struct linux_binprm * bprm)
         */
        current->mm->task_size = TASK_SIZE;
 
-       if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || 
-           file_permission(bprm->file, MAY_READ) ||
-           (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
+       if (bprm->e_uid != current->euid || bprm->e_gid != current->egid) {
+               suid_keys(current);
+               set_dumpable(current->mm, suid_dumpable);
+               current->pdeath_signal = 0;
+       } else if (file_permission(bprm->file, MAY_READ) ||
+                       (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
                suid_keys(current);
-               current->mm->dumpable = suid_dumpable;
+               set_dumpable(current->mm, suid_dumpable);
        }
 
        /* An exec changes our domain. We are no longer part of the thread
@@ -1177,8 +1169,10 @@ void compute_creds(struct linux_binprm *bprm)
 {
        int unsafe;
 
-       if (bprm->e_uid != current->uid)
+       if (bprm->e_uid != current->uid) {
                suid_keys(current);
+               current->pdeath_signal = 0;
+       }
        exec_keys(current);
 
        task_lock(current);
@@ -1665,6 +1659,56 @@ fail:
        return core_waiters;
 }
 
+/*
+ * 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.
+ */
+void set_dumpable(struct mm_struct *mm, int value)
+{
+       switch (value) {
+       case 0:
+               clear_bit(MMF_DUMPABLE, &mm->flags);
+               smp_wmb();
+               clear_bit(MMF_DUMP_SECURELY, &mm->flags);
+               break;
+       case 1:
+               set_bit(MMF_DUMPABLE, &mm->flags);
+               smp_wmb();
+               clear_bit(MMF_DUMP_SECURELY, &mm->flags);
+               break;
+       case 2:
+               set_bit(MMF_DUMP_SECURELY, &mm->flags);
+               smp_wmb();
+               set_bit(MMF_DUMPABLE, &mm->flags);
+               break;
+       }
+}
+EXPORT_SYMBOL_GPL(set_dumpable);
+
+int get_dumpable(struct mm_struct *mm)
+{
+       int ret;
+
+       ret = mm->flags & 0x3;
+       return (ret >= 2) ? 2 : ret;
+}
+
 int do_coredump(long signr, int exit_code, struct pt_regs * regs)
 {
        char corename[CORENAME_MAX_SIZE + 1];
@@ -1683,7 +1727,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
        if (!binfmt || !binfmt->core_dump)
                goto fail;
        down_write(&mm->mmap_sem);
-       if (!mm->dumpable) {
+       if (!get_dumpable(mm)) {
                up_write(&mm->mmap_sem);
                goto fail;
        }
@@ -1693,11 +1737,11 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
         *      process nor do we know its entire history. We only know it
         *      was tainted so we dump it as root in mode 2.
         */
-       if (mm->dumpable == 2) {        /* Setuid core dump mode */
+       if (get_dumpable(mm) == 2) {    /* Setuid core dump mode */
                flag = O_EXCL;          /* Stop rewrite attacks */
                current->fsuid = 0;     /* Dump root private */
        }
-       mm->dumpable = 0;
+       set_dumpable(mm, 0);
 
        retval = coredump_wait(exit_code);
        if (retval < 0)