diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-06-11 21:44:45 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-06-11 21:44:45 -0400 |
commit | aa7235483a838be79b7c22a86b0dc4cb12ee5dd6 (patch) | |
tree | d89a5978232e8dfaf47953a1b7d9ce7599b892b0 /kernel/ptrace.c | |
parent | 4d8f5f91b8a608980b173ef3382913c7405f82c3 (diff) | |
parent | f6581f5b55141a95657ef5742cf6a6bfa20a109f (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull ptrace fixes from Eric Biederman:
"This is just two very minor fixes:
- prevent ptrace from reading unitialized kernel memory found twice
by syzkaller
- restore a missing smp_rmb in ptrace_may_access and add comment tp
it so it is not removed by accident again.
Apologies for being a little slow about getting this to you, I am
still figuring out how to develop with a little baby in the house"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
ptrace: restore smp_rmb() in __ptrace_may_access()
signal/ptrace: Don't leak unitialized kernel memory with PTRACE_PEEK_SIGINFO
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r-- | kernel/ptrace.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 5710d07e67cf..8456b6e2205f 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -324,6 +324,16 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
324 | return -EPERM; | 324 | return -EPERM; |
325 | ok: | 325 | ok: |
326 | rcu_read_unlock(); | 326 | rcu_read_unlock(); |
327 | /* | ||
328 | * If a task drops privileges and becomes nondumpable (through a syscall | ||
329 | * like setresuid()) while we are trying to access it, we must ensure | ||
330 | * that the dumpability is read after the credentials; otherwise, | ||
331 | * we may be able to attach to a task that we shouldn't be able to | ||
332 | * attach to (as if the task had dropped privileges without becoming | ||
333 | * nondumpable). | ||
334 | * Pairs with a write barrier in commit_creds(). | ||
335 | */ | ||
336 | smp_rmb(); | ||
327 | mm = task->mm; | 337 | mm = task->mm; |
328 | if (mm && | 338 | if (mm && |
329 | ((get_dumpable(mm) != SUID_DUMP_USER) && | 339 | ((get_dumpable(mm) != SUID_DUMP_USER) && |
@@ -705,6 +715,10 @@ static int ptrace_peek_siginfo(struct task_struct *child, | |||
705 | if (arg.nr < 0) | 715 | if (arg.nr < 0) |
706 | return -EINVAL; | 716 | return -EINVAL; |
707 | 717 | ||
718 | /* Ensure arg.off fits in an unsigned long */ | ||
719 | if (arg.off > ULONG_MAX) | ||
720 | return 0; | ||
721 | |||
708 | if (arg.flags & PTRACE_PEEKSIGINFO_SHARED) | 722 | if (arg.flags & PTRACE_PEEKSIGINFO_SHARED) |
709 | pending = &child->signal->shared_pending; | 723 | pending = &child->signal->shared_pending; |
710 | else | 724 | else |
@@ -712,18 +726,20 @@ static int ptrace_peek_siginfo(struct task_struct *child, | |||
712 | 726 | ||
713 | for (i = 0; i < arg.nr; ) { | 727 | for (i = 0; i < arg.nr; ) { |
714 | kernel_siginfo_t info; | 728 | kernel_siginfo_t info; |
715 | s32 off = arg.off + i; | 729 | unsigned long off = arg.off + i; |
730 | bool found = false; | ||
716 | 731 | ||
717 | spin_lock_irq(&child->sighand->siglock); | 732 | spin_lock_irq(&child->sighand->siglock); |
718 | list_for_each_entry(q, &pending->list, list) { | 733 | list_for_each_entry(q, &pending->list, list) { |
719 | if (!off--) { | 734 | if (!off--) { |
735 | found = true; | ||
720 | copy_siginfo(&info, &q->info); | 736 | copy_siginfo(&info, &q->info); |
721 | break; | 737 | break; |
722 | } | 738 | } |
723 | } | 739 | } |
724 | spin_unlock_irq(&child->sighand->siglock); | 740 | spin_unlock_irq(&child->sighand->siglock); |
725 | 741 | ||
726 | if (off >= 0) /* beyond the end of the list */ | 742 | if (!found) /* beyond the end of the list */ |
727 | break; | 743 | break; |
728 | 744 | ||
729 | #ifdef CONFIG_COMPAT | 745 | #ifdef CONFIG_COMPAT |