diff options
| -rw-r--r-- | kernel/ptrace.c | 48 |
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 | ||
| 326 | static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data) | 326 | static 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 | ||
| 347 | static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data) | 344 | static 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 | } |
