feat: expand syscall

This commit is contained in:
dualfroz committed 2026-09-08 17:23:07 +02:00
1 parent 643fa45f6a
commit aad9d4ece8
1 file changed
+173
+173
View File
@@ -444,6 +444,179 @@ uint64 syscallDispatch(Registers* regs)
regs->rax = (uint64)(int64)vfsUnlink(path);
return (uint64)regs;
}
case sysRmdir: {
char path[256];
if (!copyUserPath(regs->rdi, path, sizeof(path)))
regs->rax = (uint64)-1;
else
regs->rax = (uint64)(int64)vfsRmdir(path);
return (uint64)regs;
}
case sysChmod: {
char path[256];
if (!copyUserPath(regs->rdi, path, sizeof(path)))
regs->rax = (uint64)-1;
else
regs->rax = (uint64)(int64)vfsChmod(path, (uint32)regs->rsi);
return (uint64)regs;
}
case sysChown: {
char path[256];
if (!copyUserPath(regs->rdi, path, sizeof(path)))
regs->rax = (uint64)-1;
else
regs->rax = (uint64)(int64)vfsChown(path, (uint32)regs->rsi);
return (uint64)regs;
}
case sysGetuid:
/* Real getuid(2): no arguments, always succeeds, straight through
to the calling thread's own credential. */
regs->rax = (uint64)currentThreadUid();
return (uint64)regs;
case sysSetuid:
/* Real setuid(2): currentThreadSetUid (sched.h) itself enforces the
actual privilege rule (uid 0 may become anyone; anyone else may
only pass their own current uid back in) -- this dispatch case
does no additional validation of its own, matching sysChdir's own
"the underlying function already checks everything" split. */
regs->rax = currentThreadSetUid((uint32)regs->rdi) ? 0 : (uint64)-1;
return (uint64)regs;
case sysGetgid:
/* Real getgid(2): same shape as sysGetuid above. */
regs->rax = (uint64)currentThreadGid();
return (uint64)regs;
case sysSetgid:
/* Real setgid(2): currentThreadSetGid (sched.h) itself enforces the
actual privilege rule (gated by this thread's own UID, not GID --
see that function's own doc comment). */
regs->rax = currentThreadSetGid((uint32)regs->rdi) ? 0 : (uint64)-1;
return (uint64)regs;
case sysChgrp: {
char path[256];
if (!copyUserPath(regs->rdi, path, sizeof(path)))
regs->rax = (uint64)-1;
else
regs->rax = (uint64)(int64)vfsChgrp(path, (uint32)regs->rsi);
return (uint64)regs;
}
case sysPidfdOpen:
/* vfsPidfdOpen (vfs.c) already does every validity check pidfd.h's
own pidfdOpen needs (id 0/out-of-range/already-unused target) and
the fd-table installation vfsPipe/vfsPipeAttach's own dispatch
cases above delegate the same way -- nothing left for this
handler to add. */
regs->rax = (uint64)vfsPidfdOpen((uint32)regs->rdi);
return (uint64)regs;
case sysPidfdSend: {
/* vfsPidfdTarget folds "is this fd even a live pidfd" and "has the
original target since been reaped/recycled" (pidfd.h's own
generation check) into one call -- a stale handle is rejected
right here, before sigRaiseInfo ever sees a pid, which is
exactly the ABA-safety pidfd.h exists to provide over a raw
userSigSend(pid, signum) on a cached pid (see pidfd.h's own file
comment). Otherwise identical to sysSigSend's own single-target
path just above (same siCodeUser/senderPid convention, same
sigKill/sigStop bypasses already living inside sigRaiseInfo). */
uint32 target = vfsPidfdTarget((int)regs->rdi);
if (target == threadInvalidId) {
regs->rax = (uint64)-1;
return (uint64)regs;
}
int signum = (int)regs->rsi;
bool ok = sigRaiseInfo(target, signum, siCodeUser, (int)currentThreadId(), 0);
regs->rax = ok ? 0 : (uint64)-1;
return (uint64)regs;
}
case sysPidfdWait: {
/* Same retry-the-syscall park pattern as sysWait's own specific-pid
path below, just resolving the target through a pidfd instead of
a raw pid -- re-resolved on EVERY retry (not just the first
check), so a target that gets reaped by someone else while this
thread is blocked is caught the instant this thread wakes back
up, rather than only at the moment sysPidfdWait was first called.
threadJoin(target) below only ever reaps a thread this exact
check just proved is threadDead AND still the same incarnation
this handle was opened on, so there is no risk of it silently
reaping (or reporting the exit code of) an unrelated thread that
happens to have landed on the same numeric slot since. */
uint32 target = vfsPidfdTarget((int)regs->rdi);
if (target == threadInvalidId) {
regs->rax = (uint64)-1;
return (uint64)regs;
}
Thread* targetThread = threadAt(target);
if (targetThread->state != threadDead) {
currentThread()->sigInRetryableSyscall = true;
schedBlockCurrent(targetThread);
regs->rip -= 2;
return schedule((uint64)regs);
}
regs->rax = (uint64)threadJoin(target);
return (uint64)regs;
}
case sysSymlink: {
char target[256];
char path[256];
if (!copyUserPath(regs->rdi, target, sizeof(target)) ||
!copyUserPath(regs->rsi, path, sizeof(path)))
regs->rax = (uint64)-1;
else
regs->rax = (uint64)(int64)vfsSymlink(path, target);
return (uint64)regs;
}
case sysReadlink: {
char path[256];
if (!copyUserPath(regs->rdi, path, sizeof(path)) || !userRangeOk(regs->rsi, regs->rdx))
regs->rax = (uint64)-1;
else
regs->rax = (uint64)vfsReadlink(path, (char*)regs->rsi, regs->rdx);
return (uint64)regs;
}
case sysLink: {
char oldPath[256];
char newPath[256];
if (!copyUserPath(regs->rdi, oldPath, sizeof(oldPath)) ||
!copyUserPath(regs->rsi, newPath, sizeof(newPath)))
regs->rax = (uint64)-1;
else
regs->rax = (uint64)(int64)vfsLink(oldPath, newPath);
return (uint64)regs;
}
case sysPipe: {
if (!userRangeOk(regs->rdi, 2 * sizeof(int))) {
regs->rax = (uint64)-1;
return (uint64)regs;
}
int* userFds = (int*)regs->rdi;
int readFd, writeFd;
if (vfsPipe(&readFd, &writeFd) < 0) {
regs->rax = (uint64)-1;
} else {
userFds[0] = readFd;
userFds[1] = writeFd;
regs->rax = 0;
}
return (uint64)regs;
}
case sysPipeCreate:
regs->rax = (uint64)vfsPipeCreateHandle();
return (uint64)regs;
case sysPipeAttach:
regs->rax = (uint64)vfsPipeAttach((int)regs->rdi, regs->rsi != 0);
return (uint64)regs;
case sysKill: {
/* Real kill(2)'s own pid<0/pid==0 convention (userKill's `pid` is
already a signed `long`, see ulib.h -- only this kernel-side
interpretation of the raw bit pattern was missing): pid>0 is the
single-target path this always had; pid==0 targets the caller's
OWN process group (threadKillGroup, sched.c -- naturally kills
no one else if this is the group's only OTHER member, since
threadKill itself already excludes the caller's own Running
thread); pid<0 targets group -pid, exactly like real
kill(-pgid, SIGKILL). */
int64 rawPid = (int64)regs->rdi;
bool ok;
if (rawPid > 0)
default:
regs->rax = (uint64)-1;
return (uint64)regs;