diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 42 |
1 files changed, 27 insertions, 15 deletions
@@ -2002,17 +2002,17 @@ static void coredump_finish(struct mm_struct *mm) | |||
2002 | void set_dumpable(struct mm_struct *mm, int value) | 2002 | void set_dumpable(struct mm_struct *mm, int value) |
2003 | { | 2003 | { |
2004 | switch (value) { | 2004 | switch (value) { |
2005 | case 0: | 2005 | case SUID_DUMPABLE_DISABLED: |
2006 | clear_bit(MMF_DUMPABLE, &mm->flags); | 2006 | clear_bit(MMF_DUMPABLE, &mm->flags); |
2007 | smp_wmb(); | 2007 | smp_wmb(); |
2008 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); | 2008 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); |
2009 | break; | 2009 | break; |
2010 | case 1: | 2010 | case SUID_DUMPABLE_ENABLED: |
2011 | set_bit(MMF_DUMPABLE, &mm->flags); | 2011 | set_bit(MMF_DUMPABLE, &mm->flags); |
2012 | smp_wmb(); | 2012 | smp_wmb(); |
2013 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); | 2013 | clear_bit(MMF_DUMP_SECURELY, &mm->flags); |
2014 | break; | 2014 | break; |
2015 | case 2: | 2015 | case SUID_DUMPABLE_SAFE: |
2016 | set_bit(MMF_DUMP_SECURELY, &mm->flags); | 2016 | set_bit(MMF_DUMP_SECURELY, &mm->flags); |
2017 | smp_wmb(); | 2017 | smp_wmb(); |
2018 | set_bit(MMF_DUMPABLE, &mm->flags); | 2018 | set_bit(MMF_DUMPABLE, &mm->flags); |
@@ -2025,7 +2025,7 @@ static int __get_dumpable(unsigned long mm_flags) | |||
2025 | int ret; | 2025 | int ret; |
2026 | 2026 | ||
2027 | ret = mm_flags & MMF_DUMPABLE_MASK; | 2027 | ret = mm_flags & MMF_DUMPABLE_MASK; |
2028 | return (ret >= 2) ? 2 : ret; | 2028 | return (ret > SUID_DUMPABLE_ENABLED) ? SUID_DUMPABLE_SAFE : ret; |
2029 | } | 2029 | } |
2030 | 2030 | ||
2031 | int get_dumpable(struct mm_struct *mm) | 2031 | int get_dumpable(struct mm_struct *mm) |
@@ -2111,6 +2111,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2111 | int retval = 0; | 2111 | int retval = 0; |
2112 | int flag = 0; | 2112 | int flag = 0; |
2113 | int ispipe; | 2113 | int ispipe; |
2114 | bool need_nonrelative = false; | ||
2114 | static atomic_t core_dump_count = ATOMIC_INIT(0); | 2115 | static atomic_t core_dump_count = ATOMIC_INIT(0); |
2115 | struct coredump_params cprm = { | 2116 | struct coredump_params cprm = { |
2116 | .signr = signr, | 2117 | .signr = signr, |
@@ -2136,14 +2137,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2136 | if (!cred) | 2137 | if (!cred) |
2137 | goto fail; | 2138 | goto fail; |
2138 | /* | 2139 | /* |
2139 | * We cannot trust fsuid as being the "true" uid of the | 2140 | * We cannot trust fsuid as being the "true" uid of the process |
2140 | * process nor do we know its entire history. We only know it | 2141 | * nor do we know its entire history. We only know it was tainted |
2141 | * was tainted so we dump it as root in mode 2. | 2142 | * so we dump it as root in mode 2, and only into a controlled |
2143 | * environment (pipe handler or fully qualified path). | ||
2142 | */ | 2144 | */ |
2143 | if (__get_dumpable(cprm.mm_flags) == 2) { | 2145 | if (__get_dumpable(cprm.mm_flags) == SUID_DUMPABLE_SAFE) { |
2144 | /* Setuid core dump mode */ | 2146 | /* Setuid core dump mode */ |
2145 | flag = O_EXCL; /* Stop rewrite attacks */ | 2147 | flag = O_EXCL; /* Stop rewrite attacks */ |
2146 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ | 2148 | cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ |
2149 | need_nonrelative = true; | ||
2147 | } | 2150 | } |
2148 | 2151 | ||
2149 | retval = coredump_wait(exit_code, &core_state); | 2152 | retval = coredump_wait(exit_code, &core_state); |
@@ -2171,15 +2174,16 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2171 | } | 2174 | } |
2172 | 2175 | ||
2173 | if (cprm.limit == 1) { | 2176 | if (cprm.limit == 1) { |
2174 | /* | 2177 | /* See umh_pipe_setup() which sets RLIMIT_CORE = 1. |
2178 | * | ||
2175 | * Normally core limits are irrelevant to pipes, since | 2179 | * Normally core limits are irrelevant to pipes, since |
2176 | * we're not writing to the file system, but we use | 2180 | * we're not writing to the file system, but we use |
2177 | * cprm.limit of 1 here as a speacial value. Any | 2181 | * cprm.limit of 1 here as a speacial value, this is a |
2178 | * non-1 limit gets set to RLIM_INFINITY below, but | 2182 | * consistent way to catch recursive crashes. |
2179 | * a limit of 0 skips the dump. This is a consistent | 2183 | * We can still crash if the core_pattern binary sets |
2180 | * way to catch recursive crashes. We can still crash | 2184 | * RLIM_CORE = !1, but it runs as root, and can do |
2181 | * if the core_pattern binary sets RLIM_CORE = !1 | 2185 | * lots of stupid things. |
2182 | * but it runs as root, and can do lots of stupid things | 2186 | * |
2183 | * Note that we use task_tgid_vnr here to grab the pid | 2187 | * Note that we use task_tgid_vnr here to grab the pid |
2184 | * of the process group leader. That way we get the | 2188 | * of the process group leader. That way we get the |
2185 | * right pid if a thread in a multi-threaded | 2189 | * right pid if a thread in a multi-threaded |
@@ -2223,6 +2227,14 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) | |||
2223 | if (cprm.limit < binfmt->min_coredump) | 2227 | if (cprm.limit < binfmt->min_coredump) |
2224 | goto fail_unlock; | 2228 | goto fail_unlock; |
2225 | 2229 | ||
2230 | if (need_nonrelative && cn.corename[0] != '/') { | ||
2231 | printk(KERN_WARNING "Pid %d(%s) can only dump core "\ | ||
2232 | "to fully qualified path!\n", | ||
2233 | task_tgid_vnr(current), current->comm); | ||
2234 | printk(KERN_WARNING "Skipping core dump\n"); | ||
2235 | goto fail_unlock; | ||
2236 | } | ||
2237 | |||
2226 | cprm.file = filp_open(cn.corename, | 2238 | cprm.file = filp_open(cn.corename, |
2227 | O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, | 2239 | O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, |
2228 | 0600); | 2240 | 0600); |