From c58f297cd5239b9cb30d52f46d0c921a9e55233b Mon Sep 17 00:00:00 2001 From: Tulio A M Mendes Date: Wed, 11 Feb 2026 23:54:11 -0300 Subject: [PATCH] feat: sigpending, pread/pwrite, access, umask, setuid/setgid syscalls + ulibc wrappers - SYSCALL_SIGPENDING (71): returns pending & blocked signal mask - SYSCALL_PREAD/PWRITE (72/73): positional read/write without altering file offset - SYSCALL_ACCESS (74): checks file existence (simplified, no real perm check yet) - SYSCALL_UMASK (75): per-process file creation mask (new umask field in struct process) - SYSCALL_SETUID/SETGID (76/77): change process uid/gid - Extract pread/pwrite/access into noinline posix_ext_syscall_dispatch to avoid stack bloat - ulibc: signal.h sigpending(), unistd.h pread/pwrite/access/setuid/setgid --- include/process.h | 1 + src/kernel/syscall.c | 111 +++++++++++++++++++++++++++++++++++ user/ulibc/include/signal.h | 1 + user/ulibc/include/syscall.h | 7 +++ user/ulibc/include/unistd.h | 5 ++ user/ulibc/src/signal.c | 4 ++ user/ulibc/src/unistd.c | 20 +++++++ 7 files changed, 149 insertions(+) diff --git a/include/process.h b/include/process.h index b89ace5..ddc7e74 100644 --- a/include/process.h +++ b/include/process.h @@ -84,6 +84,7 @@ struct process { uintptr_t heap_break; char cwd[128]; + uint32_t umask; int waiting; int wait_pid; diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 1c0ab58..3bb789b 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -67,6 +67,7 @@ static int fd_alloc(struct file* f); static int fd_close(int fd); static struct file* fd_get(int fd); static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no); +static void posix_ext_syscall_dispatch(struct registers* regs, uint32_t syscall_no); struct pollfd { int fd; @@ -2205,6 +2206,18 @@ void syscall_handler(struct registers* regs) { return; } + if (syscall_no == SYSCALL_SIGPENDING) { + uint32_t* user_set = (uint32_t*)regs->ebx; + if (!current_process) { regs->eax = (uint32_t)-EINVAL; return; } + uint32_t pending = current_process->sig_pending_mask & current_process->sig_blocked_mask; + if (copy_to_user(user_set, &pending, sizeof(pending)) < 0) { + regs->eax = (uint32_t)-EFAULT; + } else { + regs->eax = 0; + } + return; + } + if (syscall_no == SYSCALL_FSYNC || syscall_no == SYSCALL_FDATASYNC) { int fd = (int)regs->ebx; if (!current_process || fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd]) { @@ -2215,6 +2228,34 @@ void syscall_handler(struct registers* regs) { return; } + if (syscall_no == SYSCALL_PREAD || syscall_no == SYSCALL_PWRITE || + syscall_no == SYSCALL_ACCESS) { + posix_ext_syscall_dispatch(regs, syscall_no); + return; + } + + if (syscall_no == SYSCALL_UMASK) { + if (!current_process) { regs->eax = 0; return; } + uint32_t old = current_process->umask; + current_process->umask = regs->ebx & 0777; + regs->eax = old; + return; + } + + if (syscall_no == SYSCALL_SETUID) { + if (!current_process) { regs->eax = (uint32_t)-EINVAL; return; } + current_process->uid = regs->ebx; + regs->eax = 0; + return; + } + + if (syscall_no == SYSCALL_SETGID) { + if (!current_process) { regs->eax = (uint32_t)-EINVAL; return; } + current_process->gid = regs->ebx; + regs->eax = 0; + return; + } + /* ---- Socket syscalls ---- */ socket_syscall_dispatch(regs, syscall_no); /* If socket dispatch handled it, eax is set and we return. @@ -2222,6 +2263,76 @@ void syscall_handler(struct registers* regs) { return; } +/* Separate function to keep pread/pwrite/access locals off syscall_handler's stack */ +__attribute__((noinline)) +static void posix_ext_syscall_dispatch(struct registers* regs, uint32_t syscall_no) { + if (syscall_no == SYSCALL_PREAD) { + int fd = (int)regs->ebx; + void* buf = (void*)regs->ecx; + uint32_t count = regs->edx; + uint32_t offset = regs->esi; + struct file* f = fd_get(fd); + if (!f || !f->node) { regs->eax = (uint32_t)-EBADF; return; } + if (!f->node->read) { regs->eax = (uint32_t)-ESPIPE; return; } + if (count > 1024 * 1024) { regs->eax = (uint32_t)-EINVAL; return; } + uint8_t kbuf[256]; + uint32_t total = 0; + while (total < count) { + uint32_t chunk = count - total; + if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf); + uint32_t rd = vfs_read(f->node, offset + total, chunk, kbuf); + if (rd == 0) break; + if (copy_to_user((uint8_t*)buf + total, kbuf, rd) < 0) { + regs->eax = (uint32_t)-EFAULT; return; + } + total += rd; + if (rd < chunk) break; + } + regs->eax = total; + return; + } + + if (syscall_no == SYSCALL_PWRITE) { + int fd = (int)regs->ebx; + const void* buf = (const void*)regs->ecx; + uint32_t count = regs->edx; + uint32_t offset = regs->esi; + struct file* f = fd_get(fd); + if (!f || !f->node) { regs->eax = (uint32_t)-EBADF; return; } + if (!f->node->write) { regs->eax = (uint32_t)-ESPIPE; return; } + if (count > 1024 * 1024) { regs->eax = (uint32_t)-EINVAL; return; } + uint8_t kbuf[256]; + uint32_t total = 0; + while (total < count) { + uint32_t chunk = count - total; + if (chunk > sizeof(kbuf)) chunk = (uint32_t)sizeof(kbuf); + if (copy_from_user(kbuf, (const uint8_t*)buf + total, chunk) < 0) { + regs->eax = (uint32_t)-EFAULT; return; + } + uint32_t wr = vfs_write(f->node, offset + total, chunk, kbuf); + if (wr == 0) break; + total += wr; + if (wr < chunk) break; + } + regs->eax = total; + return; + } + + if (syscall_no == SYSCALL_ACCESS) { + const char* user_path = (const char*)regs->ebx; + if (!user_path) { regs->eax = (uint32_t)-EFAULT; return; } + char path[128]; + int prc = path_resolve_user(user_path, path, sizeof(path)); + if (prc < 0) { regs->eax = (uint32_t)prc; return; } + fs_node_t* node = vfs_lookup(path); + if (!node) { regs->eax = (uint32_t)-ENOENT; return; } + regs->eax = 0; + return; + } + + regs->eax = (uint32_t)-ENOSYS; +} + /* Separate function to keep socket locals off syscall_handler's stack frame */ __attribute__((noinline)) static void socket_syscall_dispatch(struct registers* regs, uint32_t syscall_no) { diff --git a/user/ulibc/include/signal.h b/user/ulibc/include/signal.h index dc4b571..02c9f94 100644 --- a/user/ulibc/include/signal.h +++ b/user/ulibc/include/signal.h @@ -50,5 +50,6 @@ int raise(int sig); int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact); int sigprocmask(int how, const uint32_t* set, uint32_t* oldset); +int sigpending(uint32_t* set); #endif diff --git a/user/ulibc/include/syscall.h b/user/ulibc/include/syscall.h index ec1e847..586b404 100644 --- a/user/ulibc/include/syscall.h +++ b/user/ulibc/include/syscall.h @@ -53,6 +53,13 @@ enum { SYS_GETTID = 68, SYS_FSYNC = 69, SYS_FDATASYNC = 70, + SYS_SIGPENDING = 71, + SYS_PREAD = 72, + SYS_PWRITE = 73, + SYS_ACCESS = 74, + SYS_UMASK = 75, + SYS_SETUID = 76, + SYS_SETGID = 77, }; /* Raw syscall wrappers — up to 5 args via INT 0x80 */ diff --git a/user/ulibc/include/unistd.h b/user/ulibc/include/unistd.h index 70a818f..5d4d712 100644 --- a/user/ulibc/include/unistd.h +++ b/user/ulibc/include/unistd.h @@ -35,6 +35,11 @@ int getpgrp(void); int gettid(void); int fsync(int fd); int fdatasync(int fd); +int pread(int fd, void* buf, size_t count, int offset); +int pwrite(int fd, const void* buf, size_t count, int offset); +int access(const char* path, int mode); +int setuid(int uid); +int setgid(int gid); void* brk(void* addr); void _exit(int status) __attribute__((noreturn)); diff --git a/user/ulibc/src/signal.c b/user/ulibc/src/signal.c index 0bd63c1..0eaa8d0 100644 --- a/user/ulibc/src/signal.c +++ b/user/ulibc/src/signal.c @@ -13,3 +13,7 @@ int raise(int sig) { int sigprocmask(int how, const uint32_t* set, uint32_t* oldset) { return __syscall_ret(_syscall3(SYS_SIGPROCMASK, how, (int)set, (int)oldset)); } + +int sigpending(uint32_t* set) { + return __syscall_ret(_syscall1(SYS_SIGPENDING, (int)set)); +} diff --git a/user/ulibc/src/unistd.c b/user/ulibc/src/unistd.c index 06ce1b6..b27226f 100644 --- a/user/ulibc/src/unistd.c +++ b/user/ulibc/src/unistd.c @@ -94,6 +94,26 @@ int fdatasync(int fd) { return __syscall_ret(_syscall1(SYS_FDATASYNC, fd)); } +int pread(int fd, void* buf, size_t count, int offset) { + return __syscall_ret(_syscall4(SYS_PREAD, fd, (int)buf, (int)count, offset)); +} + +int pwrite(int fd, const void* buf, size_t count, int offset) { + return __syscall_ret(_syscall4(SYS_PWRITE, fd, (int)buf, (int)count, offset)); +} + +int access(const char* path, int mode) { + return __syscall_ret(_syscall2(SYS_ACCESS, (int)path, mode)); +} + +int setuid(int uid) { + return __syscall_ret(_syscall1(SYS_SETUID, uid)); +} + +int setgid(int gid) { + return __syscall_ret(_syscall1(SYS_SETGID, gid)); +} + void* brk(void* addr) { return (void*)_syscall1(SYS_BRK, (int)addr); } -- 2.43.0