Skip to content

Commit

Permalink
c18n: Full support for signal handling
Browse files Browse the repository at this point in the history
The signal handling mechanism is completely overhauled.

RTLD now catches all signals. It then forwards the signal to libthr (if
it is linked), which in turn forwards the signal to RTLD again.

Here, RTLD determines the stack that the signal handler should run on.
It copies the sigframe to the destination stack and then finally invoke
the signal handler.

longjmping out of a signal handler is now supported.
  • Loading branch information
dpgao committed Mar 7, 2024
1 parent f29e691 commit 40def73
Show file tree
Hide file tree
Showing 9 changed files with 329 additions and 12 deletions.
3 changes: 3 additions & 0 deletions lib/libc/Symbol-c18n.map
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ FBSDprivate_1.0 {
_rtld_longjmp;
_rtld_thread_start_init;
_rtld_sighandler_init;
_rtld_dispatch_signal;
_rtld_sigaction_begin;
_rtld_sigaction_end;
};
7 changes: 7 additions & 0 deletions lib/libc/gen/dlfcn.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,13 @@ void
_rtld_sighandler_init(void (*p)(int, siginfo_t *, void *) __unused)
{
}

#pragma weak _rtld_dispatch_signal
void
_rtld_dispatch_signal(int sig __unused, siginfo_t *info __unused,
void *_ucp __unused)
{
}
#endif

#ifndef IN_LIBDL
Expand Down
4 changes: 4 additions & 0 deletions lib/libc/sys/interposing_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT_SYS(sendmsg)
SLOT_SYS(sendto)
SLOT_SYS(setcontext)
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
SLOT_LIBC(sigaction)
#else
SLOT_SYS(sigaction)
#endif
SLOT_SYS(sigprocmask)
SLOT_SYS(sigsuspend)
SLOT_LIBC(sigwait)
Expand Down
45 changes: 45 additions & 0 deletions lib/libc/sys/sigaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,52 @@
#include "libc_private.h"

__weak_reference(__sys_sigaction, __sigaction);
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
#pragma weak _rtld_sighandler
void _rtld_sighandler(int sig __unused, siginfo_t *info __unused,
void *_ucp __unused)
{
}

#pragma weak _rtld_sigaction_begin
void *_rtld_sigaction_begin(int sig __unused, struct sigaction *act __unused)
{
return (0);
}

#pragma weak _rtld_sigaction_end
void _rtld_sigaction_end(int sig __unused, void *context __unused,
const struct sigaction *act __unused, struct sigaction *oldact __unused)
{
}

int
__libc_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
{
int ret;
void *context = 0;
struct sigaction newact;
const struct sigaction *newactp = act;

if (act &&
act->sa_handler != SIG_DFL && act->sa_handler != SIG_IGN) {
newact = *act;
newactp = &newact;

context = _rtld_sigaction_begin(sig, &newact);
newact.sa_sigaction = _rtld_sighandler;
}

ret = __sys_sigaction(sig, newactp, oact);

if (ret == 0)
_rtld_sigaction_end(sig, context, act, oact);

return (ret);
}
#else
__weak_reference(sigaction, __libc_sigaction);
#endif

#pragma weak sigaction
int
Expand Down
17 changes: 17 additions & 0 deletions lib/libthr/thread/thr_sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ __weak_reference(thr_sighandler, _thr_sighandler);
void _thr_sighandler(int, siginfo_t *, void *);
__weak_reference(thr_sighandler, _rtld_sighandler);
void _rtld_sighandler(int, siginfo_t *, void *);

void _rtld_dispatch_signal(int, siginfo_t *, void *);
void *_rtld_sigaction_begin(int, struct sigaction *);
void _rtld_sigaction_end(int, void *, const struct sigaction *,
struct sigaction *);
#endif

int _sigtimedwait(const sigset_t *set, siginfo_t *info,
Expand Down Expand Up @@ -598,6 +603,9 @@ __thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
sigset_t oldset;
struct usigaction *usa;
int ret, err;
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
void *context = NULL;
#endif

if (!_SIG_VALID(sig) || sig == SIGCANCEL) {
errno = EINVAL;
Expand All @@ -624,6 +632,10 @@ __thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
*/
if (newact.sa_handler != SIG_DFL &&
newact.sa_handler != SIG_IGN) {
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
context = _rtld_sigaction_begin(sig, &newact);
newact.sa_sigaction = _rtld_dispatch_signal;
#endif
usa->sigact = newact;
remove_thr_signals(&usa->sigact.sa_mask);
newact.sa_flags &= ~SA_NODEFER;
Expand Down Expand Up @@ -652,6 +664,11 @@ __thr_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
oldact = usa->sigact;
}

#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
if (ret == 0)
_rtld_sigaction_end(sig, context, act, &oldact);
#endif

_thr_rwl_unlock(&usa->lock);
__sys_sigprocmask(SIG_SETMASK, &oldset, NULL);

Expand Down
3 changes: 3 additions & 0 deletions libexec/rtld-elf/Symbol-c18n.map
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ FBSDprivate_1.0 {
_rtld_thread_start_init;
_rtld_thread_start;
_rtld_thr_exit;
_rtld_dispatch_signal;
_rtld_sigaction_begin;
_rtld_sigaction_end;
_rtld_sighandler_init;
_rtld_sighandler;
_rtld_setjmp;
Expand Down
80 changes: 80 additions & 0 deletions libexec/rtld-elf/aarch64/rtld_c18n_asm.S
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,86 @@ ENTRY(_rtld_thread_start)
b _rtld_thread_start_impl
END(_rtld_thread_start)

/*
* void _rtld_sighandler(int, siginfo_t *, void *);
*
* This function clobbers some callee-saved registers. This is fine because it
* is only ever invoked via a trampoline by the kernel when a signal is
* delivered.
*/
ENTRY(_rtld_sighandler)
#ifndef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
/*
* The sigframe is pushed onto the trusted stack, disrupting the linked-
* list. Repair the link by pointing it to the pre-signal top of the
* trusted stack.
*/
mov c19, c30
mov c20, c0
mov c21, c1
mov c22, c2

mov c0, csp
mov c1, c2
bl sighandler_fix_link
mov x23, x0

mov c0, c20
mov c1, c21
mov c2, c22
#endif

ldr c3, signal_dispatcher
#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
br x3
#else
blr c3

/*
* Restore the link to its original value.
*/
mov c0, csp
mov x1, x23
mov c30, c19
b sighandler_unfix_link
#endif
END(_rtld_sighandler)

/*
* void _rtld_dispatch_signal(int, siginfo_t *, void *);
*
* This function clobbers some callee-saved registers. This is fine because it
* is only ever invoked by either RTLD code that is aware of this behaviour or
* external code via a trampoline.
*/
ENTRY(_rtld_dispatch_signal)
mov c24, c30
mov w25, w0
mov c26, c1
mov c27, c2
bl dispatch_signal_get
mov c28, c0

mov c1, c26
mov c2, c27
bl dispatch_signal_begin
mov c26, c1

mov c2, c1
mov c1, c0
mov w0, w25
#ifdef __ARM_MORELLO_PURECAP_BENCHMARK_ABI
blr x28
#else
blr c28
#endif

mov c0, c26
mov c1, c27
mov c30, c24
b dispatch_signal_end
END(_rtld_dispatch_signal)

ENTRY(allocate_rstk)
/*
* NON-STANDARD CALLING CONVENTION
Expand Down
Loading

0 comments on commit 40def73

Please sign in to comment.