aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-08-01 13:34:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-08-01 13:46:52 -0400
commit0083fc2c50e6c5127c2802ad323adf8143ab7856 (patch)
tree0ec735c46d8be4ae4c637243b126feba0be2ebe8 /kernel
parented680c4ad478d0fee9740f7d029087f181346564 (diff)
do_sigaltstack: avoid copying 'stack_t' as a structure to user space
Ulrich Drepper correctly points out that there is generally padding in the structure on 64-bit hosts, and that copying the structure from kernel to user space can leak information from the kernel stack in those padding bytes. Avoid the whole issue by just copying the three members one by one instead, which also means that the function also can avoid the need for a stack frame. This also happens to match how we copy the new structure from user space, so it all even makes sense. [ The obvious solution of adding a memset() generates horrid code, gcc does really stupid things. ] Reported-by: Ulrich Drepper <drepper@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/signal.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index ccf1ceedaebe..f268372c0cc0 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -2454,11 +2454,9 @@ do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long s
2454 stack_t oss; 2454 stack_t oss;
2455 int error; 2455 int error;
2456 2456
2457 if (uoss) { 2457 oss.ss_sp = (void __user *) current->sas_ss_sp;
2458 oss.ss_sp = (void __user *) current->sas_ss_sp; 2458 oss.ss_size = current->sas_ss_size;
2459 oss.ss_size = current->sas_ss_size; 2459 oss.ss_flags = sas_ss_flags(sp);
2460 oss.ss_flags = sas_ss_flags(sp);
2461 }
2462 2460
2463 if (uss) { 2461 if (uss) {
2464 void __user *ss_sp; 2462 void __user *ss_sp;
@@ -2501,13 +2499,16 @@ do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long s
2501 current->sas_ss_size = ss_size; 2499 current->sas_ss_size = ss_size;
2502 } 2500 }
2503 2501
2502 error = 0;
2504 if (uoss) { 2503 if (uoss) {
2505 error = -EFAULT; 2504 error = -EFAULT;
2506 if (copy_to_user(uoss, &oss, sizeof(oss))) 2505 if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
2507 goto out; 2506 goto out;
2507 error = __put_user(oss.ss_sp, &uoss->ss_sp) |
2508 __put_user(oss.ss_size, &uoss->ss_size) |
2509 __put_user(oss.ss_flags, &uoss->ss_flags);
2508 } 2510 }
2509 2511
2510 error = 0;
2511out: 2512out:
2512 return error; 2513 return error;
2513} 2514}