On Wed, Oct 16, 2019 at 09:33:59AM -0500, Eric Blake wrote:
On 10/16/19 9:04 AM, Daniel P. Berrangé wrote:
> On Wed, Oct 16, 2019 at 06:50:33AM -0500, Eric Blake wrote:
> > On 10/16/19 4:02 AM, Daniel P. Berrangé wrote:
> >
> > >
> > > The challenge here is that we're in between fork + execve and want
signal
> > > handlers back to their defaults at time of execve.
> > >
> > > If we set SIGPIPE to SIG_IGN and then execve() will that get reset back
> > > to SIG_DFL automatically ?
> >
> > Sadly, no. execve() does not change whether a signal is ignored or masked
> > (ignored is more common - a number of CI systems have had issues where the
> > child inherits SIGPIPE ignored because the parent forgot to reset it, but
> > the child wasn't expecting it; but inheriting a signal masked is also a
real
> > issue), with the lone exception of SIGCHLD. However, execve() _does_ change
> > a signal that is being caught in the parent into SIG_DFL post-exec.
> >
> > That does mean, however, that it is viable to install a no-op SIGPIPE
> > handler (SIGPIPE is generated but ignored, I/O gets the EPIPE as desired),
> > then post-exec the new process will have SIG_DFL.
>
> Yeah, that's workable.
>
> So we need virFork() to install a dummy SIGPIPE handler function that
> is a no-op, *before* it unmasks signals.
Why mask signals at all? You either mask the signal before I/O, install the
dummy handler, then unmask (and any intermediate SIGPIPE is now ignored by
no-op), or you can merely install the dummy handler before I/O (any SIGPIPE
is ignored by no-op). That is, by the time you identify a a safe place to
install a mask (ie. no I/O between fork() and that point, but where there
will be potential I/O between that point and exec), with plans to release it
later, that same place is just as good for changing from SIG_IGN to a no-op
handler without messing with masks.
The fork'd child process inherits all signal handlers from the parent.
These handlers may no longer be valid since we are mass-closing all
file descriptors. We thus need to kill off all the signal handlers
in the forkd child.
There's a window between fork & sigaction where signals can still
get delivered to the child & run the undesirable handlers. So we must
mask all signals immediately before fork, only unmasking them after
we have set all signal handlers back to their defaults.
We just need to set SIGPIPE to a dummy no-op handler before this
unmask
Regards,
Daniel
--
|:
https://berrange.com -o-
https://www.flickr.com/photos/dberrange :|
|:
https://libvirt.org -o-
https://fstop138.berrange.com :|
|:
https://entangle-photo.org -o-
https://www.instagram.com/dberrange :|