Re: [RESEND PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On 03/19, Andrei Vagin wrote: > > 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_GET_SIGMASK returns saved_sigmask > is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. Acked-by: Oleg Nesterov
Re: [RESEND PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On Wed, 20 Mar 2019 01:32:53 +0300 "Dmitry V. Levin" wrote: > On Tue, Mar 19, 2019 at 12:19:57PM -0700, Andrei Vagin wrote: > > 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_GET_SIGMASK returns saved_sigmask > > is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. > > If it's not too late, could somebody tweak the commit message so that > PTRACE_GET_SIGMASK becomes PTRACE_GETSIGMASK and "is it's set" is changed > to "if it's set", please? I made those changes to my copy.
Re: [RESEND PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On Tue, Mar 19, 2019 at 12:19:57PM -0700, Andrei Vagin wrote: > 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_GET_SIGMASK returns saved_sigmask > is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. If it's not too late, could somebody tweak the commit message so that PTRACE_GET_SIGMASK becomes PTRACE_GETSIGMASK and "is it's set" is changed to "if it's set", please? -- ldv signature.asc Description: PGP signature
[RESEND PATCH] 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_GET_SIGMASK returns saved_sigmask is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. Link: http://lkml.kernel.org/r/20181120060616.6043-1-ava...@gmail.com Fixes: 29000caecbe8 ("ptrace: add ability to get/set signal-blocked mask") Signed-off-by: Andrei Vagin Cc: Oleg Nesterov Cc: "Eric W. Biederman" Signed-off-by: Andrew Morton Signed-off-by: Stephen Rothwell --- Hello Andrew, This patch is in a queue for a long time and it looks like you are waiting ack from Oleg. He said the patch is fine: https://www.spinics.net/lists/kernel/msg2972154.html And promised to send a formal ack in reply to this email. include/linux/sched/signal.h | 18 ++ 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) set_thread_flag(TIF_RESTORE_SIGMASK); WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } + +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} + static inline void clear_restore_sigmask(void) { clear_thread_flag(TIF_RESTORE_SIGMASK); } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return test_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} static inline bool test_restore_sigmask(void) { return test_thread_flag(TIF_RESTORE_SIGMASK); @@ -439,6 +449,10 @@ static inline void set_restore_sigmask(void) current->restore_sigmask = true; WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + tsk->restore_sigmask = false; +} static inline void clear_restore_sigmask(void) { current->restore_sigmask = false; @@ -447,6 +461,10 @@ static inline bool test_restore_sigmask(void) { return current->restore_sigmask; } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return tsk->restore_sigmask; +} static inline bool test_and_clear_restore_sigmask(void) { 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 @@ #include #include #include +#include /* * Access another process' address space via ptrace. @@ -924,18 +925,26 @@ int ptrace_request(struct task_struct *child, long request, ret = ptrace_setsiginfo(child, ); break; - case PTRACE_GETSIGMASK: + case PTRACE_GETSIGMASK: { + sigset_t *mask; + if (addr != sizeof(sigset_t)) { ret = -EINVAL; break; } - if (copy_to_user(datavp, >blocked, sizeof(sigset_t))) + if (test_tsk_restore_sigmask(child)) + mask = >saved_sigmask; + else + mask = >blocked; + + if (copy_to_user(datavp, mask, sizeof(sigset_t))) ret = -EFAULT; else ret = 0; break; + } case PTRACE_SETSIGMASK: { sigset_t new_set; @@ -961,6 +970,8 @@ int ptrace_request(struct task_struct *child, long request, child->blocked = new_set; spin_unlock_irq(>sighand->siglock); + clear_tsk_restore_sigmask(child); + ret = 0; break; } -- 2.20.1
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On Wed, Nov 21, 2018 at 06:16:50PM -0800, Andrew Morton wrote: > On Mon, 19 Nov 2018 22:06:16 -0800 Andrei Vagin wrote: > > > 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_GET_SIGMASK returns saved_sigmask > > is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. > > Looks good to me, but what would I know. I'll await input from Eric > and/or Oleg (please). Hi Andrew, What is your plan for this patch? In the ~akpm/mmotm/series, I see a comment of waiting for ack from Oleg. Here was a feedback from Oleg: https://www.spinics.net/lists/kernel/msg2972154.html where he said: "Ok, I think the patch is fine". Is it enough or should I convince him to send a "real" ack? Thanks, Andrei > > > --- a/include/linux/sched/signal.h > > +++ b/include/linux/sched/signal.h > > @@ -417,10 +417,20 @@ static inline void set_restore_sigmask(void) > > set_thread_flag(TIF_RESTORE_SIGMASK); > > WARN_ON(!test_thread_flag(TIF_SIGPENDING)); > > } > > + > > +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) > > +{ > > + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); > > +} > > How irritating is it that this file uses "task" 85 times and "tsk" 19 > times? What did that gain us? This patch worsens things. > > Oh well.
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On 11/26, Andrei Vagin wrote: > > > IOW, could you please explain how PTRACE_SETSIGMASK should be used, and why > > it doesn't do something like > > > > CRIU uses PTRACE_SETSIGMASK when it injects a parasite code into a > target process. In this case, we have to be sure that when the process > is resumed by PTRACE_CONT, it will not start handling signals and > executing signal handlers. So iiuc CRUI uses PTRACE_SETSIGMASK to block all signals, run the parasite code, then restore the original sigmask. Assuming that CRIU also turns ERESTARTNOHAND into syscall-restart (I think it does ;) everything looks correct... OK, I think the patch is fine. Oleg.
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On 11/26, Andrei Vagin wrote: > > > IOW, could you please explain how PTRACE_SETSIGMASK should be used, and why > > it doesn't do something like > > > > CRIU uses PTRACE_SETSIGMASK when it injects a parasite code into a > target process. In this case, we have to be sure that when the process > is resumed by PTRACE_CONT, it will not start handling signals and > executing signal handlers. So iiuc CRUI uses PTRACE_SETSIGMASK to block all signals, run the parasite code, then restore the original sigmask. Assuming that CRIU also turns ERESTARTNOHAND into syscall-restart (I think it does ;) everything looks correct... OK, I think the patch is fine. Oleg.
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On Thu, Nov 22, 2018 at 12:47:52PM +0100, Oleg Nesterov wrote: > On 11/19, Andrei Vagin wrote: > > > > case PTRACE_SETSIGMASK: { > > sigset_t new_set; > > @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long > > request, > > child->blocked = new_set; > > spin_unlock_irq(>sighand->siglock); > > > > + clear_tsk_restore_sigmask(child); > > + > > I am not sure I understand this change... > > I forgot everything I knew about criu, but iiuc PTRACE_SETSIGMASK is used > at "restore" time, doesn't this mean that TIF_RESTORE_SIGMASK/restore_sigmask > can not be set? PTRACE_SETSIGMASK isn't used on restore. On restore, criu generates sigframe and calls sigreturn to restore registers, fpu state, sigmask and resume a process. When the kernel constructs a signal frame, it calls sigmask_to_save() to get a process signal mask. With this patch, PTRACE_GETSIGMASK returns the same signal mask what is returned by sigmask_to_save(). In CRIU, we don't need to set TIF_RESTORE_SIGMASK, because all processes are dumped when they are in user-space. > > IOW, could you please explain how PTRACE_SETSIGMASK should be used, and why > it doesn't do something like > CRIU uses PTRACE_SETSIGMASK when it injects a parasite code into a target process. In this case, we have to be sure that when the process is resumed by PTRACE_CONT, it will not start handling signals and executing signal handlers. > if (test_tsk_restore_sigmask(child)) > child->saved_sigmask = new_set; > else > child->blocked = new_set; > > which looks symmetrical to PTRACE_GETSIGMASK? If we set child->saved_sigmask, the child can start handling signals which are not set in child->blocked. > > Oleg. >
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On Thu, Nov 22, 2018 at 12:47:52PM +0100, Oleg Nesterov wrote: > On 11/19, Andrei Vagin wrote: > > > > case PTRACE_SETSIGMASK: { > > sigset_t new_set; > > @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long > > request, > > child->blocked = new_set; > > spin_unlock_irq(>sighand->siglock); > > > > + clear_tsk_restore_sigmask(child); > > + > > I am not sure I understand this change... > > I forgot everything I knew about criu, but iiuc PTRACE_SETSIGMASK is used > at "restore" time, doesn't this mean that TIF_RESTORE_SIGMASK/restore_sigmask > can not be set? PTRACE_SETSIGMASK isn't used on restore. On restore, criu generates sigframe and calls sigreturn to restore registers, fpu state, sigmask and resume a process. When the kernel constructs a signal frame, it calls sigmask_to_save() to get a process signal mask. With this patch, PTRACE_GETSIGMASK returns the same signal mask what is returned by sigmask_to_save(). In CRIU, we don't need to set TIF_RESTORE_SIGMASK, because all processes are dumped when they are in user-space. > > IOW, could you please explain how PTRACE_SETSIGMASK should be used, and why > it doesn't do something like > CRIU uses PTRACE_SETSIGMASK when it injects a parasite code into a target process. In this case, we have to be sure that when the process is resumed by PTRACE_CONT, it will not start handling signals and executing signal handlers. > if (test_tsk_restore_sigmask(child)) > child->saved_sigmask = new_set; > else > child->blocked = new_set; > > which looks symmetrical to PTRACE_GETSIGMASK? If we set child->saved_sigmask, the child can start handling signals which are not set in child->blocked. > > Oleg. >
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On 11/19, Andrei Vagin wrote: > > case PTRACE_SETSIGMASK: { > sigset_t new_set; > @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long > request, > child->blocked = new_set; > spin_unlock_irq(>sighand->siglock); > > + clear_tsk_restore_sigmask(child); > + I am not sure I understand this change... I forgot everything I knew about criu, but iiuc PTRACE_SETSIGMASK is used at "restore" time, doesn't this mean that TIF_RESTORE_SIGMASK/restore_sigmask can not be set? IOW, could you please explain how PTRACE_SETSIGMASK should be used, and why it doesn't do something like if (test_tsk_restore_sigmask(child)) child->saved_sigmask = new_set; else child->blocked = new_set; which looks symmetrical to PTRACE_GETSIGMASK? Oleg.
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On 11/19, Andrei Vagin wrote: > > case PTRACE_SETSIGMASK: { > sigset_t new_set; > @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long > request, > child->blocked = new_set; > spin_unlock_irq(>sighand->siglock); > > + clear_tsk_restore_sigmask(child); > + I am not sure I understand this change... I forgot everything I knew about criu, but iiuc PTRACE_SETSIGMASK is used at "restore" time, doesn't this mean that TIF_RESTORE_SIGMASK/restore_sigmask can not be set? IOW, could you please explain how PTRACE_SETSIGMASK should be used, and why it doesn't do something like if (test_tsk_restore_sigmask(child)) child->saved_sigmask = new_set; else child->blocked = new_set; which looks symmetrical to PTRACE_GETSIGMASK? Oleg.
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On Mon, 19 Nov 2018 22:06:16 -0800 Andrei Vagin wrote: > 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_GET_SIGMASK returns saved_sigmask > is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. Looks good to me, but what would I know. I'll await input from Eric and/or Oleg (please). > --- a/include/linux/sched/signal.h > +++ b/include/linux/sched/signal.h > @@ -417,10 +417,20 @@ static inline void set_restore_sigmask(void) > set_thread_flag(TIF_RESTORE_SIGMASK); > WARN_ON(!test_thread_flag(TIF_SIGPENDING)); > } > + > +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) > +{ > + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); > +} How irritating is it that this file uses "task" 85 times and "tsk" 19 times? What did that gain us? This patch worsens things. Oh well.
Re: [PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK
On Mon, 19 Nov 2018 22:06:16 -0800 Andrei Vagin wrote: > 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_GET_SIGMASK returns saved_sigmask > is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. Looks good to me, but what would I know. I'll await input from Eric and/or Oleg (please). > --- a/include/linux/sched/signal.h > +++ b/include/linux/sched/signal.h > @@ -417,10 +417,20 @@ static inline void set_restore_sigmask(void) > set_thread_flag(TIF_RESTORE_SIGMASK); > WARN_ON(!test_thread_flag(TIF_SIGPENDING)); > } > + > +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) > +{ > + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); > +} How irritating is it that this file uses "task" 85 times and "tsk" 19 times? What did that gain us? This patch worsens things. Oh well.
[PATCH] 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_GET_SIGMASK returns saved_sigmask is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. Cc: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Andrew Morton Fixes: 29000caecbe8 ("ptrace: add ability to get/set signal-blocked mask") Signed-off-by: Andrei Vagin --- include/linux/sched/signal.h | 18 ++ 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 1be35729c2c5..660d78c9af6c 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -417,10 +417,20 @@ static inline void set_restore_sigmask(void) set_thread_flag(TIF_RESTORE_SIGMASK); WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } + +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} + static inline void clear_restore_sigmask(void) { clear_thread_flag(TIF_RESTORE_SIGMASK); } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return test_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} static inline bool test_restore_sigmask(void) { return test_thread_flag(TIF_RESTORE_SIGMASK); @@ -438,6 +448,10 @@ static inline void set_restore_sigmask(void) current->restore_sigmask = true; WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + tsk->restore_sigmask = false; +} static inline void clear_restore_sigmask(void) { current->restore_sigmask = false; @@ -446,6 +460,10 @@ static inline bool test_restore_sigmask(void) { return current->restore_sigmask; } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return tsk->restore_sigmask; +} static inline bool test_and_clear_restore_sigmask(void) { if (!current->restore_sigmask) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 21fec73d45d4..fc0d667f5792 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * Access another process' address space via ptrace. @@ -925,18 +926,26 @@ int ptrace_request(struct task_struct *child, long request, ret = ptrace_setsiginfo(child, ); break; - case PTRACE_GETSIGMASK: + case PTRACE_GETSIGMASK: { + sigset_t *mask; + if (addr != sizeof(sigset_t)) { ret = -EINVAL; break; } - if (copy_to_user(datavp, >blocked, sizeof(sigset_t))) + if (test_tsk_restore_sigmask(child)) + mask = >saved_sigmask; + else + mask = >blocked; + + if (copy_to_user(datavp, mask, sizeof(sigset_t))) ret = -EFAULT; else ret = 0; break; + } case PTRACE_SETSIGMASK: { sigset_t new_set; @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long request, child->blocked = new_set; spin_unlock_irq(>sighand->siglock); + clear_tsk_restore_sigmask(child); + ret = 0; break; } -- 2.17.2
[PATCH] 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_GET_SIGMASK returns saved_sigmask is it's set. PTRACE_SETSIGMASK drops the TIF_RESTORE_SIGMASK flag. Cc: Oleg Nesterov Cc: "Eric W. Biederman" Cc: Andrew Morton Fixes: 29000caecbe8 ("ptrace: add ability to get/set signal-blocked mask") Signed-off-by: Andrei Vagin --- include/linux/sched/signal.h | 18 ++ 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 1be35729c2c5..660d78c9af6c 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -417,10 +417,20 @@ static inline void set_restore_sigmask(void) set_thread_flag(TIF_RESTORE_SIGMASK); WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } + +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + clear_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} + static inline void clear_restore_sigmask(void) { clear_thread_flag(TIF_RESTORE_SIGMASK); } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return test_tsk_thread_flag(tsk, TIF_RESTORE_SIGMASK); +} static inline bool test_restore_sigmask(void) { return test_thread_flag(TIF_RESTORE_SIGMASK); @@ -438,6 +448,10 @@ static inline void set_restore_sigmask(void) current->restore_sigmask = true; WARN_ON(!test_thread_flag(TIF_SIGPENDING)); } +static inline void clear_tsk_restore_sigmask(struct task_struct *tsk) +{ + tsk->restore_sigmask = false; +} static inline void clear_restore_sigmask(void) { current->restore_sigmask = false; @@ -446,6 +460,10 @@ static inline bool test_restore_sigmask(void) { return current->restore_sigmask; } +static inline bool test_tsk_restore_sigmask(struct task_struct *tsk) +{ + return tsk->restore_sigmask; +} static inline bool test_and_clear_restore_sigmask(void) { if (!current->restore_sigmask) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 21fec73d45d4..fc0d667f5792 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -29,6 +29,7 @@ #include #include #include +#include /* * Access another process' address space via ptrace. @@ -925,18 +926,26 @@ int ptrace_request(struct task_struct *child, long request, ret = ptrace_setsiginfo(child, ); break; - case PTRACE_GETSIGMASK: + case PTRACE_GETSIGMASK: { + sigset_t *mask; + if (addr != sizeof(sigset_t)) { ret = -EINVAL; break; } - if (copy_to_user(datavp, >blocked, sizeof(sigset_t))) + if (test_tsk_restore_sigmask(child)) + mask = >saved_sigmask; + else + mask = >blocked; + + if (copy_to_user(datavp, mask, sizeof(sigset_t))) ret = -EFAULT; else ret = 0; break; + } case PTRACE_SETSIGMASK: { sigset_t new_set; @@ -962,6 +971,8 @@ int ptrace_request(struct task_struct *child, long request, child->blocked = new_set; spin_unlock_irq(>sighand->siglock); + clear_tsk_restore_sigmask(child); + ret = 0; break; } -- 2.17.2