/* * Copyright 2022, Nicholas Miehlbradt, IBM Corporation * based on pkey_exec_prot.c * * Test if applying execute protection on pages works as expected.
*/
staticbool is_fault_expected(int fault_code)
{ if (fault_code == SEGV_ACCERR) returntrue;
/* Assume any pkey error is fine since pkey_exec_prot test covers them */ if (fault_code == SEGV_PKUERR && pkeys_supported) returntrue;
returnfalse;
}
staticvoid trap_handler(int signum, siginfo_t *sinfo, void *ctx)
{ /* Check if this fault originated from the expected address */ if (sinfo->si_addr != (void *)fault_addr)
sigsafe_err("got a fault for an unexpected address\n");
/* Check if this fault originated from the expected address */ if (sinfo->si_addr != (void *)fault_addr) {
sigsafe_err("got a fault for an unexpected address\n");
_exit(1);
}
/* Check if too many faults have occurred for a single test case */ if (!remaining_faults) {
sigsafe_err("got too many faults for the same address\n");
_exit(1);
}
/* Restore permissions in order to continue */ if (is_fault_expected(fault_code)) { if (mprotect(insns, pgsize, PROT_READ | PROT_WRITE | PROT_EXEC)) {
sigsafe_err("failed to set access permissions\n");
_exit(1);
}
} else {
sigsafe_err("got a fault with an unexpected code\n");
_exit(1);
}
remaining_faults--;
}
staticint check_exec_fault(int rights)
{ /* * Jump to the executable region. * * The first iteration also checks if the overwrite of the * first instruction word from a trap to a no-op succeeded.
*/
fault_code = -1;
remaining_faults = 0; if (!(rights & PROT_EXEC))
remaining_faults = 1;
/* Write the instruction words */ for (i = 1; i < numinsns - 1; i++)
insns[i] = PPC_INST_NOP;
/* * Set the first instruction as an unconditional trap. If * the last write to this address succeeds, this should * get overwritten by a no-op.
*/
insns[0] = PPC_INST_TRAP;
/* * Later, to jump to the executable region, we use a branch * and link instruction (bctrl) which sets the return address * automatically in LR. Use that to return back.
*/
insns[numinsns - 1] = PPC_INST_BLR;
/* * Pick the first instruction's address from the executable * region.
*/
fault_addr = insns;
/* * Read an instruction word from the address when the page * is execute only. This should generate an access fault.
*/
fault_code = -1;
remaining_faults = 1;
printf("Testing read on --x, should fault...");
FAIL_IF(mprotect(insns, pgsize, PROT_EXEC) != 0);
i = *fault_addr;
FAIL_IF(remaining_faults != 0 || !is_fault_expected(fault_code));
printf("ok!\n");
/* * Write an instruction word to the address when the page * execute only. This should also generate an access fault.
*/
fault_code = -1;
remaining_faults = 1;
printf("Testing write on --x, should fault...");
FAIL_IF(mprotect(insns, pgsize, PROT_EXEC) != 0);
*fault_addr = PPC_INST_NOP;
FAIL_IF(remaining_faults != 0 || !is_fault_expected(fault_code));
printf("ok!\n");
printf("Testing exec on ---, should fault...");
FAIL_IF(check_exec_fault(PROT_NONE));
printf("ok!\n");
printf("Testing exec on r--, should fault...");
FAIL_IF(check_exec_fault(PROT_READ));
printf("ok!\n");
printf("Testing exec on -w-, should fault...");
FAIL_IF(check_exec_fault(PROT_WRITE));
printf("ok!\n");
printf("Testing exec on rw-, should fault...");
FAIL_IF(check_exec_fault(PROT_READ | PROT_WRITE));
printf("ok!\n");
printf("Testing exec on --x, should succeed...");
FAIL_IF(check_exec_fault(PROT_EXEC));
printf("ok!\n");
printf("Testing exec on r-x, should succeed...");
FAIL_IF(check_exec_fault(PROT_READ | PROT_EXEC));
printf("ok!\n");
printf("Testing exec on -wx, should succeed...");
FAIL_IF(check_exec_fault(PROT_WRITE | PROT_EXEC));
printf("ok!\n");
printf("Testing exec on rwx, should succeed...");
FAIL_IF(check_exec_fault(PROT_READ | PROT_WRITE | PROT_EXEC));
printf("ok!\n");
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.