feat: extend syscall with copyUserArgv

This commit is contained in:
dualfroz committed 2026-09-08 15:36:33 +02:00
1 parent 8d63b96ad9
commit 0a1f4868dd
1 file changed
+53
+53
View File
@@ -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))