Skip to content

Commit

Permalink
Add some tests of explicit page permissions
Browse files Browse the repository at this point in the history
One simple test that explicit CAP_RW permissions match work just like
implied permissions.  Another that attempt to demonstrate tag stripping
when a page lacks CAP_READ and one the demonstrates faults storing
without CAP_WRITE.
  • Loading branch information
brooksdavis committed Jan 22, 2021
1 parent 89f2a07 commit 36ab463
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
19 changes: 19 additions & 0 deletions bin/cheribsdtest/cheribsdtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, },
Expand Down
3 changes: 3 additions & 0 deletions bin/cheribsdtest/cheribsdtest.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
70 changes: 69 additions & 1 deletion bin/cheribsdtest/cheribsdtest_vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
*/

/*
* A few non-faulting CHERI-related virtual-memory tests.
* CHERI-related virtual-memory tests.
*/

#include <sys/cdefs.h>
Expand Down Expand Up @@ -60,6 +60,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -96,13 +97,80 @@ 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)
{
mmap_and_check_tag_stored(-1, PROT_READ | PROT_WRITE, MAP_ANON);
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)
{
Expand Down

0 comments on commit 36ab463

Please sign in to comment.