selftests/x86/lam: Add mmap and SYSCALL test cases for linear-address masking
Add mmap and SYSCALL test cases. SYSCALL test cases: - LAM supports set metadata in high bits 62:57 (LAM_U57) of a user pointer, pass the pointer to SYSCALL, SYSCALL can dereference the pointer and return correct result. - Disable LAM, pass a pointer with metadata in high bits to SYSCALL, SYSCALL returns -1 (EFAULT). MMAP test cases: - Enable LAM_U57, MMAP with low address (below bits 47), set metadata in high bits of the address, dereference the address should be allowed. - Enable LAM_U57, MMAP with high address (above bits 47), set metadata in high bits of the address, dereference the address should be allowed. 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-14-kirill.shutemov%40linux.intel.com
This commit is contained in:
committed by
Dave Hansen
parent
3de9745c12
commit
e67876962e
@@ -7,6 +7,7 @@
|
||||
#include <signal.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -29,11 +30,18 @@
|
||||
/* Specified test function bits */
|
||||
#define FUNC_MALLOC 0x1
|
||||
#define FUNC_BITS 0x2
|
||||
#define FUNC_MMAP 0x4
|
||||
#define FUNC_SYSCALL 0x8
|
||||
|
||||
#define TEST_MASK 0x3
|
||||
#define TEST_MASK 0xf
|
||||
|
||||
#define LOW_ADDR (0x1UL << 30)
|
||||
#define HIGH_ADDR (0x3UL << 48)
|
||||
|
||||
#define MALLOC_LEN 32
|
||||
|
||||
#define PAGE_SIZE (4 << 10)
|
||||
|
||||
struct testcases {
|
||||
unsigned int later;
|
||||
int expected; /* 2: SIGSEGV Error; 1: other errors */
|
||||
@@ -49,6 +57,7 @@ jmp_buf segv_env;
|
||||
static void segv_handler(int sig)
|
||||
{
|
||||
ksft_print_msg("Get segmentation fault(%d).", sig);
|
||||
|
||||
siglongjmp(segv_env, 1);
|
||||
}
|
||||
|
||||
@@ -61,6 +70,16 @@ static inline int cpu_has_lam(void)
|
||||
return (cpuinfo[0] & (1 << 26));
|
||||
}
|
||||
|
||||
/* Check 5-level page table feature in CPUID.(EAX=07H, ECX=00H):ECX.[bit 16] */
|
||||
static inline int cpu_has_la57(void)
|
||||
{
|
||||
unsigned int cpuinfo[4];
|
||||
|
||||
__cpuid_count(0x7, 0, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
|
||||
|
||||
return (cpuinfo[2] & (1 << 16));
|
||||
}
|
||||
|
||||
/*
|
||||
* Set tagged address and read back untag mask.
|
||||
* check if the untagged mask is expected.
|
||||
@@ -213,6 +232,68 @@ static int handle_malloc(struct testcases *test)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_mmap(struct testcases *test)
|
||||
{
|
||||
void *ptr;
|
||||
unsigned int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
|
||||
int ret = 0;
|
||||
|
||||
if (test->later == 0 && test->lam != 0)
|
||||
if (set_lam(test->lam) != 0)
|
||||
return 1;
|
||||
|
||||
ptr = mmap((void *)test->addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
|
||||
flags, -1, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
if (test->addr == HIGH_ADDR)
|
||||
if (!cpu_has_la57())
|
||||
return 3; /* unsupport LA57 */
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (test->later != 0 && test->lam != 0)
|
||||
if (set_lam(test->lam) != 0)
|
||||
ret = 1;
|
||||
|
||||
if (ret == 0) {
|
||||
if (sigsetjmp(segv_env, 1) == 0) {
|
||||
signal(SIGSEGV, segv_handler);
|
||||
ret = handle_lam_test(ptr, test->lam);
|
||||
} else {
|
||||
ret = 2;
|
||||
}
|
||||
}
|
||||
|
||||
munmap(ptr, PAGE_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int handle_syscall(struct testcases *test)
|
||||
{
|
||||
struct utsname unme, *pu;
|
||||
int ret = 0;
|
||||
|
||||
if (test->later == 0 && test->lam != 0)
|
||||
if (set_lam(test->lam) != 0)
|
||||
return 1;
|
||||
|
||||
if (sigsetjmp(segv_env, 1) == 0) {
|
||||
signal(SIGSEGV, segv_handler);
|
||||
pu = (struct utsname *)set_metadata((uint64_t)&unme, test->lam);
|
||||
ret = uname(pu);
|
||||
if (ret < 0)
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 2;
|
||||
}
|
||||
|
||||
if (test->later != 0 && test->lam != 0)
|
||||
if (set_lam(test->lam) != -1 && ret == 0)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fork_test(struct testcases *test)
|
||||
{
|
||||
int ret, child_ret;
|
||||
@@ -241,13 +322,20 @@ static void run_test(struct testcases *test, int count)
|
||||
struct testcases *t = test + i;
|
||||
|
||||
/* fork a process to run test case */
|
||||
tests_cnt++;
|
||||
ret = fork_test(t);
|
||||
|
||||
/* return 3 is not support LA57, the case should be skipped */
|
||||
if (ret == 3) {
|
||||
ksft_test_result_skip(t->msg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret != 0)
|
||||
ret = (t->expected == ret);
|
||||
else
|
||||
ret = !(t->expected);
|
||||
|
||||
tests_cnt++;
|
||||
ksft_test_result(ret, t->msg);
|
||||
}
|
||||
}
|
||||
@@ -268,7 +356,6 @@ static struct testcases malloc_cases[] = {
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
static struct testcases bits_cases[] = {
|
||||
{
|
||||
.test_func = handle_max_bits,
|
||||
@@ -276,11 +363,54 @@ static struct testcases bits_cases[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct testcases syscall_cases[] = {
|
||||
{
|
||||
.later = 0,
|
||||
.lam = LAM_U57_BITS,
|
||||
.test_func = handle_syscall,
|
||||
.msg = "SYSCALL: LAM_U57. syscall with metadata\n",
|
||||
},
|
||||
{
|
||||
.later = 1,
|
||||
.expected = 1,
|
||||
.lam = LAM_U57_BITS,
|
||||
.test_func = handle_syscall,
|
||||
.msg = "SYSCALL:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
|
||||
},
|
||||
};
|
||||
|
||||
static struct testcases mmap_cases[] = {
|
||||
{
|
||||
.later = 1,
|
||||
.expected = 0,
|
||||
.lam = LAM_U57_BITS,
|
||||
.addr = HIGH_ADDR,
|
||||
.test_func = handle_mmap,
|
||||
.msg = "MMAP: First mmap high address, then set LAM_U57.\n",
|
||||
},
|
||||
{
|
||||
.later = 0,
|
||||
.expected = 0,
|
||||
.lam = LAM_U57_BITS,
|
||||
.addr = HIGH_ADDR,
|
||||
.test_func = handle_mmap,
|
||||
.msg = "MMAP: First LAM_U57, then High address.\n",
|
||||
},
|
||||
{
|
||||
.later = 0,
|
||||
.expected = 0,
|
||||
.lam = LAM_U57_BITS,
|
||||
.addr = LOW_ADDR,
|
||||
.test_func = handle_mmap,
|
||||
.msg = "MMAP: First LAM_U57, then Low address.\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;\n");
|
||||
printf("\t\t0x1:malloc; 0x2:max_bits; 0x4:mmap; 0x8:syscall.\n");
|
||||
printf("\t-h: help\n");
|
||||
}
|
||||
|
||||
@@ -320,6 +450,12 @@ int main(int argc, char **argv)
|
||||
if (tests & FUNC_BITS)
|
||||
run_test(bits_cases, ARRAY_SIZE(bits_cases));
|
||||
|
||||
if (tests & FUNC_MMAP)
|
||||
run_test(mmap_cases, ARRAY_SIZE(mmap_cases));
|
||||
|
||||
if (tests & FUNC_SYSCALL)
|
||||
run_test(syscall_cases, ARRAY_SIZE(syscall_cases));
|
||||
|
||||
ksft_set_plan(tests_cnt);
|
||||
|
||||
return ksft_exit_pass();
|
||||
|
||||
Reference in New Issue
Block a user