aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@ftp.linux.org.uk>2010-09-20 10:13:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-09-20 13:44:37 -0400
commit5f4ad04a1e805d14de080ff9d5384b4d20518a9a (patch)
tree63252b79b48b7dfd29d9a8081a34c858dab1de74
parent20cd514d0f3d288d968217028ca67b70e707d896 (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.c38
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))