aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-08-01 10:34:56 -0700
committerWilly Tarreau <w@1wt.eu>2009-09-13 08:46:29 +0200
commit1efc949ac0e96be60adbc137695f59ec0bc70ce6 (patch)
treee303d2358655218f47f7ea3d948877120c9668d1
parent096ed17f20affc2db0e307658c69b67433992a7a (diff)
downloadlinux-2.4-1efc949ac0e96be60adbc137695f59ec0bc70ce6.tar.gz
do_sigaltstack: avoid copying 'stack_t' as a structure to user space
(backported from 2.6 commit 0083fc2c50e6c5127c2802ad323adf8143ab7856) 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> Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--kernel/signal.c15
1 files changed, 8 insertions, 7 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index dff04d7d6dc55c..e392acc5472833 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1143,11 +1143,9 @@ do_sigaltstack (const stack_t *uss, stack_t *uoss, unsigned long sp)
stack_t oss;
int error;
- if (uoss) {
- oss.ss_sp = (void *) current->sas_ss_sp;
- oss.ss_size = current->sas_ss_size;
- oss.ss_flags = sas_ss_flags(sp);
- }
+ oss.ss_sp = (void *) current->sas_ss_sp;
+ oss.ss_size = current->sas_ss_size;
+ oss.ss_flags = sas_ss_flags(sp);
if (uss) {
void *ss_sp;
@@ -1190,13 +1188,16 @@ do_sigaltstack (const stack_t *uss, stack_t *uoss, unsigned long sp)
current->sas_ss_size = ss_size;
}
+ error = 0;
if (uoss) {
error = -EFAULT;
- if (copy_to_user(uoss, &oss, sizeof(oss)))
+ if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
goto out;
+ error = __put_user(oss.ss_sp, &uoss->ss_sp) |
+ __put_user(oss.ss_size, &uoss->ss_size) |
+ __put_user(oss.ss_flags, &uoss->ss_flags);
}
- error = 0;
out:
return error;
}