I wasn't CC-ed on the patch even though I'd reviewed the earlier revision.
On 12/13/23 4:17 AM, jeffxu@chromium.org wrote:
From: Jeff Xu jeffxu@chromium.org
selftest for memory sealing change in mmap() and mseal().
Signed-off-by: Jeff Xu jeffxu@chromium.org
tools/testing/selftests/mm/.gitignore | 1 + tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/config | 1 + tools/testing/selftests/mm/mseal_test.c | 2141 +++++++++++++++++++++++ 4 files changed, 2144 insertions(+) create mode 100644 tools/testing/selftests/mm/mseal_test.c
diff --git a/tools/testing/selftests/mm/.gitignore b/tools/testing/selftests/mm/.gitignore index cdc9ce4426b9..f0f22a649985 100644 --- a/tools/testing/selftests/mm/.gitignore +++ b/tools/testing/selftests/mm/.gitignore @@ -43,3 +43,4 @@ mdwe_test gup_longterm mkdirty va_high_addr_switch +mseal_test diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile index 6a9fc5693145..0c086cecc093 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -59,6 +59,7 @@ TEST_GEN_FILES += mlock2-tests TEST_GEN_FILES += mrelease_test TEST_GEN_FILES += mremap_dontunmap TEST_GEN_FILES += mremap_test +TEST_GEN_FILES += mseal_test TEST_GEN_FILES += on-fault-limit TEST_GEN_FILES += thuge-gen TEST_GEN_FILES += transhuge-stress diff --git a/tools/testing/selftests/mm/config b/tools/testing/selftests/mm/config index be087c4bc396..cf2b8780e9b1 100644 --- a/tools/testing/selftests/mm/config +++ b/tools/testing/selftests/mm/config @@ -6,3 +6,4 @@ CONFIG_TEST_HMM=m CONFIG_GUP_TEST=y CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_MEM_SOFT_DIRTY=y +CONFIG_MSEAL=y diff --git a/tools/testing/selftests/mm/mseal_test.c b/tools/testing/selftests/mm/mseal_test.c new file mode 100644 index 000000000000..0692485d8b3c --- /dev/null +++ b/tools/testing/selftests/mm/mseal_test.c @@ -0,0 +1,2141 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <sys/mman.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <stdbool.h> +#include "../kselftest.h" +#include <syscall.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <fcntl.h> +#include <assert.h> +#include <sys/ioctl.h> +#include <sys/vfs.h> +#include <sys/stat.h>
+/*
- need those definition for manually build using gcc.
- gcc -I ../../../../usr/include -DDEBUG -O3 -DDEBUG -O3 mseal_test.c -o mseal_test
- */
+#ifndef MM_SEAL_SEAL +#define MM_SEAL_SEAL 0x1 +#endif
+#ifndef MM_SEAL_BASE +#define MM_SEAL_BASE 0x2 +#endif
+#ifndef MM_SEAL_PROT_PKEY +#define MM_SEAL_PROT_PKEY 0x4 +#endif
+#ifndef MM_SEAL_DISCARD_RO_ANON +#define MM_SEAL_DISCARD_RO_ANON 0x8 +#endif
+#ifndef MAP_SEALABLE +#define MAP_SEALABLE 0x8000000 +#endif
+#ifndef PROT_SEAL_SEAL +#define PROT_SEAL_SEAL 0x04000000 +#endif
+#ifndef PROT_SEAL_BASE +#define PROT_SEAL_BASE 0x08000000 +#endif
+#ifndef PROT_SEAL_PROT_PKEY +#define PROT_SEAL_PROT_PKEY 0x10000000 +#endif
+#ifndef PROT_SEAL_DISCARD_RO_ANON +#define PROT_SEAL_DISCARD_RO_ANON 0x20000000 +#endif
+#ifndef PKEY_DISABLE_ACCESS +# define PKEY_DISABLE_ACCESS 0x1 +#endif
+#ifndef PKEY_DISABLE_WRITE +# define PKEY_DISABLE_WRITE 0x2 +#endif
+#ifndef PKEY_BITS_PER_KEY +#define PKEY_BITS_PER_PKEY 2 +#endif
+#ifndef PKEY_MASK +#define PKEY_MASK (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE) +#endif
+#ifndef DEBUG +#define LOG_TEST_ENTER() {} +#else +#define LOG_TEST_ENTER() {ksft_print_msg("%s\n", __func__); } +#endif
+#ifndef u64 +#define u64 unsigned long long +#endif
+/*
- define sys_xyx to call syscall directly.
- */
+static int sys_mseal(void *start, size_t len, int types) +{
- int sret;
- errno = 0;
- sret = syscall(__NR_mseal, start, len, types, 0);
- return sret;
+}
+int sys_mprotect(void *ptr, size_t size, unsigned long prot) +{
- int sret;
- errno = 0;
- sret = syscall(SYS_mprotect, ptr, size, prot);
- return sret;
+}
+int sys_mprotect_pkey(void *ptr, size_t size, unsigned long orig_prot,
unsigned long pkey)
+{
- int sret;
- errno = 0;
- sret = syscall(__NR_pkey_mprotect, ptr, size, orig_prot, pkey);
- return sret;
+}
+int sys_munmap(void *ptr, size_t size) +{
- int sret;
- errno = 0;
- sret = syscall(SYS_munmap, ptr, size);
- return sret;
+}
+static int sys_madvise(void *start, size_t len, int types) +{
- int sret;
- errno = 0;
- sret = syscall(__NR_madvise, start, len, types);
- return sret;
+}
+int sys_pkey_alloc(unsigned long flags, unsigned long init_val) +{
- int ret = syscall(SYS_pkey_alloc, flags, init_val);
Add empty line here.
- return ret;
+}
+static inline unsigned int __read_pkey_reg(void) +{
- unsigned int eax, edx;
- unsigned int ecx = 0;
- unsigned int pkey_reg;
- asm volatile(".byte 0x0f,0x01,0xee\n\t"
: "=a" (eax), "=d" (edx)
: "c" (ecx));
- pkey_reg = eax;
- return pkey_reg;
+}
+static inline void __write_pkey_reg(u64 pkey_reg) +{
- unsigned int eax = pkey_reg;
- unsigned int ecx = 0;
- unsigned int edx = 0;
- asm volatile(".byte 0x0f,0x01,0xef\n\t"
: : "a" (eax), "c" (ecx), "d" (edx));
- assert(pkey_reg == __read_pkey_reg());
+}
+static inline unsigned long pkey_bit_position(int pkey) +{
- return pkey * PKEY_BITS_PER_PKEY;
+}
+static inline u64 set_pkey_bits(u64 reg, int pkey, u64 flags) +{
- unsigned long shift = pkey_bit_position(pkey);
- /* mask out bits from pkey in old value */
- reg &= ~((u64)PKEY_MASK << shift);
- /* OR in new bits for pkey */
- reg |= (flags & PKEY_MASK) << shift;
- return reg;
+}
+static inline void set_pkey(int pkey, unsigned long pkey_value) +{
- unsigned long mask = (PKEY_DISABLE_ACCESS | PKEY_DISABLE_WRITE);
- u64 new_pkey_reg;
- assert(!(pkey_value & ~mask));
- new_pkey_reg = set_pkey_bits(__read_pkey_reg(), pkey, pkey_value);
- __write_pkey_reg(new_pkey_reg);
+}
+void setup_single_address(int size, void **ptrOut) +{
- void *ptr;
- ptr = mmap(NULL, size, PROT_READ, MAP_ANONYMOUS | MAP_PRIVATE | MAP_SEALABLE, -1, 0);
- assert(ptr != (void *)-1);
- *ptrOut = ptr;
+}
+void setup_single_address_sealable(int size, void **ptrOut, bool sealable) +{
- void *ptr;
- unsigned long mapflags = MAP_ANONYMOUS | MAP_PRIVATE;
- if (sealable)
mapflags |= MAP_SEALABLE;
- ptr = mmap(NULL, size, PROT_READ, mapflags, -1, 0);
- assert(ptr != (void *)-1);
- *ptrOut = ptr;
+}
+void setup_single_address_rw_sealable(int size, void **ptrOut, bool sealable) +{
- void *ptr;
- unsigned long mapflags = MAP_ANONYMOUS | MAP_PRIVATE;
- if (sealable)
mapflags |= MAP_SEALABLE;
- ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, mapflags, -1, 0);
- assert(ptr != (void *)-1);
- *ptrOut = ptr;
+}
+void clean_single_address(void *ptr, int size) +{
- int ret;
- ret = munmap(ptr, size);
- assert(!ret);
+}
+void seal_mprotect_single_address(void *ptr, int size) +{
- int ret;
- ret = sys_mseal(ptr, size, MM_SEAL_PROT_PKEY);
- assert(!ret);
+}
+void seal_discard_ro_anon_single_address(void *ptr, int size) +{
- int ret;
- ret = sys_mseal(ptr, size, MM_SEAL_DISCARD_RO_ANON);
- assert(!ret);
+}
+static void test_seal_addseals(void) +{
- LOG_TEST_ENTER();
- int ret;
- void *ptr;
- unsigned long page_size = getpagesize();
- unsigned long size = 4 * page_size;
- setup_single_address(size, &ptr);
- /* adding seal one by one */
- ret = sys_mseal(ptr, size, MM_SEAL_BASE);
- assert(!ret);
- ret = sys_mseal(ptr, size, MM_SEAL_PROT_PKEY);
- assert(!ret);
- ret = sys_mseal(ptr, size, MM_SEAL_SEAL);
- assert(!ret);
+}
+static void test_seal_addseals_combined(void) +{
- LOG_TEST_ENTER();
- int ret;
- void *ptr;
- unsigned long page_size = getpagesize();
- unsigned long size = 4 * page_size;
- setup_single_address(size, &ptr);
- ret = sys_mseal(ptr, size, MM_SEAL_PROT_PKEY);
- assert(!ret);
- /* adding multiple seals */
- ret = sys_mseal(ptr, size,
MM_SEAL_PROT_PKEY | MM_SEAL_BASE|
MM_SEAL_SEAL);
- assert(!ret);
- /* not adding more seal type, so ok. */
- ret = sys_mseal(ptr, size, MM_SEAL_BASE);
- assert(!ret);
- /* not adding more seal type, so ok. */
- ret = sys_mseal(ptr, size, MM_SEAL_SEAL);
- assert(!ret);
+}
+static void test_seal_addseals_reject(void) +{
- LOG_TEST_ENTER();
- int ret;
- void *ptr;
- unsigned long page_size = getpagesize();
- unsigned long size = 4 * page_size;
- setup_single_address(size, &ptr);
- ret = sys_mseal(ptr, size, MM_SEAL_BASE | MM_SEAL_SEAL);
- assert(!ret);
- /* MM_SEAL_SEAL is set, so not allow new seal type . */
- ret = sys_mseal(ptr, size,
MM_SEAL_PROT_PKEY | MM_SEAL_BASE | MM_SEAL_SEAL);
- assert(ret < 0);
+}
+static void test_seal_unmapped_start(void) +{
- LOG_TEST_ENTER();
- int ret;
- void *ptr;
- unsigned long page_size = getpagesize();
- unsigned long size = 4 * page_size;
- setup_single_address(size, &ptr);
- // munmap 2 pages from ptr.
Don't use different commenting styles in one file. Use /* */ for comments.
- ret = sys_munmap(ptr, 2 * page_size);
- assert(!ret);
- // mprotect will fail because 2 pages from ptr are unmapped.
- ret = sys_mprotect(ptr, size, PROT_READ | PROT_WRITE);
- assert(ret < 0);
- // mseal will fail because 2 pages from ptr are unmapped.
- ret = sys_mseal(ptr, size, MM_SEAL_SEAL);
- assert(ret < 0);
- ret = sys_mseal(ptr + 2 * page_size, 2 * page_size, MM_SEAL_SEAL);
- assert(!ret);
+}