Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[S390] CVE-2008-1514: prevent ptrace padding area read/write in 31-bit mode

When running a 31-bit ptrace, on either an s390 or s390x kernel,
reads and writes into a padding area in struct user_regs_struct32
will result in a kernel panic.

This is also known as CVE-2008-1514.

Test case available here:
http://sources.redhat.com/cgi-bin/cvsweb.cgi/~checkout~/tests/ptrace-tests/tests/user-area-padding.c?cvsroot=systemtap

Steps to reproduce:
1) wget the above
2) gcc -o user-area-padding-31bit user-area-padding.c -Wall -ggdb2 -D_GNU_SOURCE -m31
3) ./user-area-padding-31bit
<panic>

Test status
-----------
Without patch, both s390 and s390x kernels panic. With patch, the test case,
as well as the gdb testsuite, pass without incident, padding area reads
returning zero, writes ignored.

Nb: original version returned -EINVAL on write attempts, which broke the
gdb test and made the test case slightly unhappy, Jan Kratochvil suggested
the change to return 0 on write attempts.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
Tested-by: Jan Kratochvil <jan.kratochvil@redhat.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Jarod Wilson and committed by
Martin Schwidefsky
3d6e48f4 82a28c79

+29
+1
arch/s390/kernel/compat_ptrace.h
··· 42 42 u32 gprs[NUM_GPRS]; 43 43 u32 acrs[NUM_ACRS]; 44 44 u32 orig_gpr2; 45 + /* nb: there's a 4-byte hole here */ 45 46 s390_fp_regs fp_regs; 46 47 /* 47 48 * These per registers are in here so that gdb can modify them
+28
arch/s390/kernel/ptrace.c
··· 170 170 */ 171 171 tmp = (addr_t) task_pt_regs(child)->orig_gpr2; 172 172 173 + } else if (addr < (addr_t) &dummy->regs.fp_regs) { 174 + /* 175 + * prevent reads of padding hole between 176 + * orig_gpr2 and fp_regs on s390. 177 + */ 178 + tmp = 0; 179 + 173 180 } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { 174 181 /* 175 182 * floating point regs. are stored in the thread structure ··· 276 269 * orig_gpr2 is stored on the kernel stack 277 270 */ 278 271 task_pt_regs(child)->orig_gpr2 = data; 272 + 273 + } else if (addr < (addr_t) &dummy->regs.fp_regs) { 274 + /* 275 + * prevent writes of padding hole between 276 + * orig_gpr2 and fp_regs on s390. 277 + */ 278 + return 0; 279 279 280 280 } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { 281 281 /* ··· 442 428 */ 443 429 tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); 444 430 431 + } else if (addr < (addr_t) &dummy32->regs.fp_regs) { 432 + /* 433 + * prevent reads of padding hole between 434 + * orig_gpr2 and fp_regs on s390. 435 + */ 436 + tmp = 0; 437 + 445 438 } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { 446 439 /* 447 440 * floating point regs. are stored in the thread structure ··· 534 513 * orig_gpr2 is stored on the kernel stack 535 514 */ 536 515 *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; 516 + 517 + } else if (addr < (addr_t) &dummy32->regs.fp_regs) { 518 + /* 519 + * prevent writess of padding hole between 520 + * orig_gpr2 and fp_regs on s390. 521 + */ 522 + return 0; 537 523 538 524 } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { 539 525 /*