diff options
author | Jarod Wilson <jwilson@redhat.com> | 2008-09-09 06:38:56 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-09-09 06:39:06 -0400 |
commit | 3d6e48f43340343d97839eadb1ab7b6a3ea98797 (patch) | |
tree | 81d1c8709ef5a1dc8cd8c6e44072928f7c0f903a /arch/s390/kernel | |
parent | 82a28c794f27aac17d7a3ebd7f14d731a11a5532 (diff) |
[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>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/compat_ptrace.h | 1 | ||||
-rw-r--r-- | arch/s390/kernel/ptrace.c | 28 |
2 files changed, 29 insertions, 0 deletions
diff --git a/arch/s390/kernel/compat_ptrace.h b/arch/s390/kernel/compat_ptrace.h index cde81fa64f89..a2be3a978d5c 100644 --- a/arch/s390/kernel/compat_ptrace.h +++ b/arch/s390/kernel/compat_ptrace.h | |||
@@ -42,6 +42,7 @@ struct user_regs_struct32 | |||
42 | u32 gprs[NUM_GPRS]; | 42 | u32 gprs[NUM_GPRS]; |
43 | u32 acrs[NUM_ACRS]; | 43 | u32 acrs[NUM_ACRS]; |
44 | u32 orig_gpr2; | 44 | u32 orig_gpr2; |
45 | /* nb: there's a 4-byte hole here */ | ||
45 | s390_fp_regs fp_regs; | 46 | s390_fp_regs fp_regs; |
46 | /* | 47 | /* |
47 | * These per registers are in here so that gdb can modify them | 48 | * These per registers are in here so that gdb can modify them |
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 2815bfe348a6..c8b08289eb87 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c | |||
@@ -170,6 +170,13 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) | |||
170 | */ | 170 | */ |
171 | tmp = (addr_t) task_pt_regs(child)->orig_gpr2; | 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 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 180 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
174 | /* | 181 | /* |
175 | * floating point regs. are stored in the thread structure | 182 | * floating point regs. are stored in the thread structure |
@@ -270,6 +277,13 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) | |||
270 | */ | 277 | */ |
271 | task_pt_regs(child)->orig_gpr2 = data; | 278 | task_pt_regs(child)->orig_gpr2 = data; |
272 | 279 | ||
280 | } else if (addr < (addr_t) &dummy->regs.fp_regs) { | ||
281 | /* | ||
282 | * prevent writes of padding hole between | ||
283 | * orig_gpr2 and fp_regs on s390. | ||
284 | */ | ||
285 | return 0; | ||
286 | |||
273 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { | 287 | } else if (addr < (addr_t) (&dummy->regs.fp_regs + 1)) { |
274 | /* | 288 | /* |
275 | * floating point regs. are stored in the thread structure | 289 | * floating point regs. are stored in the thread structure |
@@ -428,6 +442,13 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) | |||
428 | */ | 442 | */ |
429 | tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); | 443 | tmp = *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4); |
430 | 444 | ||
445 | } else if (addr < (addr_t) &dummy32->regs.fp_regs) { | ||
446 | /* | ||
447 | * prevent reads of padding hole between | ||
448 | * orig_gpr2 and fp_regs on s390. | ||
449 | */ | ||
450 | tmp = 0; | ||
451 | |||
431 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 452 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
432 | /* | 453 | /* |
433 | * floating point regs. are stored in the thread structure | 454 | * floating point regs. are stored in the thread structure |
@@ -514,6 +535,13 @@ static int __poke_user_compat(struct task_struct *child, | |||
514 | */ | 535 | */ |
515 | *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; | 536 | *(__u32*)((addr_t) &task_pt_regs(child)->orig_gpr2 + 4) = tmp; |
516 | 537 | ||
538 | } else if (addr < (addr_t) &dummy32->regs.fp_regs) { | ||
539 | /* | ||
540 | * prevent writess of padding hole between | ||
541 | * orig_gpr2 and fp_regs on s390. | ||
542 | */ | ||
543 | return 0; | ||
544 | |||
517 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { | 545 | } else if (addr < (addr_t) (&dummy32->regs.fp_regs + 1)) { |
518 | /* | 546 | /* |
519 | * floating point regs. are stored in the thread structure | 547 | * floating point regs. are stored in the thread structure |