From ac31cd8168eedf16ad226982be55b527148ffdf0 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Sun, 13 Sep 2026 12:54:20 +0200 Subject: [PATCH] test: add more cases for bytesEqual --- user/mmaptest.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 user/mmaptest.c diff --git a/user/mmaptest.c b/user/mmaptest.c new file mode 100644 index 0000000..74ae590 --- /dev/null +++ b/user/mmaptest.c @@ -0,0 +1,134 @@ +#include "ulib.h" + +/* + * Live ring-3 proof for mmap.c's real demand-paged mmap(2)/munmap(2), + * through the actual sysMmap/sysMunmap syscall path (not just mmapTest.c's + * own in-kernel KTEST coverage, which calls mmap.c's functions directly): + * anonymous demand-zero fill, a real write landing on that same page, a + * real file-backed mapping whose content matches the real file it names, + * (via mmapprotvictim.c) a real SIGSEGV -- not a kernel panic -- when a + * different process writes to a PROT_READ-only mapping, a real function + * call succeeding against a mapping that WAS granted PROT_EXEC, and (via + * mmapexecvictim.c) a real SIGSEGV when a different process jumps into a + * mapping that was NOT granted it -- the hardware NX enforcement fs.h's + * own mmapProtExec doc comment used to name as unimplemented. + */ + +#define mmapTestPageSize 4096 + +static int bytesEqual(const volatile unsigned char* a, const char* b, unsigned long n) +{ + for (unsigned long i = 0; i < n; i++) + if (a[i] != (unsigned char)b[i]) + return 0; + return 1; +} + +int main(void) +{ + print("mmaptest: start\n"); + + void* anon = userMmap(0, 2 * mmapTestPageSize, mmapProtRead | mmapProtWrite, mmapAnonymous, -1, 0); + if (anon == userMmapFailed) { + print("mmaptest: FAIL anon mmap\n"); + return 1; + } + volatile unsigned char* ap = (volatile unsigned char*)anon; + if (ap[0] != 0 || ap[mmapTestPageSize] != 0) { + print("mmaptest: FAIL anon page not zero-filled\n"); + return 1; + } + print("mmaptest: anon-zero-fill-ok\n"); + + ap[0] = 7; + ap[mmapTestPageSize] = 9; + if (ap[0] != 7 || ap[mmapTestPageSize] != 9) { + print("mmaptest: FAIL anon write/read mismatch\n"); + return 1; + } + print("mmaptest: anon-write-read-ok\n"); + + if (userMunmap(anon, 2 * mmapTestPageSize) != 0) { + print("mmaptest: FAIL munmap anon\n"); + return 1; + } + print("mmaptest: anon-munmap-ok\n"); + + int fd = userOpen("/etc/motd.txt", oReadOnly); + if (fd < 0) { + print("mmaptest: FAIL open motd\n"); + return 1; + } + + void* filed = userMmap(0, mmapTestPageSize, mmapProtRead, 0, fd, 0); + if (filed == userMmapFailed) { + print("mmaptest: FAIL file mmap\n"); + return 1; + } + if (!bytesEqual((const volatile unsigned char*)filed, "frostbyte ramdisk file\n", 23)) { + print("mmaptest: FAIL file-backed content mismatch\n"); + return 1; + } + print("mmaptest: file-map-content-ok\n"); + userClose(fd); + + long victim = userSpawn("/bin/mmapprotvictim", 0); + if (victim < 0) { + print("mmaptest: FAIL spawn mmapprotvictim\n"); + return 1; + } + long status = userWait(victim); + print("mmaptest: victim exit status="); + printDec(status); + print("\n"); + if (status != 128 + sigSegv) { + print("mmaptest: FAIL expected sigsegv exit status\n"); + return 1; + } + print("mmaptest: protection-sigsegv-ok\n"); + + /* A mapping that WAS granted mmapProtExec really is executable, not + just "not actively refused" -- a real function call through it, + not merely a read/write, is the only proof that means anything + given mmapexecvictim.c below proves the opposite direction. */ + void* execMem = userMmap(0, mmapTestPageSize, mmapProtRead | mmapProtWrite | mmapProtExec, + mmapAnonymous, -1, 0); + if (execMem == userMmapFailed) { + print("mmaptest: FAIL exec mmap\n"); + return 1; + } + /* x86_64: mov eax, 42; ret -- a real, self-contained function body. */ + unsigned char* code = (unsigned char*)execMem; + code[0] = 0xB8; + code[1] = 42; + code[2] = 0; + code[3] = 0; + code[4] = 0; + code[5] = 0xC3; + int (*fn)(void) = (int (*)(void))execMem; + int result = fn(); + if (result != 42) { + print("mmaptest: FAIL exec-allowed call returned wrong value\n"); + return 1; + } + print("mmaptest: exec-allowed-ok\n"); + userMunmap(execMem, mmapTestPageSize); + + long execVictim = userSpawn("/bin/mmapexecvictim", 0); + if (execVictim < 0) { + print("mmaptest: FAIL spawn mmapexecvictim\n"); + return 1; + } + long execStatus = userWait(execVictim); + print("mmaptest: exec victim exit status="); + printDec(execStatus); + print("\n"); + if (execStatus != 128 + sigSegv) { + print("mmaptest: FAIL expected sigsegv exit status for exec victim\n"); + return 1; + } + print("mmaptest: exec-denied-sigsegv-ok\n"); + + print("mmaptest: PASS\n"); + return 0; +}