Re: fork(2), PT_ATTACH & SIGTRAP

2021-03-22 Thread Mark Kettenis
> Date: Sun, 21 Mar 2021 16:56:47 +0100
> From: Martin Pieuchot 
> 
> On 21/03/21(Sun) 13:42, Mark Kettenis wrote:
> > > Date: Sat, 20 Mar 2021 13:10:17 +0100
> > > From: Martin Pieuchot 
> > > 
> > > On SP systems, like bluhm@'s armv7 regression machine, the kern/ptrace2
> > > test is failing due to a subtle behavior.  Diff below makes it pass.
> > > 
> > > http://bluhm.genua.de/regress/results/2021-03-19T15%3A17%3A02Z/logs/sys/kern/ptrace2/make.log
> > > 
> > > The failing test does a fork(2) and the parent issues a PT_ATTACH on the
> > > child before it has been scheduled for the first time.  Then the parent
> > > goes to sleep in waitpid() and when the child starts executing the check
> > > below overwrites the ptrace(2)-received SIGSTOP by a SIGTRAP.
> > > 
> > > This scenario doesn't seem to happen on MP machine because the child
> > > starts to execute itself on a different core right after sys_fork() is
> > > finished.
> > > 
> > > What is the purpose of this check?  Should it be relaxed or removed?
> > 
> > This is part of PT_SET_EVENT_MASK/PTRACE_FORK support:
> > 
> > https://github.com/openbsd/src/commit/f38bed7f869bd3503530c554b4860228ea4e8641
> > 
> > When reporting of the PTRACE_FORK event is requested, the debugger
> > expects to see a SIGTRAP in both the parent and the child.  The code
> > expects that the only way to have PS_TRACED set in the child from the
> > start is when PTRACE_FORK is requested.  But the failing test shows
> > there is a race with PT_ATTACH.
> 
> Thanks for the explanation.
> 
> > I think the solution is to have fork1() only run fork_return() if the
> > FORK_PTRACE flag is set, and use run child_return() otherwise.
> 
> Diff below does that and prevent the race, ok?

ok kettenis@

> Index: kern/kern_fork.c
> ===
> RCS file: /cvs/src/sys/kern/kern_fork.c,v
> retrieving revision 1.234
> diff -u -p -r1.234 kern_fork.c
> --- kern/kern_fork.c  15 Feb 2021 09:35:59 -  1.234
> +++ kern/kern_fork.c  21 Mar 2021 15:55:26 -
> @@ -95,12 +95,15 @@ fork_return(void *arg)
>  int
>  sys_fork(struct proc *p, void *v, register_t *retval)
>  {
> + void (*func)(void *) = child_return;
>   int flags;
>  
>   flags = FORK_FORK;
> - if (p->p_p->ps_ptmask & PTRACE_FORK)
> + if (p->p_p->ps_ptmask & PTRACE_FORK) {
>   flags |= FORK_PTRACE;
> - return fork1(p, flags, fork_return, NULL, retval, NULL);
> + func = fork_return;
> + }
> + return fork1(p, flags, func, NULL, retval, NULL);
>  }
>  
>  int
> 



Re: fork(2), PT_ATTACH & SIGTRAP

2021-03-21 Thread Martin Pieuchot
On 21/03/21(Sun) 13:42, Mark Kettenis wrote:
> > Date: Sat, 20 Mar 2021 13:10:17 +0100
> > From: Martin Pieuchot 
> > 
> > On SP systems, like bluhm@'s armv7 regression machine, the kern/ptrace2
> > test is failing due to a subtle behavior.  Diff below makes it pass.
> > 
> > http://bluhm.genua.de/regress/results/2021-03-19T15%3A17%3A02Z/logs/sys/kern/ptrace2/make.log
> > 
> > The failing test does a fork(2) and the parent issues a PT_ATTACH on the
> > child before it has been scheduled for the first time.  Then the parent
> > goes to sleep in waitpid() and when the child starts executing the check
> > below overwrites the ptrace(2)-received SIGSTOP by a SIGTRAP.
> > 
> > This scenario doesn't seem to happen on MP machine because the child
> > starts to execute itself on a different core right after sys_fork() is
> > finished.
> > 
> > What is the purpose of this check?  Should it be relaxed or removed?
> 
> This is part of PT_SET_EVENT_MASK/PTRACE_FORK support:
> 
> https://github.com/openbsd/src/commit/f38bed7f869bd3503530c554b4860228ea4e8641
> 
> When reporting of the PTRACE_FORK event is requested, the debugger
> expects to see a SIGTRAP in both the parent and the child.  The code
> expects that the only way to have PS_TRACED set in the child from the
> start is when PTRACE_FORK is requested.  But the failing test shows
> there is a race with PT_ATTACH.

Thanks for the explanation.

> I think the solution is to have fork1() only run fork_return() if the
> FORK_PTRACE flag is set, and use run child_return() otherwise.

Diff below does that and prevent the race, ok?

Index: kern/kern_fork.c
===
RCS file: /cvs/src/sys/kern/kern_fork.c,v
retrieving revision 1.234
diff -u -p -r1.234 kern_fork.c
--- kern/kern_fork.c15 Feb 2021 09:35:59 -  1.234
+++ kern/kern_fork.c21 Mar 2021 15:55:26 -
@@ -95,12 +95,15 @@ fork_return(void *arg)
 int
 sys_fork(struct proc *p, void *v, register_t *retval)
 {
+   void (*func)(void *) = child_return;
int flags;
 
flags = FORK_FORK;
-   if (p->p_p->ps_ptmask & PTRACE_FORK)
+   if (p->p_p->ps_ptmask & PTRACE_FORK) {
flags |= FORK_PTRACE;
-   return fork1(p, flags, fork_return, NULL, retval, NULL);
+   func = fork_return;
+   }
+   return fork1(p, flags, func, NULL, retval, NULL);
 }
 
 int



Re: fork(2), PT_ATTACH & SIGTRAP

2021-03-21 Thread Mark Kettenis
> Date: Sat, 20 Mar 2021 13:10:17 +0100
> From: Martin Pieuchot 
> 
> On SP systems, like bluhm@'s armv7 regression machine, the kern/ptrace2
> test is failing due to a subtle behavior.  Diff below makes it pass.
> 
> http://bluhm.genua.de/regress/results/2021-03-19T15%3A17%3A02Z/logs/sys/kern/ptrace2/make.log
> 
> The failing test does a fork(2) and the parent issues a PT_ATTACH on the
> child before it has been scheduled for the first time.  Then the parent
> goes to sleep in waitpid() and when the child starts executing the check
> below overwrites the ptrace(2)-received SIGSTOP by a SIGTRAP.
> 
> This scenario doesn't seem to happen on MP machine because the child
> starts to execute itself on a different core right after sys_fork() is
> finished.
> 
> What is the purpose of this check?  Should it be relaxed or removed?

This is part of PT_SET_EVENT_MASK/PTRACE_FORK support:

https://github.com/openbsd/src/commit/f38bed7f869bd3503530c554b4860228ea4e8641

When reporting of the PTRACE_FORK event is requested, the debugger
expects to see a SIGTRAP in both the parent and the child.  The code
expects that the only way to have PS_TRACED set in the child from the
start is when PTRACE_FORK is requested.  But the failing test shows
there is a race with PT_ATTACH.

I think the solution is to have fork1() only run fork_return() if the
FORK_PTRACE flag is set, and use run child_return() otherwise.


> Index: kern/kern_fork.c
> ===
> RCS file: /cvs/src/sys/kern/kern_fork.c,v
> retrieving revision 1.234
> diff -u -p -r1.234 kern_fork.c
> --- kern/kern_fork.c  15 Feb 2021 09:35:59 -  1.234
> +++ kern/kern_fork.c  20 Mar 2021 11:59:18 -
> @@ -86,9 +86,6 @@ fork_return(void *arg)
>  {
>   struct proc *p = (struct proc *)arg;
>  
> - if (p->p_p->ps_flags & PS_TRACED)
> - psignal(p, SIGTRAP);
> -
>   child_return(p);
>  }
>  
> 
> 



fork(2), PT_ATTACH & SIGTRAP

2021-03-20 Thread Martin Pieuchot
On SP systems, like bluhm@'s armv7 regression machine, the kern/ptrace2
test is failing due to a subtle behavior.  Diff below makes it pass.

http://bluhm.genua.de/regress/results/2021-03-19T15%3A17%3A02Z/logs/sys/kern/ptrace2/make.log

The failing test does a fork(2) and the parent issues a PT_ATTACH on the
child before it has been scheduled for the first time.  Then the parent
goes to sleep in waitpid() and when the child starts executing the check
below overwrites the ptrace(2)-received SIGSTOP by a SIGTRAP.

This scenario doesn't seem to happen on MP machine because the child
starts to execute itself on a different core right after sys_fork() is
finished.

What is the purpose of this check?  Should it be relaxed or removed?

Index: kern/kern_fork.c
===
RCS file: /cvs/src/sys/kern/kern_fork.c,v
retrieving revision 1.234
diff -u -p -r1.234 kern_fork.c
--- kern/kern_fork.c15 Feb 2021 09:35:59 -  1.234
+++ kern/kern_fork.c20 Mar 2021 11:59:18 -
@@ -86,9 +86,6 @@ fork_return(void *arg)
 {
struct proc *p = (struct proc *)arg;
 
-   if (p->p_p->ps_flags & PS_TRACED)
-   psignal(p, SIGTRAP);
-
child_return(p);
 }