diff --git a/bin/cheribsdtest/cheribsdtest.c b/bin/cheribsdtest/cheribsdtest.c index b8116fd5c891..78ffb73dfc6c 100644 --- a/bin/cheribsdtest/cheribsdtest.c +++ b/bin/cheribsdtest/cheribsdtest.c @@ -810,6 +810,25 @@ static const struct cheri_test cheri_tests[] = { .ct_desc = "check tags are stored for MAP_ANON pages", .ct_func = cheribsdtest_vm_tag_mmap_anon, }, + { .ct_name = "cheribsdtest_vm_tag_mmap_anon_cap_rw", + .ct_desc = "check tags are stored for MAP_ANON pages with " + "explicit page capability read/write perms", + .ct_func = cheribsdtest_vm_tag_mmap_anon_cap_rw, }, + + { .ct_name = "cheribsdtest_vm_tag_mmap_anon_cap_w", + .ct_desc = "check that a load from MAP_ANON pages without " + "PROT_CAP_READ strips tags", + .ct_func = cheribsdtest_vm_tag_mmap_anon_cap_w, }, + + { .ct_name = "cheribsdtest_vm_tag_mmap_anon_cap_none_store", + .ct_desc = "check that a store to MAP_ANON pages without " + "PROT_CAP_WRITE faults", + .ct_func = cheribsdtest_vm_tag_mmap_anon_cap_none_store, + .ct_flags = CT_FLAG_SIGNAL | CT_FLAG_SI_CODE | CT_FLAG_SI_TRAPNO, + .ct_signum = SIGSEGV, + .ct_si_code = SEGV_STORETAG, + .ct_si_trapno = TRAPNO_CHERI, }, + { .ct_name = "cheribsdtest_vm_tag_shm_open_anon_shared", .ct_desc = "check tags are stored for SHM_ANON MAP_SHARED pages", .ct_func = cheribsdtest_vm_tag_shm_open_anon_shared, }, diff --git a/bin/cheribsdtest/cheribsdtest.h b/bin/cheribsdtest/cheribsdtest.h index 07c4cf2b9d44..81a7ea5fd53d 100644 --- a/bin/cheribsdtest/cheribsdtest.h +++ b/bin/cheribsdtest/cheribsdtest.h @@ -634,6 +634,9 @@ DECLARE_CHERIBSD_TEST(test_tls_threads); /* cheribsdtest_vm.c */ DECLARE_CHERIBSD_TEST(cheribsdtest_vm_tag_mmap_anon); +DECLARE_CHERIBSD_TEST(cheribsdtest_vm_tag_mmap_anon_cap_rw); +DECLARE_CHERIBSD_TEST(cheribsdtest_vm_tag_mmap_anon_cap_w); +DECLARE_CHERIBSD_TEST(cheribsdtest_vm_tag_mmap_anon_cap_none_store); DECLARE_CHERIBSD_TEST(cheribsdtest_vm_tag_shm_open_anon_shared); DECLARE_CHERIBSD_TEST(cheribsdtest_vm_tag_shm_open_anon_private); DECLARE_CHERIBSD_TEST(cheribsdtest_vm_tag_shm_open_anon_shared2x); diff --git a/bin/cheribsdtest/cheribsdtest_vm.c b/bin/cheribsdtest/cheribsdtest_vm.c index 0a6a752fa734..7da3e390d9d0 100644 --- a/bin/cheribsdtest/cheribsdtest_vm.c +++ b/bin/cheribsdtest/cheribsdtest_vm.c @@ -29,7 +29,7 @@ */ /* - * A few non-faulting CHERI-related virtual-memory tests. + * CHERI-related virtual-memory tests. */ #include @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,48 @@ mmap_and_check_tag_stored(int fd, int protflags, int mapflags) CHERIBSDTEST_CHECK_SYSCALL(close(fd)); } +static void +mmap_and_check_tag_stripped(int fd, int protflags, int mapflags) +{ + void * __capability volatile *cp; + void * __capability cp_value; + int max_prot, prot, v; + + /* Make sure we can load and store through the capability. */ + max_prot = PROT_MAX_IMPLIED(protflags) | PROT_CAP_READ | PROT_CAP_WRITE; + /* Make sure we can store a capability to the page. */ + prot = PROT_EXTRACT(protflags) | PROT_CAP_WRITE; + cp = CHERIBSDTEST_CHECK_SYSCALL(mmap(NULL, getpagesize(), + prot | PROT_MAX(max_prot), mapflags, fd, 0)); + cp_value = cheri_ptr(&v, sizeof(v)); + *cp = cp_value; + cp_value = *cp; + CHERIBSDTEST_VERIFY2(cheri_gettag(cp_value) == 0, "tag preserved"); + CHERIBSDTEST_CHECK_SYSCALL(munmap(__DEVOLATILE(void *, cp), + getpagesize())); + if (fd != -1) + CHERIBSDTEST_CHECK_SYSCALL(close(fd)); +} + +static void +mmap_and_page_store_fault(int fd, int protflags, int mapflags) +{ + void * __capability volatile *cp; + void * __capability cp_value; + int v; + + /* + * Add PROT_CAP_WRITE to PROT_MAX so the fault is triggered in + * the MMU. + */ + cp = CHERIBSDTEST_CHECK_SYSCALL(mmap(NULL, getpagesize(), + protflags | PROT_MAX(PROT_CAP_WRITE | PROT_MAX_IMPLIED(protflags)), + mapflags, fd, 0)); + cp_value = cheri_ptr(&v, sizeof(v)); + *cp = cp_value; + cheribsdtest_failure_errx("failed to fault with prot 0x%x", protflags); +} + void cheribsdtest_vm_tag_mmap_anon(const struct cheri_test *ctp __unused) { @@ -103,6 +146,31 @@ cheribsdtest_vm_tag_mmap_anon(const struct cheri_test *ctp __unused) cheribsdtest_success(); } +void +cheribsdtest_vm_tag_mmap_anon_cap_rw(const struct cheri_test *ctp __unused) +{ + mmap_and_check_tag_stored(-1, + PROT_READ | PROT_WRITE | PROT_CAP_READ | PROT_CAP_WRITE, MAP_ANON); + cheribsdtest_success(); +} + +void +cheribsdtest_vm_tag_mmap_anon_cap_w( + const struct cheri_test *ctp __unused) +{ + mmap_and_check_tag_stripped(-1, + PROT_READ | PROT_WRITE | PROT_CAP_WRITE, MAP_ANON); + cheribsdtest_success(); +} + +void +cheribsdtest_vm_tag_mmap_anon_cap_none_store( + const struct cheri_test *ctp __unused) +{ + mmap_and_page_store_fault(-1, PROT_READ | PROT_WRITE | PROT_CAP_NONE, + MAP_ANON); +} + void cheribsdtest_vm_tag_shm_open_anon_shared(const struct cheri_test *ctp __unused) {