/* Work around printf() being unsafe in signals: */ #define SIGNAL_BUF_LEN 1000 char signal_message_buffer[SIGNAL_BUF_LEN]; void sig_print(char *msg)
{ int left = SIGNAL_BUF_LEN - strlen(signal_message_buffer) - 1;
strncat(signal_message_buffer, msg, left);
}
staticvolatilebool noperm_signaled; staticint noperm_errs; /* * Signal handler for when AMX is used but * permission has not been obtained.
*/ staticvoid handle_noperm(int sig, siginfo_t *si, void *ctx_void)
{
ucontext_t *ctx = (ucontext_t *)ctx_void; void *xbuf = ctx->uc_mcontext.fpregs; struct _fpx_sw_bytes *sw_bytes;
uint64_t features;
/* Reset the signal message buffer: */
signal_message_buffer[0] = '\0';
sig_print("\tAt SIGILL handler,\n");
if (si->si_code != ILL_ILLOPC) {
noperm_errs++;
sig_print("[FAIL]\tInvalid signal code.\n");
} else {
sig_print("[OK]\tValid signal code (ILL_ILLOPC).\n");
}
sw_bytes = get_fpx_sw_bytes(xbuf); /* * Without permission, the signal XSAVE buffer should not * have room for AMX register state (aka. xtiledata). * Check that the size does not overlap with where xtiledata * will reside. * * This also implies that no state components *PAST* * XTILEDATA (features >=19) can be present in the buffer.
*/ if (sw_bytes->xstate_size <= xtiledata.xbuf_offset) {
sig_print("[OK]\tValid xstate size\n");
} else {
noperm_errs++;
sig_print("[FAIL]\tInvalid xstate size\n");
}
features = get_fpx_sw_bytes_features(xbuf); /* * Without permission, the XTILEDATA feature * bit should not be set.
*/ if ((features & XFEATURE_MASK_XTILEDATA) == 0) {
sig_print("[OK]\tValid xstate mask\n");
} else {
noperm_errs++;
sig_print("[FAIL]\tInvalid xstate mask\n");
}
/* Print any messages produced by the signal code: */
printf("%s", signal_message_buffer); /* * Reset the buffer to make sure any future printing * only outputs new messages:
*/
signal_message_buffer[0] = '\0';
if (noperm_errs)
fatal_error("saw %d errors in noperm signal handler\n", noperm_errs);
return !noperm_signaled;
}
/* * Use XRSTOR to populate the XTILEDATA registers with * random data. * * Return true if successful; otherwise, false.
*/ staticinlinebool load_rand_tiledata(struct xsave_buffer *xbuf)
{
clear_xstate_header(xbuf);
set_xstatebv(xbuf, XFEATURE_MASK_XTILEDATA);
set_rand_data(&xtiledata, xbuf); return xrstor_safe(xbuf, XFEATURE_MASK_XTILEDATA);
}
minsigstksz = getauxval(AT_MINSIGSTKSZ);
printf("\tAT_MINSIGSTKSZ = %lu\n", minsigstksz); /* * getauxval() itself can return 0 for failure or * success. But, in this case, AT_MINSIGSTKSZ * will always return a >=0 value if implemented. * Just check for 0.
*/ if (minsigstksz == 0) {
printf("no support for AT_MINSIGSTKSZ, skipping sigaltstack tests\n"); return;
}
enough_size = minsigstksz * 2;
altstack = alloc_altstack(enough_size);
printf("\tAllocate memory for altstack (%u bytes).\n", enough_size);
/* * Try setup_altstack() with a size which can not fit * XTILEDATA. ARCH_REQ_XCOMP_PERM should fail.
*/
small_size = minsigstksz - xtiledata.size;
printf("\tAfter sigaltstack() with small size (%u bytes).\n", small_size);
setup_altstack(altstack, small_size, SUCCESS_EXPECTED);
validate_req_xcomp_perm(FAIL_EXPECTED);
/* * Try setup_altstack() with a size derived from * AT_MINSIGSTKSZ. It should be more than large enough * and thus ARCH_REQ_XCOMP_PERM should succeed.
*/
printf("\tAfter sigaltstack() with enough size (%u bytes).\n", enough_size);
setup_altstack(altstack, enough_size, SUCCESS_EXPECTED);
validate_req_xcomp_perm(SUCCESS_EXPECTED);
/* * Try to coerce setup_altstack() to again accept a * too-small altstack. This ensures that big-enough * sigaltstacks can not shrink to a too-small value * once XTILEDATA permission is established.
*/
printf("\tThen, sigaltstack() with small size (%u bytes).\n", small_size);
setup_altstack(altstack, small_size, FAIL_EXPECTED);
}
parent = fork(); if (parent < 0) { /* fork() failed */
fatal_error("fork");
} elseif (parent > 0) { int status; /* fork() succeeded. Now in the parent. */
wait(&status); if (!WIFEXITED(status) || WEXITSTATUS(status))
fatal_error("arch_prctl test parent exit"); return;
} /* fork() succeeded. Now in the child . */
printf("[RUN]\tCheck ARCH_REQ_XCOMP_PERM around process fork() and sigaltack() test.\n");
printf("\tFork a child.\n");
child = fork(); if (child < 0) {
fatal_error("fork");
} elseif (child > 0) { int status;
wait(&status); if (!WIFEXITED(status) || WEXITSTATUS(status))
fatal_error("arch_prctl test child exit");
_exit(0);
}
/* * The permission request should fail without an * XTILEDATA-compatible signal stack
*/
printf("\tTest XCOMP_PERM at child.\n");
validate_xcomp_perm(FAIL_EXPECTED);
/* * Set up an XTILEDATA-compatible signal stack and * also obtain permission to populate XTILEDATA.
*/
printf("\tTest dynamic sigaltstack at child:\n");
test_dynamic_sigaltstack();
/* Ensure that XTILEDATA can be populated. */
printf("\tTest XCOMP_PERM again at child.\n");
validate_xcomp_perm(SUCCESS_EXPECTED);
printf("\tFork a grandchild.\n");
grandchild = fork(); if (grandchild < 0) { /* fork() failed */
fatal_error("fork");
} elseif (!grandchild) { /* fork() succeeded. Now in the (grand)child. */
printf("\tTest XCOMP_PERM at grandchild.\n");
/* * Ensure that the grandchild inherited * permission and a compatible sigaltstack:
*/
validate_xcomp_perm(SUCCESS_EXPECTED);
} else { int status; /* fork() succeeded. Now in the parent. */
wait(&status); if (!WIFEXITED(status) || WEXITSTATUS(status))
fatal_error("fork test grandchild");
}
/* * Save current register state and compare it to @xbuf1.' * * Returns false if @xbuf1 matches the registers. * Returns true if @xbuf1 differs from the registers.
*/ staticinlinebool __validate_tiledata_regs(struct xsave_buffer *xbuf1)
{ struct xsave_buffer *xbuf2; int ret;
xbuf2 = alloc_xbuf(); if (!xbuf2)
fatal_error("failed to allocate XSAVE buffer\n");
xsave(xbuf2, XFEATURE_MASK_XTILEDATA);
ret = __compare_tiledata_state(xbuf1, xbuf2);
free(xbuf2);
if (ret == 0) returnfalse; returntrue;
}
staticinlinevoid validate_tiledata_regs_changed(struct xsave_buffer *xbuf)
{ int ret = __validate_tiledata_regs(xbuf);
if (ret == 0)
fatal_error("TILEDATA registers did not change");
}
child = fork(); if (child < 0) { /* fork() failed */
fatal_error("fork");
} elseif (child > 0) { /* fork() succeeded. Now in the parent. */ int status;
wait(&status); if (!WIFEXITED(status) || WEXITSTATUS(status))
fatal_error("fork test child"); return;
} /* fork() succeeded. Now in the child. */
printf("[RUN]\tCheck tile data inheritance.\n\tBefore fork(), load tiledata\n");
load_rand_tiledata(stashed_xsave);
grandchild = fork(); if (grandchild < 0) { /* fork() failed */
fatal_error("fork");
} elseif (grandchild > 0) { /* fork() succeeded. Still in the first child. */ int status;
wait(&status); if (!WIFEXITED(status) || WEXITSTATUS(status))
fatal_error("fork test grand child");
_exit(0);
} /* fork() succeeded. Now in the (grand)child. */
/* * TILEDATA registers are not preserved across fork(). * Ensure that their value has changed:
*/
validate_tiledata_regs_changed(stashed_xsave);
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.