On 20/03/18(Tue) 17:04, Visa Hankala wrote:
> On Tue, Mar 20, 2018 at 10:45:56AM +0100, Martin Pieuchot wrote:
> > On 19/03/18(Mon) 15:38, Visa Hankala wrote:
> > > On Mon, Mar 19, 2018 at 12:27:10PM +0100, Martin Pieuchot wrote:
> > > > Thanks for the report.
> > > > 
> > > > On 19/03/18(Mon) 09:49, Theo Buehler wrote:
> > > > > This is a regression that came with the TOCTOU race fix in kern_sig.c 
> > > > > 1.216:
> > > > > https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/kern/kern_sig.c#rev1.216
> > > > > [...] 
> > > > > Now gdb just hangs there and does nothing instead of exiting as
> > > > > expected.  It doesn't react to ^C but one can easily kill it with
> > > > > ^Z and then kill %%.
> > > > 
> > > > What happens is that the programs stays stopped.  Or to be more precise
> > > > re-enter the SSTOP'd state after ptrace(PT_KILL...) has been issued by
> > > > gdb(1).
> > > > The problem comes from the fact that CURSIG() is now called twice in
> > > > userret().  That means that issignal() is also called twice.  The fix
> > > > is to treat SIGKILL as special if the process is currently traced.
> > > 
> > > As an alternative, the double call of issignal() could be avoided.
> > 
> > I like this.  But I still think that we should handle SIGKILL correctly
> > in CURSIG().  However your fix seems safer for release.
> > 
> > > CURSIG(p) evaluates to zero if p->p_siglist is zero, or eventually
> > > issignal(p) returns zero if there are no unmasked signals (that is,
> > > if (p->p_siglist & ~p->p_sigmask) == 0).
> > 
> > But if the process is being traced issignal() is always called.  Does
> > that mean that the `PS_TRACED' check is useless because issignal() also
> > starts with  if (p->p_siglist & ~p->p_sigmask) == 0?
> 
> So it seems. The trace point is taken only if the signal mask allows
> signal delivery.
> 
> > I'd prefer if you could used a function (inline) with an explicit name
> > like hassignal() or unmaskedsignal()?
> 
> Updated diff:

I like it.  I you don't return a boolean but the mask of pending signals
in the macro we could use it in issignal().  But that can be for a later
change.

ok mpi@

> Index: kern/kern_sig.c
> ===================================================================
> RCS file: src/sys/kern/kern_sig.c,v
> retrieving revision 1.216
> diff -u -p -r1.216 kern_sig.c
> --- kern/kern_sig.c   26 Feb 2018 13:33:25 -0000      1.216
> +++ kern/kern_sig.c   20 Mar 2018 16:53:25 -0000
> @@ -1833,7 +1833,7 @@ userret(struct proc *p)
>               KERNEL_UNLOCK();
>       }
>  
> -     if (CURSIG(p) != 0) {
> +     if (SIGPENDING(p)) {
>               KERNEL_LOCK();
>               while ((signum = CURSIG(p)) != 0)
>                       postsig(p, signum);
> Index: sys/signalvar.h
> ===================================================================
> RCS file: src/sys/sys/signalvar.h,v
> retrieving revision 1.29
> diff -u -p -r1.29 signalvar.h
> --- sys/signalvar.h   26 Feb 2018 13:33:25 -0000      1.29
> +++ sys/signalvar.h   20 Mar 2018 16:53:25 -0000
> @@ -66,6 +66,11 @@ struct     sigacts {
>  #define      SIG_HOLD        (void (*)(int))3
>  
>  /*
> + * Check if process p has an unmasked signal pending.
> + */
> +#define      SIGPENDING(p)   (((p)->p_siglist & ~(p)->p_sigmask) != 0)
> +
> +/*
>   * Determine signal that should be delivered to process p, the current
>   * process, 0 if none.  If there is a pending stop signal with default
>   * action, the process stops in issignal().

Reply via email to