test: add more cases for bytesEqual
This commit is contained in:
1 parent
6bc6f1ab4e
commit
ac31cd8168
1 file changed
+134
+134
@@ -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;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user