Skip to content

Commit

Permalink
c18n: Rework implementation to be interrupt-safe
Browse files Browse the repository at this point in the history
The trampoline and other parts of RTLD are refactored to be
interrupt-safe. The trusted frame is redesigned to allow trampolines to
perform tail-calls that do not push a trusted frame.

The new design also no longer relies on a region of metadata at the
bottom of each compartment's stack.
  • Loading branch information
dpgao committed Apr 11, 2024
1 parent d7daaf3 commit 9680cbd
Show file tree
Hide file tree
Showing 16 changed files with 1,292 additions and 1,194 deletions.
36 changes: 4 additions & 32 deletions lib/libc/sys/sigaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,43 +37,15 @@ __weak_reference(__sys_sigaction, __sigaction);
__weak_reference(sigaction, __libc_sigaction);
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
/*
* These weak symbols will always be resolved at runtime.
* This weak symbol will always be resolved at runtime.
*/
/*
* XXX: Explicit function pointer used so that RTLD can wrap it in trampoline.
*/
extern void (*_rtld_sighandler)(int, siginfo_t *, void *);

#pragma weak _rtld_sigaction_begin
void *_rtld_sigaction_begin(int, struct sigaction *);

#pragma weak _rtld_sigaction_end
void _rtld_sigaction_end(int, void *, const struct sigaction *,
struct sigaction *);
#pragma weak _rtld_sigaction
int _rtld_sigaction(int, const struct sigaction *, struct sigaction *);

Check failure on line 43 in lib/libc/sys/sigaction.c

View workflow job for this annotation

GitHub Actions / Style Checker

externs should be avoided in .c files

int
sigaction_c18n(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);
return (_rtld_sigaction(sig, act, oact));
}
#endif

Expand Down
38 changes: 28 additions & 10 deletions lib/libsysdecode/utrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,29 @@ print_utrace_mrs(FILE *fp, void *p)
}
return (1);
}

static int
print_utrace_c18n(FILE *fp, void *p)
{
struct utrace_c18n *ut = p;

switch (ut->event) {
case UTRACE_COMPARTMENT_ENTER:
fprintf(fp, "RTLD: c18n: %s -> %s at [%zu] %s (%02hhx)",
ut->caller, ut->callee, ut->symnum, ut->symbol, ut->fsig);
break;
case UTRACE_COMPARTMENT_LEAVE:
fprintf(fp, "RTLD: c18n: %s <- %s at [%zu] %s (%02hhx)",
ut->caller, ut->callee, ut->symnum, ut->symbol, ut->fsig);
break;
default:
return (0);
}
fprintf(fp, "\nnsp = %#p\nosp = %#p, previous = %#p\n"
"fp = %#p, pc = %#p", ut->sp, ut->osp, ut->previous,
ut->fp, ut->pc);
return (1);
}
#endif

#ifdef __LP64__
Expand Down Expand Up @@ -200,16 +223,6 @@ print_utrace_rtld(FILE *fp, void *p)
case UTRACE_RTLD_ERROR:
fprintf(fp, "RTLD: error: %s\n", ut->name);
break;
case UTRACE_COMPARTMENT_ENTER:
fprintf(fp,
"RTLD: c18n: enter %s from %s at [%zu] %s (%p)",
ut->callee, ut->caller, ut->mapsize, ut->symbol, ut->handle);
break;
case UTRACE_COMPARTMENT_LEAVE:
fprintf(fp,
"RTLD: c18n: leave %s to %s at [%zu] %s",
ut->callee, ut->caller, ut->mapsize, ut->symbol);
break;

default:
return (0);
Expand Down Expand Up @@ -279,10 +292,15 @@ sysdecode_utrace(FILE *fp, void *p, size_t len)
static const char rtld_utrace_sig[RTLD_UTRACE_SIG_SZ] = RTLD_UTRACE_SIG;
#ifdef __CHERI_PURE_CAPABILITY__
static const char mrs_utrace_sig[MRS_UTRACE_SIG_SZ] = MRS_UTRACE_SIG;
static const char c18n_utrace_sig[C18N_UTRACE_SIG_SZ] = C18N_UTRACE_SIG;

if (len == sizeof(struct utrace_mrs) && bcmp(p, mrs_utrace_sig,
sizeof(mrs_utrace_sig)) == 0)
return (print_utrace_mrs(fp, p));

if (len == sizeof(struct utrace_c18n) && bcmp(p, c18n_utrace_sig,
sizeof(c18n_utrace_sig)) == 0)
return (print_utrace_c18n(fp, p));
#endif

if (len == sizeof(struct utrace_rtld) && bcmp(p, rtld_utrace_sig,
Expand Down
18 changes: 18 additions & 0 deletions lib/libthr/thread/thr_create.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,14 +210,24 @@ _pthread_create(pthread_t * __restrict thread,
param.rtp = &rtp;
}

/*
* c18n: Always block all signals when creating a new thread to allow
* RTLD to set up the environment to handle signals.
*/
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
(void)create_suspended;
#else
/* Schedule the new thread. */
if (create_suspended) {
#endif
SIGFILLSET(set);
SIGDELSET(set, SIGTRAP);
__sys_sigprocmask(SIG_SETMASK, &set, &oset);
new_thread->sigmask = oset;
SIGDELSET(new_thread->sigmask, SIGCANCEL);
#if !defined(__CHERI_PURE_CAPABILITY__) || !defined(RTLD_SANDBOX)
}
#endif

ret = thr_new(&param, sizeof(param));

Expand All @@ -230,7 +240,9 @@ _pthread_create(pthread_t * __restrict thread,
ret = EAGAIN;
}

#if !defined(__CHERI_PURE_CAPABILITY__) || !defined(RTLD_SANDBOX)
if (create_suspended)
#endif
__sys_sigprocmask(SIG_SETMASK, &oset, NULL);

if (ret != 0) {
Expand Down Expand Up @@ -290,7 +302,9 @@ thread_start(struct pthread *curthread)
{
sigset_t set;

#if !defined(__CHERI_PURE_CAPABILITY__) || !defined(RTLD_SANDBOX)
if (curthread->attr.suspend == THR_CREATE_SUSPENDED)
#endif
set = curthread->sigmask;
_thr_signal_block_setup(curthread);

Expand All @@ -305,7 +319,9 @@ thread_start(struct pthread *curthread)
if (curthread->force_exit)
_pthread_exit(PTHREAD_CANCELED);

#if !defined(__CHERI_PURE_CAPABILITY__) || !defined(RTLD_SANDBOX)
if (curthread->attr.suspend == THR_CREATE_SUSPENDED) {
#endif
#if 0
/* Done in THR_UNLOCK() */
_thr_ast(curthread);
Expand All @@ -316,7 +332,9 @@ thread_start(struct pthread *curthread)
* we should restore it now.
*/
__sys_sigprocmask(SIG_SETMASK, &set, NULL);
#if !defined(__CHERI_PURE_CAPABILITY__) || !defined(RTLD_SANDBOX)
}
#endif

#ifdef _PTHREAD_FORCED_UNWIND
curthread->unwind_stackend = (char *)curthread->attr.stackaddr_attr +
Expand Down
48 changes: 22 additions & 26 deletions lib/libthr/thread/thr_sig.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,14 @@ static void check_cancel(struct pthread *curthread, ucontext_t *ucp);
/*
* These weak symbols will always be resolved at runtime.
*/
/*
* XXX: Explicit function pointer used so that RTLD can wrap it in trampoline.
*/
extern void (*_rtld_sighandler)(int, siginfo_t *, void *);

/*
* XXX: Explicit function pointer used so that RTLD can wrap it in trampoline.
*/
extern void (*_rtld_dispatch_signal)(int, siginfo_t *, void *);
#pragma weak _rtld_sighandler
void _rtld_sighandler(int, siginfo_t *, void *);

#pragma weak _rtld_sigaction_begin
void *_rtld_sigaction_begin(int, struct sigaction *);
#pragma weak _rtld_sigaction
int _rtld_sigaction(int, const struct sigaction *, struct sigaction *);

Check failure on line 83 in lib/libthr/thread/thr_sig.c

View workflow job for this annotation

GitHub Actions / Style Checker

externs should be avoided in .c files

#pragma weak _rtld_sigaction_end
void _rtld_sigaction_end(int, void *, const struct sigaction *,
struct sigaction *);
#pragma weak _rtld_siginvoke
void _rtld_siginvoke(int, siginfo_t *, void *, const struct sigaction *);

Check failure on line 86 in lib/libthr/thread/thr_sig.c

View workflow job for this annotation

GitHub Actions / Style Checker

externs should be avoided in .c files
#endif

int _sigtimedwait(const sigset_t *set, siginfo_t *info,
Expand Down Expand Up @@ -305,10 +297,14 @@ handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
if (!cancel_async)
curthread->cancel_enable = 0;

#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
(void)sigfunc;
#else
/* restore correct mask before calling user handler */
__sys_sigprocmask(SIG_SETMASK, &actp->sa_mask, NULL);

sigfunc = actp->sa_sigaction;
#endif

/*
* We have already reset cancellation point flags, so if user's code
Expand All @@ -318,13 +314,17 @@ handle_signal(struct sigaction *actp, int sig, siginfo_t *info, ucontext_t *ucp)
* so after setjmps() returns once more, the user code may need to
* re-set cancel_enable flag by calling pthread_setcancelstate().
*/
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
_rtld_siginvoke(sig, info, ucp, actp);
#else
if ((actp->sa_flags & SA_SIGINFO) != 0) {
sigfunc(sig, info, ucp);
} else {
((ohandler)sigfunc)(sig, info->si_code,
(struct sigcontext *)ucp, info->si_addr,
(__sighandler_t *)sigfunc);
}
#endif
err = errno;

curthread->in_sigsuspend = in_sigsuspend;
Expand Down Expand Up @@ -501,7 +501,11 @@ _thr_signal_init(int dlopened)
for (sig = 1; sig <= _SIG_MAXSIG; sig++) {
if (sig == SIGCANCEL)
continue;
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
error = _rtld_sigaction(sig, NULL, &oact);
#else
error = __sys_sigaction(sig, NULL, &oact);
#endif
if (error == -1 || oact.sa_handler == SIG_DFL ||
oact.sa_handler == SIG_IGN)
continue;
Expand All @@ -512,6 +516,8 @@ _thr_signal_init(int dlopened)
nact.sa_flags &= ~SA_NODEFER;
nact.sa_flags |= SA_SIGINFO;
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
/* XXX: Ignore sigaltstack for now */
nact.sa_flags &= ~SA_ONSTACK;
nact.sa_sigaction = _rtld_sighandler;
#else
nact.sa_sigaction = thr_sighandler;
Expand Down Expand Up @@ -615,9 +621,6 @@ __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 @@ -644,15 +647,13 @@ __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;
newact.sa_flags |= SA_SIGINFO;
#if defined(__CHERI_PURE_CAPABILITY__) && defined(RTLD_SANDBOX)
/* XXX: Ignore sigaltstack for now */
newact.sa_flags &= ~SA_ONSTACK;
newact.sa_sigaction = _rtld_sighandler;
#else
newact.sa_sigaction = thr_sighandler;
Expand All @@ -676,11 +677,6 @@ __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
5 changes: 2 additions & 3 deletions libexec/rtld-elf/Symbol-c18n.map
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ 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_siginvoke;
_rtld_sigaction;
_rtld_setjmp;
_rtld_longjmp;
_rtld_unw_getcontext;
Expand Down
Loading

0 comments on commit 9680cbd

Please sign in to comment.