Re: [RESEND PATCH] ptrace: take into account saved_sigmask in PTRACE_{GET,SET}SIGMASK

2019-03-20 Thread Oleg Nesterov
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

2019-03-19 Thread Andrew Morton
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

2019-03-19 Thread Dmitry V. Levin
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

2019-03-19 Thread Andrei Vagin
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

2019-02-02 Thread Andrei Vagin
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

2018-11-27 Thread Oleg Nesterov
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

2018-11-27 Thread Oleg Nesterov
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

2018-11-26 Thread Andrei Vagin
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

2018-11-26 Thread Andrei Vagin
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

2018-11-22 Thread Oleg Nesterov
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

2018-11-22 Thread Oleg Nesterov
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

2018-11-21 Thread Andrew Morton
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

2018-11-21 Thread Andrew Morton
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

2018-11-19 Thread Andrei Vagin
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

2018-11-19 Thread Andrei Vagin
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