aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2008-04-20 16:10:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-21 18:53:41 -0400
commite16b27816462de700f9508d86954410c41105dc2 (patch)
treef3827a23a43dcaad06362d511ac20d576b9128d5 /kernel/ptrace.c
parent553a56726be86c09cfa53c84da1ea0e2043e364e (diff)
ptrace: compat_ptrace_request siginfo
This adds support for PTRACE_GETSIGINFO and PTRACE_SETSIGINFO in compat_ptrace_request. It relies on existing arch definitions for copy_siginfo_to_user32 and copy_siginfo_from_user32. On powerpc, this fixes a longstanding regression of 32-bit ptrace calls on 64-bit kernels vs native calls (64-bit calls or 32-bit kernels). This can be seen in a 32-bit call using PTRACE_GETSIGINFO to examine e.g. siginfo_t.si_addr from a signal that sets it. (This was broken as of 2.6.24 and, I presume, many or all prior versions.) Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c48
1 files changed, 35 insertions, 13 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index fdb34e86f923..67e392ed5496 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -323,9 +323,8 @@ static int ptrace_setoptions(struct task_struct *child, long data)
323 return (data & ~PTRACE_O_MASK) ? -EINVAL : 0; 323 return (data & ~PTRACE_O_MASK) ? -EINVAL : 0;
324} 324}
325 325
326static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data) 326static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
327{ 327{
328 siginfo_t lastinfo;
329 int error = -ESRCH; 328 int error = -ESRCH;
330 329
331 read_lock(&tasklist_lock); 330 read_lock(&tasklist_lock);
@@ -333,31 +332,25 @@ static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data)
333 error = -EINVAL; 332 error = -EINVAL;
334 spin_lock_irq(&child->sighand->siglock); 333 spin_lock_irq(&child->sighand->siglock);
335 if (likely(child->last_siginfo != NULL)) { 334 if (likely(child->last_siginfo != NULL)) {
336 lastinfo = *child->last_siginfo; 335 *info = *child->last_siginfo;
337 error = 0; 336 error = 0;
338 } 337 }
339 spin_unlock_irq(&child->sighand->siglock); 338 spin_unlock_irq(&child->sighand->siglock);
340 } 339 }
341 read_unlock(&tasklist_lock); 340 read_unlock(&tasklist_lock);
342 if (!error)
343 return copy_siginfo_to_user(data, &lastinfo);
344 return error; 341 return error;
345} 342}
346 343
347static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data) 344static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
348{ 345{
349 siginfo_t newinfo;
350 int error = -ESRCH; 346 int error = -ESRCH;
351 347
352 if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
353 return -EFAULT;
354
355 read_lock(&tasklist_lock); 348 read_lock(&tasklist_lock);
356 if (likely(child->sighand != NULL)) { 349 if (likely(child->sighand != NULL)) {
357 error = -EINVAL; 350 error = -EINVAL;
358 spin_lock_irq(&child->sighand->siglock); 351 spin_lock_irq(&child->sighand->siglock);
359 if (likely(child->last_siginfo != NULL)) { 352 if (likely(child->last_siginfo != NULL)) {
360 *child->last_siginfo = newinfo; 353 *child->last_siginfo = *info;
361 error = 0; 354 error = 0;
362 } 355 }
363 spin_unlock_irq(&child->sighand->siglock); 356 spin_unlock_irq(&child->sighand->siglock);
@@ -424,6 +417,7 @@ int ptrace_request(struct task_struct *child, long request,
424 long addr, long data) 417 long addr, long data)
425{ 418{
426 int ret = -EIO; 419 int ret = -EIO;
420 siginfo_t siginfo;
427 421
428 switch (request) { 422 switch (request) {
429 case PTRACE_PEEKTEXT: 423 case PTRACE_PEEKTEXT:
@@ -442,12 +436,22 @@ int ptrace_request(struct task_struct *child, long request,
442 case PTRACE_GETEVENTMSG: 436 case PTRACE_GETEVENTMSG:
443 ret = put_user(child->ptrace_message, (unsigned long __user *) data); 437 ret = put_user(child->ptrace_message, (unsigned long __user *) data);
444 break; 438 break;
439
445 case PTRACE_GETSIGINFO: 440 case PTRACE_GETSIGINFO:
446 ret = ptrace_getsiginfo(child, (siginfo_t __user *) data); 441 ret = ptrace_getsiginfo(child, &siginfo);
442 if (!ret)
443 ret = copy_siginfo_to_user((siginfo_t __user *) data,
444 &siginfo);
447 break; 445 break;
446
448 case PTRACE_SETSIGINFO: 447 case PTRACE_SETSIGINFO:
449 ret = ptrace_setsiginfo(child, (siginfo_t __user *) data); 448 if (copy_from_user(&siginfo, (siginfo_t __user *) data,
449 sizeof siginfo))
450 ret = -EFAULT;
451 else
452 ret = ptrace_setsiginfo(child, &siginfo);
450 break; 453 break;
454
451 case PTRACE_DETACH: /* detach a process that was attached. */ 455 case PTRACE_DETACH: /* detach a process that was attached. */
452 ret = ptrace_detach(child, data); 456 ret = ptrace_detach(child, data);
453 break; 457 break;
@@ -616,6 +620,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
616{ 620{
617 compat_ulong_t __user *datap = compat_ptr(data); 621 compat_ulong_t __user *datap = compat_ptr(data);
618 compat_ulong_t word; 622 compat_ulong_t word;
623 siginfo_t siginfo;
619 int ret; 624 int ret;
620 625
621 switch (request) { 626 switch (request) {
@@ -638,6 +643,23 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
638 ret = put_user((compat_ulong_t) child->ptrace_message, datap); 643 ret = put_user((compat_ulong_t) child->ptrace_message, datap);
639 break; 644 break;
640 645
646 case PTRACE_GETSIGINFO:
647 ret = ptrace_getsiginfo(child, &siginfo);
648 if (!ret)
649 ret = copy_siginfo_to_user32(
650 (struct compat_siginfo __user *) datap,
651 &siginfo);
652 break;
653
654 case PTRACE_SETSIGINFO:
655 memset(&siginfo, 0, sizeof siginfo);
656 if (copy_siginfo_from_user32(
657 &siginfo, (struct compat_siginfo __user *) datap))
658 ret = -EFAULT;
659 else
660 ret = ptrace_setsiginfo(child, &siginfo);
661 break;
662
641 default: 663 default:
642 ret = ptrace_request(child, request, addr, data); 664 ret = ptrace_request(child, request, addr, data);
643 } 665 }