feat: add streq
This commit is contained in:
1 parent
8962d40688
commit
412e4fd9a1
4 files changed
+182
No files matched your search
@@ -0,0 +1,40 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spawned by mmaptest.c to prove that a real jump into a mapping that never
|
||||||
|
* asked for mmapProtExec turns into a genuine SIGSEGV (isr.c's tryResolve-
|
||||||
|
* UserPageFault I/D-bit short-circuit, not an infinite fault loop and not
|
||||||
|
* a kernel-wide panic) rather than silently letting the CPU execute
|
||||||
|
* whatever bytes happen to sit there -- the exact NX enforcement gap
|
||||||
|
* fs.h's own mmapProtExec doc comment used to name as unimplemented. This
|
||||||
|
* process is expected to die, not return 0; its own final "FAIL" print/
|
||||||
|
* return only runs if that protection was somehow NOT enforced.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef void (*victimFn)(void);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("mmapexecvictim: start\n");
|
||||||
|
|
||||||
|
void* addr = userMmap(0, 4096, mmapProtRead | mmapProtWrite, mmapAnonymous, -1, 0);
|
||||||
|
if (addr == userMmapFailed) {
|
||||||
|
print("mmapexecvictim: FAIL mmap\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A real `ret` instruction (0xC3) -- harmless if it ever actually runs,
|
||||||
|
since the point is that it must never get the chance to. */
|
||||||
|
volatile unsigned char* code = (volatile unsigned char*)addr;
|
||||||
|
code[0] = 0xC3;
|
||||||
|
print("mmapexecvictim: write-ok\n");
|
||||||
|
|
||||||
|
/* PROT_READ|PROT_WRITE only -- no PROT_EXEC -- so this call's own
|
||||||
|
instruction fetch must be refused by the CPU's own NX bit and turn
|
||||||
|
into a real SIGSEGV delivered against THIS process alone. */
|
||||||
|
victimFn fn = (victimFn)addr;
|
||||||
|
fn();
|
||||||
|
|
||||||
|
print("mmapexecvictim: FAIL exec should have segfaulted\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Spawned by mmaptest.c to prove that a real write against a PROT_READ-only
|
||||||
|
* mapping turns into a genuine SIGSEGV (isr.c's #PF handler) rather than a
|
||||||
|
* kernel-wide panic -- this process is expected to die, not return 0. Its
|
||||||
|
* own final "FAIL" print/return only runs if that protection was somehow
|
||||||
|
* NOT enforced.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("mmapprotvictim: start\n");
|
||||||
|
|
||||||
|
int fd = userOpen("/etc/motd.txt", oReadOnly);
|
||||||
|
if (fd < 0) {
|
||||||
|
print("mmapprotvictim: FAIL open\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* addr = userMmap(0, 4096, mmapProtRead, 0, fd, 0);
|
||||||
|
if (addr == userMmapFailed) {
|
||||||
|
print("mmapprotvictim: FAIL mmap\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile char* p = (volatile char*)addr;
|
||||||
|
if (p[0] != 'f') {
|
||||||
|
print("mmapprotvictim: FAIL unexpected read content\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("mmapprotvictim: read-ok\n");
|
||||||
|
|
||||||
|
/* PROT_READ only -- this write must be refused by mmapFaultHandler and
|
||||||
|
turn into a real SIGSEGV delivered against THIS process alone. */
|
||||||
|
p[0] = 'X';
|
||||||
|
|
||||||
|
print("mmapprotvictim: FAIL write should have segfaulted\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Boot-spawned independently of namedwriter.c (see kmain.c's spawnUser
|
||||||
|
* calls) -- unlike fiforeader.c/fifowriter.c, which fifomaster.c spawns as
|
||||||
|
* its own children and hands a shared pipe.h handle to via argv, this
|
||||||
|
* process and namedwriter.c have no relationship at all beyond both being
|
||||||
|
* launched at boot: neither one's pid, argv, or fd table ever mentions the
|
||||||
|
* other. The only thing they share is agreeing on the path "/tmp/rendezvous"
|
||||||
|
* (mkfifo'd by kmain.c before either is spawned) -- proving vfsMkfifo/
|
||||||
|
* vfsOpen (vfs.h) really do let two unrelated processes rendezvous purely
|
||||||
|
* through the filesystem namespace, the gap FALA 11 explicitly left open.
|
||||||
|
* Opens for read immediately, well before namedwriter.c's deliberate sleep
|
||||||
|
* elapses, so the blocking read() below has to genuinely park across many
|
||||||
|
* timer ticks and be woken later -- not just win a race against data that
|
||||||
|
* was already sitting in the pipe.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define namedPipePath "/tmp/rendezvous"
|
||||||
|
|
||||||
|
static int streq(const char* a, const char* b)
|
||||||
|
{
|
||||||
|
while (*a && *a == *b) {
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
return *a == *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("namedreader: start, pid=");
|
||||||
|
printDec(userGetpid());
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
long fd = userOpen(namedPipePath, oReadOnly);
|
||||||
|
if (fd < 0) {
|
||||||
|
print("namedreader: FAIL open\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
print("namedreader: opened, blocking on read\n");
|
||||||
|
char buffer[64];
|
||||||
|
long got = userRead((int)fd, buffer, sizeof(buffer) - 1);
|
||||||
|
if (got <= 0) {
|
||||||
|
print("namedreader: FAIL read\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
buffer[got] = 0;
|
||||||
|
|
||||||
|
print("namedreader: got: ");
|
||||||
|
print(buffer);
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
int ok = streq(buffer, "hello via named pipe");
|
||||||
|
print(ok ? "namedreader: payload-ok\n" : "namedreader: payload-FAIL\n");
|
||||||
|
|
||||||
|
userClose((int)fd);
|
||||||
|
return ok ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#include "ulib.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sibling of namedreader.c -- see its header comment for the full picture.
|
||||||
|
* Sleeps well past when namedreader.c (spawned moments earlier, at boot)
|
||||||
|
* will already be parked in a blocking read() on the still-empty named
|
||||||
|
* pipe, so the write below has to actually wake it back up (schedWakeChannel
|
||||||
|
* via pipeWrite, pipe.c) instead of the reader simply finding data already
|
||||||
|
* waiting -- same proof pattern fifowriter.c uses for the handle-based
|
||||||
|
* shared pipe, now for a path-based one neither side had to be told about
|
||||||
|
* by a common parent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define namedPipePath "/tmp/rendezvous"
|
||||||
|
#define namedWriterDelayMs 200
|
||||||
|
|
||||||
|
static const char* payload = "hello via named pipe";
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
print("namedwriter: start, pid=");
|
||||||
|
printDec(userGetpid());
|
||||||
|
print("\n");
|
||||||
|
|
||||||
|
userSleep(namedWriterDelayMs);
|
||||||
|
|
||||||
|
long fd = userOpen(namedPipePath, oWriteOnly);
|
||||||
|
if (fd < 0) {
|
||||||
|
print("namedwriter: FAIL open\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
long written = userWrite((int)fd, payload, stringLength(payload));
|
||||||
|
if (written != (long)stringLength(payload)) {
|
||||||
|
print("namedwriter: FAIL short/failed write\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
print("namedwriter: wrote payload\n");
|
||||||
|
|
||||||
|
userClose((int)fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user