Commit 833c12ce authored by Weihong Zhang's avatar Weihong Zhang Committed by Dave Hansen

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: default avatarWeihong Zhang <weihong.zhang@intel.com>
Signed-off-by: default avatarKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: default avatarDave Hansen <dave.hansen@linux.intel.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/20230312112612.31869-16-kirill.shutemov%40linux.intel.com
parent 72fd6d73
......@@ -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 @@ int do_uring(unsigned long lam)
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();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment