/* * Obtaining a valid and full-blown ucontext_t from userspace is tricky: * libc getcontext does() not save all the regs and messes with some of * them (pstate value in particular is not reliable). * * Here we use a service signal to grab the ucontext_t from inside a * dedicated signal handler, since there, it is populated by Kernel * itself in setup_sigframe(). The grabbed context is then stored and * made available in td->live_uc. * * As service-signal is used a SIGTRAP induced by a 'brk' instruction, * because here we have to avoid syscalls to trigger the signal since * they would cause any SVE sigframe content (if any) to be removed. * * Anyway this function really serves a dual purpose: * * 1. grab a valid sigcontext into td->live_uc for result analysis: in * such case it returns 1. * * 2. detect if, somehow, a previously grabbed live_uc context has been * used actively with a sigreturn: in such a case the execution would have * magically resumed in the middle of this function itself (seen_already==1): * in such a case return 0, since in fact we have not just simply grabbed * the context. * * This latter case is useful to detect when a fake_sigreturn test-case has * unexpectedly survived without hitting a SEGV. * * Note that the case of runtime dynamically sized sigframes (like in SVE * context) is still NOT addressed: sigframe size is supposed to be fixed * at sizeof(ucontext_t).
*/ static __always_inline bool get_current_context(struct tdescr *td,
ucontext_t *dest_uc,
size_t dest_sz)
{ staticvolatilebool seen_already; int i; char *uc = (char *)dest_uc;
/* * This is a memset() but we don't want the compiler to * optimise it into either instructions or a library call * which might be incompatible with streaming mode.
*/ for (i = 0; i < td->live_sz; i++) {
uc[i] = 0;
OPTIMIZER_HIDE_VAR(uc[0]);
}
td->live_uc = dest_uc; /* * Grab ucontext_t triggering a SIGTRAP. * * Note that: * - live_uc_valid is declared volatile sig_atomic_t in * struct tdescr since it will be changed inside the * sig_copyctx handler * - the additional 'memory' clobber is there to avoid possible * compiler's assumption on live_uc_valid and the content * pointed by dest_uc, which are all changed inside the signal * handler * - BRK causes a debug exception which is handled by the Kernel * and finally causes the SIGTRAP signal to be delivered to this * test thread. Since such delivery happens on the ret_to_user() * /do_notify_resume() debug exception return-path, we are sure * that the registered SIGTRAP handler has been run to completion * before the execution path is restored here: as a consequence * we can be sure that the volatile sig_atomic_t live_uc_valid * carries a meaningful result. Being in a single thread context * we'll also be sure that any access to memory modified by the * handler (namely ucontext_t) will be visible once returned. * - note that since we are using a breakpoint instruction here * to cause a SIGTRAP, the ucontext_t grabbed from the signal * handler would naturally contain a PC pointing exactly to this * BRK line, which means that, on return from the signal handler, * or if we place the ucontext_t on the stack to fake a sigreturn, * we'll end up in an infinite loop of BRK-SIGTRAP-handler. * For this reason we take care to artificially move forward the * PC to the next instruction while inside the signal handler.
*/ asmvolatile ("brk #666"
: "+m" (*dest_uc)
:
: "memory");
/* * If we were grabbing a streaming mode context then we may * have entered streaming mode behind the system's back and * libc or compiler generated code might decide to do * something invalid in streaming mode, or potentially even * the state of ZA. Issue a SMSTOP to exit both now we have * grabbed the state.
*/ if (td->feats_supported & FEAT_SME) asmvolatile("msr S0_3_C4_C6_3, xzr");
/* * If we get here with seen_already==1 it implies the td->live_uc * context has been used to get back here....this probably means * a test has failed to cause a SEGV...anyway live_uc does not * point to a just acquired copy of ucontext_t...so return 0
*/ if (seen_already) {
fprintf(stdout, "Unexpected successful sigreturn detected: live_uc is stale !\n"); return 0;
}
seen_already = 1;
return td->live_uc_valid;
}
int fake_sigreturn(void *sigframe, size_t sz, int misalign_bytes); #endif
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.