tools/testing/selftests/riscv/cfi/cfitests.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/riscv/cfi/cfitests.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/riscv/cfi/cfitests.c
Extension
.c
Size
5015 bytes
Lines
181
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

if (WIFSTOPPED(status)) {
			errno = 0;
			ret = ptrace(PTRACE_GETREGSET, pid, (void *)NT_RISCV_USER_CFI, &iov);
			if (ret == -1 && errno)
				ksft_exit_fail_msg("%s: PTRACE_GETREGSET failed\n", __func__);
		} else {
			ksft_exit_fail_msg("%s: child didn't stop, failed\n", __func__);
		}

		switch (ptrace_test_num) {
#define CFI_ENABLE_MASK (PTRACE_CFI_BRANCH_LANDING_PAD_EN_STATE |	\
			 PTRACE_CFI_SHADOW_STACK_EN_STATE |		\
			 PTRACE_CFI_SHADOW_STACK_PTR_STATE)
		case 0:
			if ((cfi_reg.cfi_status.cfi_state & CFI_ENABLE_MASK) != CFI_ENABLE_MASK)
				ksft_exit_fail_msg("%s: ptrace_getregset failed, %llu\n", __func__,
						   cfi_reg.cfi_status.cfi_state);
			if (!cfi_reg.shstk_ptr)
				ksft_exit_fail_msg("%s: NULL shadow stack pointer, test failed\n",
						   __func__);
			break;
		case 1:
			if (!(cfi_reg.cfi_status.cfi_state &
			      PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_STATE))
				ksft_exit_fail_msg("%s: elp must have been set\n", __func__);
			/* clear elp state. not interested in anything else */
			cfi_reg.cfi_status.cfi_state = 0;

			ret = ptrace(PTRACE_SETREGSET, pid, (void *)NT_RISCV_USER_CFI, &iov);
			if (ret == -1 && errno)
				ksft_exit_fail_msg("%s: PTRACE_GETREGSET failed\n", __func__);
			break;
		default:
			ksft_exit_fail_msg("%s: unreachable switch case\n", __func__);
			break;
		}
		ptrace(PTRACE_CONT, pid, NULL, NULL);
		ptrace_test_num++;
	}

	waitpid(pid, &status, 0);
	if (WEXITSTATUS(status) != 11)
		ksft_print_msg("%s, bad return code from child\n", __func__);

	ksft_print_msg("%s, ptrace test succeeded\n", __func__);
	return true;
}

int main(int argc, char *argv[])
{
	int ret = 0;
	unsigned long lpad_status = 0, ss_status = 0;

	ksft_print_header();

	ksft_print_msg("Starting risc-v tests\n");

	/* Test unknown PR_CFI bits */
	ret = my_syscall5(__NR_prctl, PR_SET_CFI, PR_CFI_BRANCH_LANDING_PADS,
			  PR_CFI_ENABLE | 0xffff0, 0, 0);
	if (!ret)
		ksft_exit_fail_msg("PR_SET_CFI accepted reserved branch landing pad bits\n");

	/*
	 * Landing pad test. Not a lot of kernel changes to support landing
	 * pads for user mode except lighting up a bit in senvcfg via a prctl.
	 * Enable landing pad support throughout the execution of the test binary.
	 */
	ret = my_syscall5(__NR_prctl, PR_GET_CFI, PR_CFI_BRANCH_LANDING_PADS, &lpad_status, 0, 0);
	if (ret)
		ksft_exit_fail_msg("Get landing pad status failed with %d\n", ret);

	if (!(lpad_status & PR_CFI_ENABLE))
		ksft_exit_fail_msg("Landing pad is not enabled, should be enabled via glibc\n");

	ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0);
	if (ret)
		ksft_exit_fail_msg("Get shadow stack failed with %d\n", ret);

	if (!(ss_status & PR_SHADOW_STACK_ENABLE))
		ksft_exit_fail_msg("Shadow stack is not enabled, should be enabled via glibc\n");

	if (!register_signal_handler())
		ksft_exit_fail_msg("Registering signal handler for SIGSEGV failed\n");

	ksft_print_msg("Landing pad and shadow stack are enabled for binary\n");
	cfi_ptrace_test();

	execute_shadow_stack_tests();

Annotation

Implementation Notes