selftests/x86/lam: Add inherit test cases for linear-address masking
LAM is enabled per-thread and gets inherited on fork(2)/clone(2). exec() reverts LAM status to the default disabled state. There are two test scenarios: - Fork test cases: These cases were used to test the inheritance of LAM for per-thread, Child process generated by fork() should inherit LAM feature from parent process, Child process can get the LAM mode same as parent process. - Execve test cases: Processes generated by execve() are different from processes generated by fork(), these processes revert LAM status to disabled status. Signed-off-by: Weihong Zhang <weihong.zhang@intel.com> Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/all/20230312112612.31869-16-kirill.shutemov%40linux.intel.com
This commit is contained in:
parent
72fd6d738c
commit
833c12ce0f
@ -37,8 +37,9 @@
|
||||
#define FUNC_MMAP 0x4
|
||||
#define FUNC_SYSCALL 0x8
|
||||
#define FUNC_URING 0x10
|
||||
#define FUNC_INHERITE 0x20
|
||||
|
||||
#define TEST_MASK 0x1f
|
||||
#define TEST_MASK 0x3f
|
||||
|
||||
#define LOW_ADDR (0x1UL << 30)
|
||||
#define HIGH_ADDR (0x3UL << 48)
|
||||
@ -174,6 +175,28 @@ static unsigned long get_default_tag_bits(void)
|
||||
return lam;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set tagged address and read back untag mask.
|
||||
* check if the untag mask is expected.
|
||||
*/
|
||||
static int get_lam(void)
|
||||
{
|
||||
uint64_t ptr = 0;
|
||||
int ret = -1;
|
||||
/* Get untagged mask */
|
||||
if (syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr) == -1)
|
||||
return -1;
|
||||
|
||||
/* Check mask returned is expected */
|
||||
if (ptr == ~(LAM_U57_MASK))
|
||||
ret = LAM_U57_BITS;
|
||||
else if (ptr == -1ULL)
|
||||
ret = LAM_NONE;
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* According to LAM mode, set metadata in high bits */
|
||||
static uint64_t set_metadata(uint64_t src, unsigned long lam)
|
||||
{
|
||||
@ -581,7 +604,7 @@ out:
|
||||
|
||||
switch (lam) {
|
||||
case LAM_U57_BITS: /* Clear bits 62:57 */
|
||||
addr = (addr & ~(0x3fULL << 57));
|
||||
addr = (addr & ~(LAM_U57_MASK));
|
||||
break;
|
||||
}
|
||||
free((void *)addr);
|
||||
@ -632,6 +655,72 @@ static int fork_test(struct testcases *test)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_execve(struct testcases *test)
|
||||
{
|
||||
int ret, child_ret;
|
||||
int lam = test->lam;
|
||||
pid_t pid;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("Fork failed.");
|
||||
ret = 1;
|
||||
} else if (pid == 0) {
|
||||
char path[PATH_MAX];
|
||||
|
||||
/* Set LAM mode in parent process */
|
||||
if (set_lam(lam) != 0)
|
||||
return 1;
|
||||
|
||||
/* Get current binary's path and the binary was run by execve */
|
||||
if (readlink("/proc/self/exe", path, PATH_MAX) <= 0)
|
||||
exit(-1);
|
||||
|
||||
/* run binary to get LAM mode and return to parent process */
|
||||
if (execlp(path, path, "-t 0x0", NULL) < 0) {
|
||||
perror("error on exec");
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
wait(&child_ret);
|
||||
ret = WEXITSTATUS(child_ret);
|
||||
if (ret != LAM_NONE)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_inheritance(struct testcases *test)
|
||||
{
|
||||
int ret, child_ret;
|
||||
int lam = test->lam;
|
||||
pid_t pid;
|
||||
|
||||
/* Set LAM mode in parent process */
|
||||
if (set_lam(lam) != 0)
|
||||
return 1;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("Fork failed.");
|
||||
return 1;
|
||||
} else if (pid == 0) {
|
||||
/* Set LAM mode in parent process */
|
||||
int child_lam = get_lam();
|
||||
|
||||
exit(child_lam);
|
||||
} else {
|
||||
wait(&child_ret);
|
||||
ret = WEXITSTATUS(child_ret);
|
||||
|
||||
if (lam != ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void run_test(struct testcases *test, int count)
|
||||
{
|
||||
int i, ret = 0;
|
||||
@ -740,11 +829,26 @@ static struct testcases mmap_cases[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct testcases inheritance_cases[] = {
|
||||
{
|
||||
.expected = 0,
|
||||
.lam = LAM_U57_BITS,
|
||||
.test_func = handle_inheritance,
|
||||
.msg = "FORK: LAM_U57, child process should get LAM mode same as parent\n",
|
||||
},
|
||||
{
|
||||
.expected = 0,
|
||||
.lam = LAM_U57_BITS,
|
||||
.test_func = handle_execve,
|
||||
.msg = "EXECVE: LAM_U57, child process should get disabled LAM mode\n",
|
||||
},
|
||||
};
|
||||
|
||||
static void cmd_help(void)
|
||||
{
|
||||
printf("usage: lam [-h] [-t test list]\n");
|
||||
printf("\t-t test list: run tests specified in the test list, default:0x%x\n", TEST_MASK);
|
||||
printf("\t\t0x1:malloc; 0x2:max_bits; 0x4:mmap; 0x8:syscall; 0x10:io_uring.\n");
|
||||
printf("\t\t0x1:malloc; 0x2:max_bits; 0x4:mmap; 0x8:syscall; 0x10:io_uring; 0x20:inherit;\n");
|
||||
printf("\t-h: help\n");
|
||||
}
|
||||
|
||||
@ -764,7 +868,7 @@ int main(int argc, char **argv)
|
||||
switch (c) {
|
||||
case 't':
|
||||
tests = strtoul(optarg, NULL, 16);
|
||||
if (!(tests & TEST_MASK)) {
|
||||
if (tests && !(tests & TEST_MASK)) {
|
||||
ksft_print_msg("Invalid argument!\n");
|
||||
return -1;
|
||||
}
|
||||
@ -778,6 +882,16 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* When tests is 0, it is not a real test case;
|
||||
* the option used by test case(execve) to check the lam mode in
|
||||
* process generated by execve, the process read back lam mode and
|
||||
* check with lam mode in parent process.
|
||||
*/
|
||||
if (!tests)
|
||||
return (get_lam());
|
||||
|
||||
/* Run test cases */
|
||||
if (tests & FUNC_MALLOC)
|
||||
run_test(malloc_cases, ARRAY_SIZE(malloc_cases));
|
||||
|
||||
@ -793,6 +907,9 @@ int main(int argc, char **argv)
|
||||
if (tests & FUNC_URING)
|
||||
run_test(uring_cases, ARRAY_SIZE(uring_cases));
|
||||
|
||||
if (tests & FUNC_INHERITE)
|
||||
run_test(inheritance_cases, ARRAY_SIZE(inheritance_cases));
|
||||
|
||||
ksft_set_plan(tests_cnt);
|
||||
|
||||
return ksft_exit_pass();
|
||||
|
Loading…
x
Reference in New Issue
Block a user