Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Wed, 6 Mar 2019 11:25:08 -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 05:07:40PM +0100, Markus Wichmann wrote:
> On Wed, Mar 06, 2019 at 01:56:02PM +0100, Florian Weimer wrote:
> > * Rich Felker:
> > 
> > > If we add unblockable, implementation-internal signals that are
> > > flagged SA_ONSTACK, however, this breaks; now even if an application
> > > has taken the "proper precautions", they can be delivered in a state
> > > where the alt stack is nonempty but the stack pointer doesn't point
> > > into it, thereby causing it to get clobbered.
> > 
> > There's also the matter of applications which do not use signal handlers
> > at all (and thus never invoke sigaltstack) and have really small stacks,
> > or use the stack pointer register for something else.  Is either of that
> > supported?
> > 
> 
> If you or any library you use install signal handlers, your code is
> constantly at an interface boundary, since a signal can appear at any
> time.

No, only when signals are not blocked. You can block any signals that
are provided to the application for its use, but the libc-internal
signals are not blockable by the application.

> libc uses signal handlers. And you use libc. Connect the dots...

This is an implementation detail, not part of the specification.

> > I think it is not clear whether a libc implementation may generate
> > sporadic signals *at all* to support implementation needs.
> > 
> 
> Well, then we're at an impasse, as POSIX requires certain semantics and
> the kernel provides different ones, and we need the signals as a
> go-between. Alright, what implementation-internal signals are there?
> 
> 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.

> 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)) {

> Anyway, this signal has no impact on application stacks.

It does if the thread attribute object defines a custom stack, but I
think POSIX severely limits or forbids what you can do with this,
since the stack is never freed/freeable.

> SIGCANCEL:
> The cancelled thread will take this signal. Wanting to cancel a thread
> without signalling it is like wanting to be washed without being made
> wet; it simply makes no sense.

No, it's an implementation detail that the underlying kernel lacks any
way to make cancellation work without signals. It's not part of how
cancellation is specified, but there might be language in POSIX
suggesting that signals are a possible mechanism, in which case I
think that's good evidence that applications should account for the
possibility in their stack usage.

> Applications can trivially prevent the
> generation of this signal by simply foregoing the use of
> pthread_cancel().

Yes.

> SIGSYNCCALL:
> This is going to be the sticking point, isn't it? This signal really
> does appear in each thread, even application threads, without warning.
> It is currently used to implement setrlimit(), setegid(), seteuid(),
> setgid(), setuid(), setregid(), setreuid(), setresgid() and setresuid().
> Except for setrlimit(), I would not expect applications with tiny stacks
> and lots of threads to call any of these. Much less often enough to
> cause an issue. So setrlimit() is probably the only call that will cause
> problems in the kind of applications you speak of.
> 
> Thus the entire problem could be solved if the kernel allowed setting
> rlimits for the entire process, or at least for other threads. Seems
> like the smaller change to me.

Yes.

> > Does musl use asynchronous implementation signals?  For glibc, we would
> > prefer synchronous delivery, that is, the handler runs before the
> > signal-generating system call returns.  This makes me wonder if we
> > should try to get the kernel to provide us a system call which allows us
> > to run code on a different thread, with signals disabled, but with the
> > caller's stack (from the original thread).  I think this would address
> > issues caused by strange stack pointer values in the target thread.
> 
> Hmmm... if the kernel supported remote sigaltstack() (i.e. setting a
> signal stack for another thread), then this would all be done. But alas,
> no such luck.

It's not remote sigaltstack; that would break all sorts of things and
would not give conforming behavior. Rather it needs to be a mechanism
to deliver a specific signal (or better yet, not a signal, just a
caller-provided function) on a specific stack (so that it doesn't
affect delivery of any other signals at the same time).

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.