Saving errno around signal handlers

Florian Weimer fweimer@redhat.com
Fri Feb 28 11:49:00 GMT 2014


POSIX has green-lighted saving errno around signal handlers.  So the 
question now is how we implement that.

* glibc-only solution

We need to wrap the signal handler with a function that calls the actual 
handler, saving and restoring errno around it.  We do not have a place 
to store the real handler address, so we need to use separate 
trampolines, either generated dynamically or a from a static, 
pre-allocated pool.  There are only a few signal handlers, so a static 
set of trampolines would work if we deallocate trampolines.

The problem with deallocation is that when sigaction is used to obtain 
the address of the existing handler, we have to translate it back, and 
concurrently freeing the trampoline will result in the wrong handler 
address.  So we'd need some form of locking, and it still needs to be 
fully reentrant, so this will be difficult.

On the other hand, a trampoline just needs a few bytes on most 
architectures (an indirect call to a machine language helper), so we 
might get away with leaking the trampoline permanently, particularly if 
we use a hash table to reuse the same trampoline for the same handler.

The trampolines are architecture-specific, but the rest would be generic.

* kernel-based solutions

We could teach the kernel about the location of the errno variable in 
the TLS data structure and save and restore that.  But this a gross 
layering violation, so I won't consider it further.

We could add a process-wide callback function, settable with prctl, that 
will be called by the kernel instead of the actual signal handler.  It 
would receive the same arguments as the handler, and an additional 
argument that contains the address of the configured signal handler.

We could a flag which replaces SA_RESTORER and switches on this callback 
behavior for a specific signal handler, using the existing sa_restorer 
field as the address of the wrapper function.

The kernel-based approaches need architecture-specific changes in the 
signal stack frame setup.

In all cases (kernel and glibc implementation), we can use a tail call 
to make sure that the stack layout looks like it is at present (at least 
on architectures with an available callee-saved register), and we would 
not have to adjust GDB and other tools.

I'm not sure which approach would be the best way to proceed here. 
Comments?

-- 
Florian Weimer / Red Hat Product Security Team



More information about the Libc-alpha mailing list