From 0a1f4868dd71b5e21861753b21a450e61cff7ce4 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Tue, 8 Sep 2026 15:36:33 +0200 Subject: [PATCH] feat: extend syscall with copyUserArgv --- src/syscall.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/syscall.c b/src/syscall.c index 16847e9..8308620 100644 --- a/src/syscall.c +++ b/src/syscall.c @@ -5,10 +5,24 @@ #include "vfs.h" #include "fs.h" #include "string.h" +#include "elf.h" +#include "paging.h" +#include "signal.h" +#include "keyboard.h" +#include "pit.h" +#include "poll.h" +#include "rtc.h" +#include "mmap.h" #define userSpaceMin 0x0000000040000000ull #define userSpaceMax 0x0000800000000000ull +/* Matches kmain.c's userStackSize -- both sides map exactly one slot's + worth of stack for a freshly loaded binary, whether it was spawned at + boot (kmain.c's spawnUser, addresses picked by hand) or at runtime + (doSpawn/doExec below, addresses derived from elfSlotStackTop). */ +#define execStackSize 0x4000 + static bool userRangeOk(uint64 pointer, uint64 length) { if (pointer < userSpaceMin) @@ -34,6 +48,45 @@ static bool copyUserPath(uint64 pointer, char* dst, uint64 max) return true; } +#define execArgMaxLen 256 + +/* Copies a NULL-terminated array of user-space `const char*` (the argv + parameter of sysExec/sysSpawn -- userExec/userSpawn, ulib.c) into kernel + memory: up to elfMaxArgs (elf.h) pointers are read out of userspace one + at a time (each individually range-checked, since the array itself is + just user memory a buggy or hostile caller controls) and each string + copied via copyUserPath into `storage`, which the caller owns for as + long as it needs argvPtrs to stay valid. A null `argvPointer` (the + common "no arguments" case) is not an error -- it yields argc 0, letting + userExec(path, nullptr) mean the same as a bare execve(path) with an + otherwise-empty argv. Fails (leaving *outArgc untouched) on a bad + pointer, a string that doesn't fit `execArgMaxLen`, or an argv longer + than elfMaxArgs entries that never hits its NULL terminator. */ +static bool copyUserArgv(uint64 argvPointer, char storage[elfMaxArgs][execArgMaxLen], + const char* argvPtrs[elfMaxArgs], int* outArgc) +{ + if (argvPointer == 0) { + *outArgc = 0; + return true; + } + if (!userRangeOk(argvPointer, sizeof(uint64) * (elfMaxArgs + 1))) + return false; + + const uint64* userArgv = (const uint64*)argvPointer; + int argc = 0; + while (argc < elfMaxArgs && userArgv[argc] != 0) { + if (!copyUserPath(userArgv[argc], storage[argc], execArgMaxLen)) + return false; + argvPtrs[argc] = storage[argc]; + argc++; + } + if (argc == elfMaxArgs && userArgv[argc] != 0) + return false; + + *outArgc = argc; + return true; +} + static int64 doWrite(uint64 fd, uint64 buffer, uint64 length) { if (!userRangeOk(buffer, length))