aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorKees Cook <keescook@chromium.org>2012-07-30 17:39:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-07-30 20:25:11 -0400
commit9520628e8ceb69fa9a4aee6b57f22675d9e1b709 (patch)
treec8e1dbd5820e818eef930cf55cbd94dec941eb44 /fs/exec.c
parent779302e67835fe9a6b74327e54969ba59cb3478a (diff)
fs: make dumpable=2 require fully qualified path
When the suid_dumpable sysctl is set to "2", and there is no core dump pipe defined in the core_pattern sysctl, a local user can cause core files to be written to root-writable directories, potentially with user-controlled content. This means an admin can unknowningly reintroduce a variation of CVE-2006-2451, allowing local users to gain root privileges. $ cat /proc/sys/fs/suid_dumpable 2 $ cat /proc/sys/kernel/core_pattern core $ ulimit -c unlimited $ cd / $ ls -l core ls: cannot access core: No such file or directory $ touch core touch: cannot touch `core': Permission denied $ OHAI="evil-string-here" ping localhost >/dev/null 2>&1 & $ pid=$! $ sleep 1 $ kill -SEGV $pid $ ls -l core -rw------- 1 root kees 458752 Jun 21 11:35 core $ sudo strings core | grep evil OHAI=evil-string-here While cron has been fixed to abort reading a file when there is any parse error, there are still other sensitive directories that will read any file present and skip unparsable lines. Instead of introducing a suid_dumpable=3 mode and breaking all users of mode 2, this only disables the unsafe portion of mode 2 (writing to disk via relative path). Most users of mode 2 (e.g. Chrome OS) already use a core dump pipe handler, so this change will not break them. For the situations where a pipe handler is not defined but mode 2 is still active, crash dumps will only be written to fully qualified paths. If a relative path is defined (e.g. the default "core" pattern), dump attempts will trigger a printk yelling about the lack of a fully qualified path. Signed-off-by: Kees Cook <keescook@chromium.org> Cc: Alexander Viro <viro@zeniv.linux.org.uk> Cc: Alan Cox <alan@linux.intel.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Cc: Doug Ledford <dledford@redhat.com> Cc: Serge Hallyn <serge.hallyn@canonical.com> Cc: James Morris <james.l.morris@oracle.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/fs/exec.c b/fs/exec.c
index e95aeeddd25c..95aae3f9c036 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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) == 2) {
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);
@@ -2223,6 +2226,14 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
2223 if (cprm.limit < binfmt->min_coredump) 2226 if (cprm.limit < binfmt->min_coredump)
2224 goto fail_unlock; 2227 goto fail_unlock;
2225 2228
2229 if (need_nonrelative && cn.corename[0] != '/') {
2230 printk(KERN_WARNING "Pid %d(%s) can only dump core "\
2231 "to fully qualified path!\n",
2232 task_tgid_vnr(current), current->comm);
2233 printk(KERN_WARNING "Skipping core dump\n");
2234 goto fail_unlock;
2235 }
2236
2226 cprm.file = filp_open(cn.corename, 2237 cprm.file = filp_open(cn.corename,
2227 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 2238 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
2228 0600); 2239 0600);