Skip to content

Commit 2745940

Browse files
committed
cheritest: minimal capdirty test
1 parent 00cc0c2 commit 2745940

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

bin/cheritest/cheritest.c

+4
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,10 @@ static const struct cheri_test cheri_tests[] = {
10301030
.ct_desc = "read capabilities from a faulted copy-on-write page",
10311031
.ct_func = cheritest_vm_cow_write, },
10321032

1033+
{ .ct_name = "cheritest_vm_capdirty",
1034+
.ct_desc = "verify capdirty marking and mincore",
1035+
.ct_func = cheritest_vm_capdirty, },
1036+
10331037
{ .ct_name = "cheritest_vm_swap",
10341038
.ct_desc = "check tags are swapped out by swap pager",
10351039
.ct_func = cheritest_vm_swap,

bin/cheritest/cheritest.h

+1
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ DECLARE_CHERI_TEST(cheritest_vm_tag_tmpfile_private);
554554
DECLARE_CHERI_TEST(cheritest_vm_tag_tmpfile_private_prefault);
555555
DECLARE_CHERI_TEST(cheritest_vm_cow_read);
556556
DECLARE_CHERI_TEST(cheritest_vm_cow_write);
557+
DECLARE_CHERI_TEST(cheritest_vm_capdirty);
557558
const char *xfail_need_writable_tmp(const char *name);
558559

559560
/* cheritest_vm_swap.c */

bin/cheritest/cheritest_vm.c

+62
Original file line numberDiff line numberDiff line change
@@ -602,3 +602,65 @@ cheritest_vm_cow_write(const struct cheri_test *ctp __unused)
602602
CHERITEST_CHECK_SYSCALL(close(fd));
603603
cheritest_success();
604604
}
605+
606+
/* Store a cap to a page and check that mincore reports it dirty */
607+
void
608+
cheritest_vm_capdirty(const struct cheri_test *ctp __unused)
609+
{
610+
static const size_t npg = 2;
611+
size_t sz = npg * getpagesize();
612+
613+
void * __capability * pg0;
614+
unsigned char mcv[npg] = { 0 };
615+
616+
pg0 = CHERITEST_CHECK_SYSCALL(mmap(NULL, sz,
617+
PROT_READ | PROT_WRITE, MAP_ANON, -1, 0));
618+
619+
void * __capability * pg1 = (void *)&((char *)pg0)[getpagesize()];
620+
621+
CHERITEST_CHECK_SYSCALL(mincore(pg0, sz, &mcv[0]));
622+
CHERITEST_VERIFY2(mcv[0] == 0, "page 0 status 0");
623+
CHERITEST_VERIFY2(mcv[1] == 0, "page 1 status 0");
624+
625+
*(char *)pg0 = 0x42;
626+
627+
CHERITEST_CHECK_SYSCALL(mincore(pg0, sz, &mcv[0]));
628+
CHERITEST_VERIFY2((mcv[0] & MINCORE_MODIFIED) != 0, "page 0 modified 1");
629+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPSTORE) != 0, "page 0 capstore 1");
630+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPDIRTY) == 0, "page 0 !capdirty 1");
631+
CHERITEST_VERIFY2(mcv[1] == 0, "page 1 status 1");
632+
633+
/*
634+
* To really spot-check what's going on, kick on user-mode tracing.
635+
* Assuming we haven't fast-path'd anything, we should get a series of
636+
* traps from the hardware. The slowest expected case is something
637+
* like this:
638+
*
639+
* 1. miss (puts the RO zero page in place)
640+
* 2. write (allocates physical frame)
641+
* 3. capdirty (just sets capdirty bit)
642+
*
643+
* Hardware should merge the first two together, giving us a "miss for
644+
* store" exception that causes the kernel to jump up to the allocated
645+
* physical frame immediately.
646+
*
647+
* CHERI-MIPS defines its capdirty trap to happen only for Valid, Dirty
648+
* entries, so that the capdirty emulation trap does not need to check,
649+
* so at least there there will always be two traps. Other CHERI archs
650+
* may be able to conflate this down to one trap.
651+
*/
652+
// CHERI_START_USER_TRACE;
653+
*pg1 = (void * __capability)pg0;
654+
// CHERI_STOP_USER_TRACE;
655+
656+
CHERITEST_CHECK_SYSCALL(mincore(pg0, sz, &mcv[0]));
657+
CHERITEST_VERIFY2((mcv[0] & MINCORE_MODIFIED) != 0, "page 0 modified 2");
658+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPSTORE) != 0, "page 0 capstore 2");
659+
CHERITEST_VERIFY2((mcv[0] & MINCORE_CAPDIRTY) == 0, "page 0 !capdirty 2");
660+
CHERITEST_VERIFY2((mcv[1] & MINCORE_MODIFIED) != 0, "page 1 modified 2");
661+
CHERITEST_VERIFY2((mcv[1] & MINCORE_CAPSTORE) != 0, "page 1 capstore 2");
662+
CHERITEST_VERIFY2((mcv[1] & MINCORE_CAPDIRTY) != 0, "page 1 capdirty 2");
663+
664+
CHERITEST_CHECK_SYSCALL(munmap(pg0, sz));
665+
cheritest_success();
666+
}

0 commit comments

Comments
 (0)