diff options
| author | Andrei Vagin <avagin@gmail.com> | 2019-03-28 23:44:13 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-29 13:01:37 -0400 |
| commit | fcfc2aa0185f4a731d05a21e9f359968fdfd02e7 (patch) | |
| tree | be2e72904e527207f223eeb070b94062999ebdbf | |
| parent | eebf36480678f948b3ed15d56ca7b8e6194e7c18 (diff) | |
ptrace: take into account saved_sigmask in PTRACE{GET,SET}SIGMASK
There are a few system calls (pselect, ppoll, etc) which replace a task
sigmask while they are running in a kernel-space
When a task calls one of these syscalls, the kernel saves a current
sigmask in task->saved_sigmask and sets a syscall sigmask.
On syscall-exit-stop, ptrace traps a task before restoring the
saved_sigmask, so PTRACE_GETSIGMASK returns the syscall sigmask and
PTRACE_SETSIGMASK does nothing, because its sigmask is replaced by
saved_sigmask, when the task returns to user-space.
This patch fixes this problem. PTRACE_GETSIGMASK returns saved_sigmask
if it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag.
Link: http://lkml.kernel.org/r/20181120060616.6043-1-avagin@gmail.com
Fixes: 29000caecbe8 ("ptrace: add ability to get/set signal-blocked mask")
Signed-off-by: Andrei Vagin <avagin@gmail.com>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/sched/signal.h | 18 | ||||
| -rw-r--r-- | kernel/ptrace.c | 15 |
2 files changed, 31 insertions, 2 deletions
diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index ae5655197698..e412c092c1e8 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h | |||
| @@ -418,10 +418,20 @@ static inline void set_restore_sigmask(void) | |||
| 418 | set_thread_flag(TIF_RESTORE_SIGMASK); | 418 | set_thread_flag(TIF_RESTORE_SIGMASK); |
| 419 | WARN_ON(!test_thread_flag(TIF_SIGPENDING)); | 419 | WARN_ON(!test_thread_flag(TIF_SIGPENDING)); |
| 420 | } | 420 | } |
| 421 | |||
| 422 | static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) | ||
| 423 | { | ||
| 424 | clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); | ||
| 425 | } | ||
| 426 | |||
| 421 | static inline void clear_restore_sigmask(void) | 427 | static inline void clear_restore_sigmask(void) |
| 422 | { | 428 | { |
| 423 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 429 | clear_thread_flag(TIF_RESTORE_SIGMASK); |
| 424 | } | 430 | } |
| 431 | static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) | ||
| 432 | { | ||
| 433 | return test_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); | ||
| 434 | } | ||
| 425 | static inline bool test_restore_sigmask(void) | 435 | static inline bool test_restore_sigmask(void) |
| 426 | { | 436 | { |
| 427 | return test_thread_flag(TIF_RESTORE_SIGMASK); | 437 | return test_thread_flag(TIF_RESTORE_SIGMASK); |
| @@ -439,6 +449,10 @@ static inline void set_restore_sigmask(void) | |||
| 439 | current->restore_sigmask = true; | 449 | current->restore_sigmask = true; |
| 440 | WARN_ON(!test_thread_flag(TIF_SIGPENDING)); | 450 | WARN_ON(!test_thread_flag(TIF_SIGPENDING)); |
| 441 | } | 451 | } |
| 452 | static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) | ||
| 453 | { | ||
| 454 | tsk->restore_sigmask = false; | ||
| 455 | } | ||
| 442 | static inline void clear_restore_sigmask(void) | 456 | static inline void clear_restore_sigmask(void) |
| 443 | { | 457 | { |
| 444 | current->restore_sigmask = false; | 458 | current->restore_sigmask = false; |
| @@ -447,6 +461,10 @@ static inline bool test_restore_sigmask(void) | |||
| 447 | { | 461 | { |
| 448 | return current->restore_sigmask; | 462 | return current->restore_sigmask; |
| 449 | } | 463 | } |
| 464 | static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) | ||
| 465 | { | ||
| 466 | return tsk->restore_sigmask; | ||
| 467 | } | ||
| 450 | static inline bool test_and_clear_restore_sigmask(void) | 468 | static inline bool test_and_clear_restore_sigmask(void) |
| 451 | { | 469 | { |
| 452 | if (!current->restore_sigmask) | 470 | if (!current->restore_sigmask) |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 771e93f9c43f..6f357f4fc859 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/hw_breakpoint.h> | 29 | #include <linux/hw_breakpoint.h> |
| 30 | #include <linux/cn_proc.h> | 30 | #include <linux/cn_proc.h> |
| 31 | #include <linux/compat.h> | 31 | #include <linux/compat.h> |
| 32 | #include <linux/sched/signal.h> | ||
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * Access another process' address space via ptrace. | 35 | * Access another process' address space via ptrace. |
| @@ -924,18 +925,26 @@ int ptrace_request(struct task_struct *child, long request, | |||
| 924 | ret = ptrace_setsiginfo(child, &siginfo); | 925 | ret = ptrace_setsiginfo(child, &siginfo); |
| 925 | break; | 926 | break; |
| 926 | 927 | ||
| 927 | case PTRACE_GETSIGMASK: | 928 | case PTRACE_GETSIGMASK: { |
| 929 | sigset_t *mask; | ||
| 930 | |||
| 928 | if (addr != sizeof(sigset_t)) { | 931 | if (addr != sizeof(sigset_t)) { |
| 929 | ret = -EINVAL; | 932 | ret = -EINVAL; |
| 930 | break; | 933 | break; |
| 931 | } | 934 | } |
| 932 | 935 | ||
| 933 | if (copy_to_user(datavp, &child->blocked, sizeof(sigset_t))) | 936 | if (test_tsk_restore_sigmask(child)) |
| 937 | mask = &child->saved_sigmask; | ||
| 938 | else | ||
| 939 | mask = &child->blocked; | ||
| 940 | |||
| 941 | if (copy_to_user(datavp, mask, sizeof(sigset_t))) | ||
| 934 | ret = -EFAULT; | 942 | ret = -EFAULT; |
| 935 | else | 943 | else |
| 936 | ret = 0; | 944 | ret = 0; |
| 937 | 945 | ||
| 938 | break; | 946 | break; |
| 947 | } | ||
| 939 | 948 | ||
| 940 | case PTRACE_SETSIGMASK: { | 949 | case PTRACE_SETSIGMASK: { |
| 941 | sigset_t new_set; | 950 | sigset_t new_set; |
| @@ -961,6 +970,8 @@ int ptrace_request(struct task_struct *child, long request, | |||
| 961 | child->blocked = new_set; | 970 | child->blocked = new_set; |
| 962 | spin_unlock_irq(&child->sighand->siglock); | 971 | spin_unlock_irq(&child->sighand->siglock); |
| 963 | 972 | ||
| 973 | clear_tsk_restore_sigmask(child); | ||
| 974 | |||
| 964 | ret = 0; | 975 | ret = 0; |
| 965 | break; | 976 | break; |
| 966 | } | 977 | } |
