aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/exec.c62
-rw-r--r--fs/proc/base.c2
2 files changed, 57 insertions, 7 deletions
diff --git a/fs/exec.c b/fs/exec.c
index 498f2b3dca20..7bdea7937ee8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1058,9 +1058,9 @@ int flush_old_exec(struct linux_binprm * bprm)
1058 current->sas_ss_sp = current->sas_ss_size = 0; 1058 current->sas_ss_sp = current->sas_ss_size = 0;
1059 1059
1060 if (current->euid == current->uid && current->egid == current->gid) 1060 if (current->euid == current->uid && current->egid == current->gid)
1061 current->mm->dumpable = 1; 1061 set_dumpable(current->mm, 1);
1062 else 1062 else
1063 current->mm->dumpable = suid_dumpable; 1063 set_dumpable(current->mm, suid_dumpable);
1064 1064
1065 name = bprm->filename; 1065 name = bprm->filename;
1066 1066
@@ -1088,7 +1088,7 @@ int flush_old_exec(struct linux_binprm * bprm)
1088 file_permission(bprm->file, MAY_READ) || 1088 file_permission(bprm->file, MAY_READ) ||
1089 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { 1089 (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) {
1090 suid_keys(current); 1090 suid_keys(current);
1091 current->mm->dumpable = suid_dumpable; 1091 set_dumpable(current->mm, suid_dumpable);
1092 } 1092 }
1093 1093
1094 /* An exec changes our domain. We are no longer part of the thread 1094 /* An exec changes our domain. We are no longer part of the thread
@@ -1665,6 +1665,56 @@ fail:
1665 return core_waiters; 1665 return core_waiters;
1666} 1666}
1667 1667
1668/*
1669 * set_dumpable converts traditional three-value dumpable to two flags and
1670 * stores them into mm->flags. It modifies lower two bits of mm->flags, but
1671 * these bits are not changed atomically. So get_dumpable can observe the
1672 * intermediate state. To avoid doing unexpected behavior, get get_dumpable
1673 * return either old dumpable or new one by paying attention to the order of
1674 * modifying the bits.
1675 *
1676 * dumpable | mm->flags (binary)
1677 * old new | initial interim final
1678 * ---------+-----------------------
1679 * 0 1 | 00 01 01
1680 * 0 2 | 00 10(*) 11
1681 * 1 0 | 01 00 00
1682 * 1 2 | 01 11 11
1683 * 2 0 | 11 10(*) 00
1684 * 2 1 | 11 11 01
1685 *
1686 * (*) get_dumpable regards interim value of 10 as 11.
1687 */
1688void set_dumpable(struct mm_struct *mm, int value)
1689{
1690 switch (value) {
1691 case 0:
1692 clear_bit(MMF_DUMPABLE, &mm->flags);
1693 smp_wmb();
1694 clear_bit(MMF_DUMP_SECURELY, &mm->flags);
1695 break;
1696 case 1:
1697 set_bit(MMF_DUMPABLE, &mm->flags);
1698 smp_wmb();
1699 clear_bit(MMF_DUMP_SECURELY, &mm->flags);
1700 break;
1701 case 2:
1702 set_bit(MMF_DUMP_SECURELY, &mm->flags);
1703 smp_wmb();
1704 set_bit(MMF_DUMPABLE, &mm->flags);
1705 break;
1706 }
1707}
1708EXPORT_SYMBOL_GPL(set_dumpable);
1709
1710int get_dumpable(struct mm_struct *mm)
1711{
1712 int ret;
1713
1714 ret = mm->flags & 0x3;
1715 return (ret >= 2) ? 2 : ret;
1716}
1717
1668int do_coredump(long signr, int exit_code, struct pt_regs * regs) 1718int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1669{ 1719{
1670 char corename[CORENAME_MAX_SIZE + 1]; 1720 char corename[CORENAME_MAX_SIZE + 1];
@@ -1683,7 +1733,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1683 if (!binfmt || !binfmt->core_dump) 1733 if (!binfmt || !binfmt->core_dump)
1684 goto fail; 1734 goto fail;
1685 down_write(&mm->mmap_sem); 1735 down_write(&mm->mmap_sem);
1686 if (!mm->dumpable) { 1736 if (!get_dumpable(mm)) {
1687 up_write(&mm->mmap_sem); 1737 up_write(&mm->mmap_sem);
1688 goto fail; 1738 goto fail;
1689 } 1739 }
@@ -1693,11 +1743,11 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
1693 * process nor do we know its entire history. We only know it 1743 * process nor do we know its entire history. We only know it
1694 * was tainted so we dump it as root in mode 2. 1744 * was tainted so we dump it as root in mode 2.
1695 */ 1745 */
1696 if (mm->dumpable == 2) { /* Setuid core dump mode */ 1746 if (get_dumpable(mm) == 2) { /* Setuid core dump mode */
1697 flag = O_EXCL; /* Stop rewrite attacks */ 1747 flag = O_EXCL; /* Stop rewrite attacks */
1698 current->fsuid = 0; /* Dump root private */ 1748 current->fsuid = 0; /* Dump root private */
1699 } 1749 }
1700 mm->dumpable = 0; 1750 set_dumpable(mm, 0);
1701 1751
1702 retval = coredump_wait(exit_code); 1752 retval = coredump_wait(exit_code);
1703 if (retval < 0) 1753 if (retval < 0)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 42cb4f5613b6..49b3ab0175e0 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1014,7 +1014,7 @@ static int task_dumpable(struct task_struct *task)
1014 task_lock(task); 1014 task_lock(task);
1015 mm = task->mm; 1015 mm = task->mm;
1016 if (mm) 1016 if (mm)
1017 dumpable = mm->dumpable; 1017 dumpable = get_dumpable(mm);
1018 task_unlock(task); 1018 task_unlock(task);
1019 if(dumpable == 1) 1019 if(dumpable == 1)
1020 return 1; 1020 return 1;