diff options
author | Al Viro <viro@ftp.linux.org.uk> | 2010-09-20 10:13:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-09-20 13:44:37 -0400 |
commit | 5f4ad04a1e805d14de080ff9d5384b4d20518a9a (patch) | |
tree | 63252b79b48b7dfd29d9a8081a34c858dab1de74 | |
parent | 20cd514d0f3d288d968217028ca67b70e707d896 (diff) |
frv: fix address verification holes in setup_frame/setup_rt_frame
a) sa_handler might be maliciously set to point to kernel memory;
blindly dereferencing it in FDPIC case is a Bad Idea(tm).
b) I'm not sure you need that set_fs(USER_DS) there at all, but if you
do, you'd better do it *before* checking the frame you've decided to
use with access_ok(), lest sigaltstack() becomes a convenient
roothole.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | arch/frv/kernel/signal.c | 38 |
1 files changed, 22 insertions, 16 deletions
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 7fc29615ef01..5fb2d0661c78 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c | |||
@@ -253,6 +253,8 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) | |||
253 | struct sigframe __user *frame; | 253 | struct sigframe __user *frame; |
254 | int rsig; | 254 | int rsig; |
255 | 255 | ||
256 | set_fs(USER_DS); | ||
257 | |||
256 | frame = get_sigframe(ka, sizeof(*frame)); | 258 | frame = get_sigframe(ka, sizeof(*frame)); |
257 | 259 | ||
258 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 260 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
@@ -296,22 +298,23 @@ static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set) | |||
296 | (unsigned long) (frame->retcode + 2)); | 298 | (unsigned long) (frame->retcode + 2)); |
297 | } | 299 | } |
298 | 300 | ||
299 | /* set up registers for signal handler */ | 301 | /* Set up registers for the signal handler */ |
300 | __frame->sp = (unsigned long) frame; | ||
301 | __frame->lr = (unsigned long) &frame->retcode; | ||
302 | __frame->gr8 = sig; | ||
303 | |||
304 | if (current->personality & FDPIC_FUNCPTRS) { | 302 | if (current->personality & FDPIC_FUNCPTRS) { |
305 | struct fdpic_func_descriptor __user *funcptr = | 303 | struct fdpic_func_descriptor __user *funcptr = |
306 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | 304 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; |
307 | __get_user(__frame->pc, &funcptr->text); | 305 | struct fdpic_func_descriptor desc; |
308 | __get_user(__frame->gr15, &funcptr->GOT); | 306 | if (copy_from_user(&desc, funcptr, sizeof(desc))) |
307 | goto give_sigsegv; | ||
308 | __frame->pc = desc.text; | ||
309 | __frame->gr15 = desc.GOT; | ||
309 | } else { | 310 | } else { |
310 | __frame->pc = (unsigned long) ka->sa.sa_handler; | 311 | __frame->pc = (unsigned long) ka->sa.sa_handler; |
311 | __frame->gr15 = 0; | 312 | __frame->gr15 = 0; |
312 | } | 313 | } |
313 | 314 | ||
314 | set_fs(USER_DS); | 315 | __frame->sp = (unsigned long) frame; |
316 | __frame->lr = (unsigned long) &frame->retcode; | ||
317 | __frame->gr8 = sig; | ||
315 | 318 | ||
316 | /* the tracer may want to single-step inside the handler */ | 319 | /* the tracer may want to single-step inside the handler */ |
317 | if (test_thread_flag(TIF_SINGLESTEP)) | 320 | if (test_thread_flag(TIF_SINGLESTEP)) |
@@ -341,6 +344,8 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
341 | struct rt_sigframe __user *frame; | 344 | struct rt_sigframe __user *frame; |
342 | int rsig; | 345 | int rsig; |
343 | 346 | ||
347 | set_fs(USER_DS); | ||
348 | |||
344 | frame = get_sigframe(ka, sizeof(*frame)); | 349 | frame = get_sigframe(ka, sizeof(*frame)); |
345 | 350 | ||
346 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | 351 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
@@ -395,22 +400,23 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
395 | } | 400 | } |
396 | 401 | ||
397 | /* Set up registers for signal handler */ | 402 | /* Set up registers for signal handler */ |
398 | __frame->sp = (unsigned long) frame; | ||
399 | __frame->lr = (unsigned long) &frame->retcode; | ||
400 | __frame->gr8 = sig; | ||
401 | __frame->gr9 = (unsigned long) &frame->info; | ||
402 | |||
403 | if (current->personality & FDPIC_FUNCPTRS) { | 403 | if (current->personality & FDPIC_FUNCPTRS) { |
404 | struct fdpic_func_descriptor __user *funcptr = | 404 | struct fdpic_func_descriptor __user *funcptr = |
405 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; | 405 | (struct fdpic_func_descriptor __user *) ka->sa.sa_handler; |
406 | __get_user(__frame->pc, &funcptr->text); | 406 | struct fdpic_func_descriptor desc; |
407 | __get_user(__frame->gr15, &funcptr->GOT); | 407 | if (copy_from_user(&desc, funcptr, sizeof(desc))) |
408 | goto give_sigsegv; | ||
409 | __frame->pc = desc.text; | ||
410 | __frame->gr15 = desc.GOT; | ||
408 | } else { | 411 | } else { |
409 | __frame->pc = (unsigned long) ka->sa.sa_handler; | 412 | __frame->pc = (unsigned long) ka->sa.sa_handler; |
410 | __frame->gr15 = 0; | 413 | __frame->gr15 = 0; |
411 | } | 414 | } |
412 | 415 | ||
413 | set_fs(USER_DS); | 416 | __frame->sp = (unsigned long) frame; |
417 | __frame->lr = (unsigned long) &frame->retcode; | ||
418 | __frame->gr8 = sig; | ||
419 | __frame->gr9 = (unsigned long) &frame->info; | ||
414 | 420 | ||
415 | /* the tracer may want to single-step inside the handler */ | 421 | /* the tracer may want to single-step inside the handler */ |
416 | if (test_thread_flag(TIF_SINGLESTEP)) | 422 | if (test_thread_flag(TIF_SINGLESTEP)) |