mirror of
https://github.com/raspberrypi/linux.git
synced 2026-01-02 15:53:42 +00:00
selftests/powerpc/dexcr: Add DEXCR prctl interface test
Some basic tests of the prctl interface of the DEXCR. Signed-off-by: Benjamin Gray <bgray@linux.ibm.com> [mpe: Add missing SPDX tag] Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://msgid.link/20240417112325.728010-6-bgray@linux.ibm.com
This commit is contained in:
committed by
Michael Ellerman
parent
628d701f2d
commit
5bfa66bf86
@@ -1,2 +1,3 @@
|
||||
dexcr_test
|
||||
hashchk_test
|
||||
lsdexcr
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
TEST_GEN_PROGS := hashchk_test
|
||||
TEST_GEN_PROGS := dexcr_test hashchk_test
|
||||
TEST_GEN_FILES := lsdexcr
|
||||
|
||||
include ../../lib.mk
|
||||
include ../flags.mk
|
||||
|
||||
CFLAGS += $(KHDR_INCLUDES)
|
||||
|
||||
$(OUTPUT)/hashchk_test: CFLAGS += -fno-pie -no-pie $(call cc-option,-mno-rop-protect)
|
||||
|
||||
$(TEST_GEN_PROGS): ../harness.c ../utils.c ./dexcr.c
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
@@ -43,6 +44,45 @@ out:
|
||||
return exists;
|
||||
}
|
||||
|
||||
unsigned int pr_which_to_aspect(unsigned long which)
|
||||
{
|
||||
switch (which) {
|
||||
case PR_PPC_DEXCR_SBHE:
|
||||
return DEXCR_PR_SBHE;
|
||||
case PR_PPC_DEXCR_IBRTPD:
|
||||
return DEXCR_PR_IBRTPD;
|
||||
case PR_PPC_DEXCR_SRAPD:
|
||||
return DEXCR_PR_SRAPD;
|
||||
case PR_PPC_DEXCR_NPHIE:
|
||||
return DEXCR_PR_NPHIE;
|
||||
default:
|
||||
FAIL_IF_EXIT_MSG(true, "unknown PR aspect");
|
||||
}
|
||||
}
|
||||
|
||||
int pr_get_dexcr(unsigned long which)
|
||||
{
|
||||
return prctl(PR_PPC_GET_DEXCR, which, 0UL, 0UL, 0UL);
|
||||
}
|
||||
|
||||
int pr_set_dexcr(unsigned long which, unsigned long ctrl)
|
||||
{
|
||||
return prctl(PR_PPC_SET_DEXCR, which, ctrl, 0UL, 0UL);
|
||||
}
|
||||
|
||||
bool pr_dexcr_aspect_supported(unsigned long which)
|
||||
{
|
||||
if (pr_get_dexcr(which) == -1)
|
||||
return errno == ENODEV;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pr_dexcr_aspect_editable(unsigned long which)
|
||||
{
|
||||
return pr_get_dexcr(which) & PR_PPC_DEXCR_CTRL_EDITABLE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just test if a bad hashchk triggers a signal, without checking
|
||||
* for support or if the NPHIE aspect is enabled.
|
||||
|
||||
@@ -28,6 +28,16 @@
|
||||
|
||||
bool dexcr_exists(void);
|
||||
|
||||
bool pr_dexcr_aspect_supported(unsigned long which);
|
||||
|
||||
bool pr_dexcr_aspect_editable(unsigned long which);
|
||||
|
||||
int pr_get_dexcr(unsigned long pr_aspect);
|
||||
|
||||
int pr_set_dexcr(unsigned long pr_aspect, unsigned long ctrl);
|
||||
|
||||
unsigned int pr_which_to_aspect(unsigned long which);
|
||||
|
||||
bool hashchk_triggers(void);
|
||||
|
||||
enum dexcr_source {
|
||||
|
||||
215
tools/testing/selftests/powerpc/dexcr/dexcr_test.c
Normal file
215
tools/testing/selftests/powerpc/dexcr/dexcr_test.c
Normal file
@@ -0,0 +1,215 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dexcr.h"
|
||||
#include "utils.h"
|
||||
|
||||
/*
|
||||
* Helper function for testing the behaviour of a newly exec-ed process
|
||||
*/
|
||||
static int dexcr_prctl_onexec_test_child(unsigned long which, const char *status)
|
||||
{
|
||||
unsigned long dexcr = mfspr(SPRN_DEXCR_RO);
|
||||
unsigned long aspect = pr_which_to_aspect(which);
|
||||
int ctrl = pr_get_dexcr(which);
|
||||
|
||||
if (!strcmp(status, "set")) {
|
||||
FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET),
|
||||
"setting aspect across exec not applied");
|
||||
|
||||
FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC),
|
||||
"setting aspect across exec not inherited");
|
||||
|
||||
FAIL_IF_EXIT_MSG(!(aspect & dexcr), "setting aspect across exec did not take effect");
|
||||
} else if (!strcmp(status, "clear")) {
|
||||
FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR),
|
||||
"clearing aspect across exec not applied");
|
||||
|
||||
FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC),
|
||||
"clearing aspect across exec not inherited");
|
||||
|
||||
FAIL_IF_EXIT_MSG(aspect & dexcr, "clearing aspect across exec did not take effect");
|
||||
} else {
|
||||
FAIL_IF_EXIT_MSG(true, "unknown expected status");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the given prctl value can be manipulated freely
|
||||
*/
|
||||
static int dexcr_prctl_aspect_test(unsigned long which)
|
||||
{
|
||||
unsigned long aspect = pr_which_to_aspect(which);
|
||||
pid_t pid;
|
||||
int ctrl;
|
||||
int err;
|
||||
int errno_save;
|
||||
|
||||
SKIP_IF_MSG(!dexcr_exists(), "DEXCR not supported");
|
||||
SKIP_IF_MSG(!pr_dexcr_aspect_supported(which), "DEXCR aspect not supported");
|
||||
SKIP_IF_MSG(!pr_dexcr_aspect_editable(which), "DEXCR aspect not editable with prctl");
|
||||
|
||||
/* We reject invalid combinations of arguments */
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR);
|
||||
errno_save = errno;
|
||||
FAIL_IF_MSG(err != -1, "simultaneous set and clear should be rejected");
|
||||
FAIL_IF_MSG(errno_save != EINVAL, "simultaneous set and clear should be rejected with EINVAL");
|
||||
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET_ONEXEC | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
|
||||
errno_save = errno;
|
||||
FAIL_IF_MSG(err != -1, "simultaneous set and clear on exec should be rejected");
|
||||
FAIL_IF_MSG(errno_save != EINVAL, "simultaneous set and clear on exec should be rejected with EINVAL");
|
||||
|
||||
/* We set the aspect */
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET);
|
||||
FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET failed");
|
||||
|
||||
ctrl = pr_get_dexcr(which);
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET), "config value not PR_PPC_DEXCR_CTRL_SET");
|
||||
FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_CLEAR, "config value unexpected clear flag");
|
||||
FAIL_IF_MSG(!(aspect & mfspr(SPRN_DEXCR_RO)), "setting aspect did not take effect");
|
||||
|
||||
/* We clear the aspect */
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR);
|
||||
FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR failed");
|
||||
|
||||
ctrl = pr_get_dexcr(which);
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "config value not PR_PPC_DEXCR_CTRL_CLEAR");
|
||||
FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_SET, "config value unexpected set flag");
|
||||
FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "clearing aspect did not take effect");
|
||||
|
||||
/* We make it set on exec (doesn't change our current value) */
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET_ONEXEC);
|
||||
FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET_ONEXEC failed");
|
||||
|
||||
ctrl = pr_get_dexcr(which);
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "process aspect should still be cleared");
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_SET_ONEXEC");
|
||||
FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC, "config value unexpected clear on exec flag");
|
||||
FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "scheduling aspect to set on exec should not change it now");
|
||||
|
||||
/* We make it clear on exec (doesn't change our current value) */
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
|
||||
FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed");
|
||||
|
||||
ctrl = pr_get_dexcr(which);
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "process aspect config should still be cleared");
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC");
|
||||
FAIL_IF_MSG(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC, "config value unexpected set on exec flag");
|
||||
FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "process aspect should still be cleared");
|
||||
|
||||
/* We allow setting the current and on-exec value in a single call */
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
|
||||
FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed");
|
||||
|
||||
ctrl = pr_get_dexcr(which);
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET), "config value not PR_PPC_DEXCR_CTRL_SET");
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC");
|
||||
FAIL_IF_MSG(!(aspect & mfspr(SPRN_DEXCR_RO)), "process aspect should be set");
|
||||
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_CLEAR | PR_PPC_DEXCR_CTRL_SET_ONEXEC);
|
||||
FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_CLEAR | PR_PPC_DEXCR_CTRL_SET_ONEXEC failed");
|
||||
|
||||
ctrl = pr_get_dexcr(which);
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR), "config value not PR_PPC_DEXCR_CTRL_CLEAR");
|
||||
FAIL_IF_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC), "config value not PR_PPC_DEXCR_CTRL_SET_ONEXEC");
|
||||
FAIL_IF_MSG(aspect & mfspr(SPRN_DEXCR_RO), "process aspect should be clear");
|
||||
|
||||
/* Verify the onexec value is applied across exec */
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
char which_str[32] = {};
|
||||
char *args[] = { "dexcr_prctl_onexec_test_child", which_str, "set", NULL };
|
||||
unsigned int ctrl = pr_get_dexcr(which);
|
||||
|
||||
sprintf(which_str, "%lu", which);
|
||||
|
||||
FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_SET_ONEXEC),
|
||||
"setting aspect on exec not copied across fork");
|
||||
|
||||
FAIL_IF_EXIT_MSG(mfspr(SPRN_DEXCR_RO) & aspect,
|
||||
"setting aspect on exec wrongly applied to fork");
|
||||
|
||||
execve("/proc/self/exe", args, NULL);
|
||||
_exit(errno);
|
||||
}
|
||||
await_child_success(pid);
|
||||
|
||||
err = pr_set_dexcr(which, PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC);
|
||||
FAIL_IF_MSG(err, "PR_PPC_DEXCR_CTRL_SET | PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC failed");
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
char which_str[32] = {};
|
||||
char *args[] = { "dexcr_prctl_onexec_test_child", which_str, "clear", NULL };
|
||||
unsigned int ctrl = pr_get_dexcr(which);
|
||||
|
||||
sprintf(which_str, "%lu", which);
|
||||
|
||||
FAIL_IF_EXIT_MSG(!(ctrl & PR_PPC_DEXCR_CTRL_CLEAR_ONEXEC),
|
||||
"clearing aspect on exec not copied across fork");
|
||||
|
||||
FAIL_IF_EXIT_MSG(!(mfspr(SPRN_DEXCR_RO) & aspect),
|
||||
"clearing aspect on exec wrongly applied to fork");
|
||||
|
||||
execve("/proc/self/exe", args, NULL);
|
||||
_exit(errno);
|
||||
}
|
||||
await_child_success(pid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dexcr_prctl_ibrtpd_test(void)
|
||||
{
|
||||
return dexcr_prctl_aspect_test(PR_PPC_DEXCR_IBRTPD);
|
||||
}
|
||||
|
||||
static int dexcr_prctl_srapd_test(void)
|
||||
{
|
||||
return dexcr_prctl_aspect_test(PR_PPC_DEXCR_SRAPD);
|
||||
}
|
||||
|
||||
static int dexcr_prctl_nphie_test(void)
|
||||
{
|
||||
return dexcr_prctl_aspect_test(PR_PPC_DEXCR_NPHIE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/*
|
||||
* Some tests require checking what happens across exec, so we may be
|
||||
* invoked as the child of a particular test
|
||||
*/
|
||||
if (argc > 1) {
|
||||
if (argc == 3 && !strcmp(argv[0], "dexcr_prctl_onexec_test_child")) {
|
||||
unsigned long which;
|
||||
|
||||
err = parse_ulong(argv[1], strlen(argv[1]), &which, 10);
|
||||
FAIL_IF_MSG(err, "failed to parse which value for child");
|
||||
|
||||
return dexcr_prctl_onexec_test_child(which, argv[2]);
|
||||
}
|
||||
|
||||
FAIL_IF_MSG(true, "unknown test case");
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we are the main test invocation and run the full suite
|
||||
*/
|
||||
err |= test_harness(dexcr_prctl_ibrtpd_test, "dexcr_prctl_ibrtpd");
|
||||
err |= test_harness(dexcr_prctl_srapd_test, "dexcr_prctl_srapd");
|
||||
err |= test_harness(dexcr_prctl_nphie_test, "dexcr_prctl_nphie");
|
||||
|
||||
return err;
|
||||
}
|
||||
Reference in New Issue
Block a user