diff --git a/src/syscall.c b/src/syscall.c index 1939b83..eeb1175 100644 --- a/src/syscall.c +++ b/src/syscall.c @@ -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;