Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20190306182030.GU23599@brightrain.aerifal.cx>
Date: Wed, 6 Mar 2019 13:20:30 -0500
From: Rich Felker <dalias@...c.org>
To: Markus Wichmann <nullplan@....net>
Cc: musl@...ts.openwall.com
Subject: Re: sigaltstack for implementation-internal signals?

On Wed, Mar 06, 2019 at 06:11:19PM +0100, Markus Wichmann wrote:
> On Wed, Mar 06, 2019 at 11:25:08AM -0500, Rich Felker wrote:
> > On Wed, Mar 06, 2019 at 05:07:40PM +0100, Markus Wichmann wrote:
> > > libc uses signal handlers. And you use libc. Connect the dots...
> > 
> > This is an implementation detail, not part of the specification.
> 
> Well, then the spec must allow for this implementation (else it would
> not be conforming). Which means we move from "libc uses signal handlers"
> to "libc might use signal handlers". From a practical point of view,
> that is no difference at all.

The question is whether it's a conforming implementation at all. If
the use of signals is visible in ways it shouldn't be (i.e. without
doing hacks outside the scope of the language/API like setting a bogus
stack pointer) then that's non-conforming. That (aside from other
practical necessities to prevent breakage) is why we take such
measures to "hide" the internal use of signals, like preventing them
from being added to sigset_t.

> But the point about not being able to block these signals remains... not
> sure what the right thing is, really. On one hand, this breaks
> applications that assume no signal will arrive after blocking signals,
> on the other hand, blocking libc-internal signals might deadlock. (We
> had that thread about go a while back, remember?)

It doesn't break applications that assume no signal will arrive, since
its arrival isn't observable within the standard interfaces. It breaks
applications that are doing particular hacks outside of the scope of
what's specified.

> One thing I noticed: At least on Linux, the main thread must always have
> a valid stack pointer in order to facilitate the rather fragile stack
> expansion mechanism. As I recall, that mechanism is triggered every time
> a stack pointer reference causes a page fault, and if the ulimit for the
> stack size is exceeded, the process is signalled.

I don't see how this matters. If you set the stack pointer to an
invalid value (e.g. to use it as a general purpose register), you're
not going to be trying to dereference it.

> > > SIGTIMER:
> > > That one is needed in timer_create() to be able to spawn a thread if
> > > someone creates a timer with SIGEV_THREAD. Since the handling thread is
> > > spawned immediately, the signal is taken only on the stack of the
> > > internal thread. And the handler itself does nothing.
> > 
> > This can be removed at some point anyway. SIGEV_THREAD is easier to do
> > in userspace without kernel timer objects and signals.
> > 
> 
> How? clock_nanosleep() in a loop, then?

Yes. What we're doing now is essentially a huge pile of unnecessary
complexity and kernel resource consumption to get the same effect as
clock_nanosleep in a loop. However there is some convenience; it
avoids having to calculate overruns ourselves and allows
timer_settime, etc. to use the common kernel interface regardless of
which type of timer they're acting on. This is why I haven't converted
it over yet; converting it requires writing the equivalent logic for
"userspace timer threads".

> > > BTW, is there a
> > > reason that handler is installed with SA_SIGINFO if it does nothing with
> > > the extra info?
> > 
> > 		if (si.si_code == SI_TIMER && !setjmp(jb)) {
> > 
> 
> That is in the handling thread, and the signal info comes out of
> sigwaitinfo(). No, I meant timer_handler(), which is installed with
> SA_SIGINFO but does nothing.

Well before it was in the handler, but it's not clear that you can use
sigwaitinfo to get the info without SI_SIGINFO. See the application
usage notes in POSIX for sigwaitinfo:

    "Note that in order to ensure that generated signals are queued
    and signal values passed to sigqueue() are available in si_value,
    applications which use sigwaitinfo() or sigtimedwait() need to set
    the SA_SIGINFO flag for each signal in the set (see Signal
    Concepts). This means setting each signal to be handled by a
    three-argument signal-catching function, even if the handler will
    never be called. It is not possible (portably) to set a signal
    handler to SIG_DFL while setting the SA_SIGINFO flag, because
    assigning to the sa_handler member of struct sigaction instead of
    the sa_sigaction member would result in undefined behavior, and
    SIG_DFL need not be assignment-compatible with sa_sigaction. Even
    if an assignment of SIG_DFL to sa_sigaction is accepted by the
    compiler, the implementation need not treat this value as
    special-it could just be taken as the address of a signal-catching
    function."

Thus the SA_SIGINFO flag was kept with the understanding that it might
be required for the current logic to work.

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.