feat: expand syscall
This commit is contained in:
1 parent
643fa45f6a
commit
aad9d4ece8
1 file changed
+173
+173
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user