aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
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 }