diff options
author | Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | 2013-06-28 09:49:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-06-29 14:29:08 -0400 |
commit | 706b23bde27a391f0974df2a8351661770fa2e07 (patch) | |
tree | 2b8d6be33dda49dcfc9ed8a5a688db4e8f56ac4c /kernel/ptrace.c | |
parent | bd2931b5cff6a3bf39bfe15fae051fb8229c0029 (diff) |
Fix: kernel/ptrace.c: ptrace_peek_siginfo() missing __put_user() validation
This __put_user() could be used by unprivileged processes to write into
kernel memory. The issue here is that even if copy_siginfo_to_user()
fails, the error code is not checked before __put_user() is executed.
Luckily, ptrace_peek_siginfo() has been added within the 3.10-rc cycle,
so it has not hit a stable release yet.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Andrey Vagin <avagin@openvz.org>
Cc: Roland McGrath <roland@redhat.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Dave Jones <davej@redhat.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Pedro Alves <palves@redhat.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 20 |
1 files changed, 11 insertions, 9 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index aed981a3f69c..335a7ae697f5 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -665,20 +665,22 @@ static int ptrace_peek_siginfo(struct task_struct *child, | |||
665 | if (unlikely(is_compat_task())) { | 665 | if (unlikely(is_compat_task())) { |
666 | compat_siginfo_t __user *uinfo = compat_ptr(data); | 666 | compat_siginfo_t __user *uinfo = compat_ptr(data); |
667 | 667 | ||
668 | ret = copy_siginfo_to_user32(uinfo, &info); | 668 | if (copy_siginfo_to_user32(uinfo, &info) || |
669 | ret |= __put_user(info.si_code, &uinfo->si_code); | 669 | __put_user(info.si_code, &uinfo->si_code)) { |
670 | ret = -EFAULT; | ||
671 | break; | ||
672 | } | ||
673 | |||
670 | } else | 674 | } else |
671 | #endif | 675 | #endif |
672 | { | 676 | { |
673 | siginfo_t __user *uinfo = (siginfo_t __user *) data; | 677 | siginfo_t __user *uinfo = (siginfo_t __user *) data; |
674 | 678 | ||
675 | ret = copy_siginfo_to_user(uinfo, &info); | 679 | if (copy_siginfo_to_user(uinfo, &info) || |
676 | ret |= __put_user(info.si_code, &uinfo->si_code); | 680 | __put_user(info.si_code, &uinfo->si_code)) { |
677 | } | 681 | ret = -EFAULT; |
678 | 682 | break; | |
679 | if (ret) { | 683 | } |
680 | ret = -EFAULT; | ||
681 | break; | ||
682 | } | 684 | } |
683 | 685 | ||
684 | data += sizeof(siginfo_t); | 686 | data += sizeof(siginfo_t); |