From: Tulio A M Mendes Date: Thu, 12 Feb 2026 08:34:46 +0000 (-0300) Subject: feat: proper uid/gid + euid/egid implementation with permission enforcement X-Git-Url: https://projects.tadryanom.me/sitemap.xml?a=commitdiff_plain;h=30bc2100854a9d4fea3d5a821e0742ea5e0f6d90;p=AdrOS.git feat: proper uid/gid + euid/egid implementation with permission enforcement Kernel: - struct process: added euid/egid (effective uid/gid) fields - process_fork_create: now inherits uid/gid/euid/egid from parent (previously left at 0 from memset) - process_clone_create: also inherits euid/egid - setuid/setgid: permission checks — only euid==0 can set arbitrary uid/gid; unprivileged processes can only set to their real uid/gid - New syscalls: geteuid (88), getegid (89), seteuid (90), setegid (91) - vfs_check_permission(): checks owner/group/other rwx bits against process euid/egid and file uid/gid/mode - open() now calls vfs_check_permission() for R/W/RW access - chmod: only root or file owner can change mode - chown: only root can change ownership - Added EACCES (13) to errno.h ulibc: - Added SYS_GETUID (52), SYS_GETGID (53), SYS_CHMOD (50), SYS_CHOWN (51), SYS_GETEUID (88), SYS_GETEGID (89), SYS_SETEUID (90), SYS_SETEGID (91) - Added getuid/getgid/geteuid/getegid/seteuid/setegid wrappers All 19/19 smoke tests pass. --- diff --git a/include/errno.h b/include/errno.h index c0f3cc3..2719927 100644 --- a/include/errno.h +++ b/include/errno.h @@ -3,6 +3,7 @@ #define EPERM 1 #define ENOENT 2 +#define EACCES 13 #define EIO 5 #define EINTR 4 #define E2BIG 7 diff --git a/include/process.h b/include/process.h index fee54f5..aaf1ace 100644 --- a/include/process.h +++ b/include/process.h @@ -47,6 +47,8 @@ struct process { uint32_t pgrp_id; uint32_t uid; uint32_t gid; + uint32_t euid; + uint32_t egid; uintptr_t sp; uintptr_t addr_space; uint32_t* kernel_stack; diff --git a/include/syscall.h b/include/syscall.h index 33d63ba..decd7e7 100644 --- a/include/syscall.h +++ b/include/syscall.h @@ -111,6 +111,10 @@ enum { SYSCALL_FUTEX = 85, SYSCALL_SIGALTSTACK = 86, SYSCALL_FLOCK = 87, + SYSCALL_GETEUID = 88, + SYSCALL_GETEGID = 89, + SYSCALL_SETEUID = 90, + SYSCALL_SETEGID = 91, }; #endif diff --git a/src/kernel/scheduler.c b/src/kernel/scheduler.c index 7e0c058..ae87d43 100644 --- a/src/kernel/scheduler.c +++ b/src/kernel/scheduler.c @@ -401,6 +401,10 @@ struct process* process_fork_create(uintptr_t child_as, const struct registers* proc->parent_pid = current_process ? current_process->pid : 0; proc->session_id = current_process ? current_process->session_id : proc->pid; proc->pgrp_id = current_process ? current_process->pgrp_id : proc->pid; + proc->uid = current_process ? current_process->uid : 0; + proc->gid = current_process ? current_process->gid : 0; + proc->euid = current_process ? current_process->euid : 0; + proc->egid = current_process ? current_process->egid : 0; proc->priority = current_process ? current_process->priority : SCHED_DEFAULT_PRIO; proc->nice = current_process ? current_process->nice : 0; proc->state = PROCESS_READY; @@ -559,6 +563,8 @@ struct process* process_clone_create(uint32_t clone_flags, proc->uid = current_process->uid; proc->gid = current_process->gid; + proc->euid = current_process->euid; + proc->egid = current_process->egid; proc->heap_start = current_process->heap_start; proc->heap_break = current_process->heap_break; diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index c32c9c9..6454f1c 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -883,6 +883,31 @@ static int syscall_lseek_impl(int fd, int32_t offset, int whence) { return (int)f->offset; } +/* + * Check if the current process has the requested access to a file node. + * want: bitmask of 4 (read), 2 (write), 1 (execute). + * Returns 0 if allowed, -EACCES if denied. + */ +static int vfs_check_permission(fs_node_t* node, int want) { + if (!current_process) return 0; /* kernel context — allow all */ + if (current_process->euid == 0) return 0; /* root — allow all */ + if (node->mode == 0) return 0; /* mode not set — permissive */ + + uint32_t mode = node->mode; + uint32_t perm; + + if (current_process->euid == node->uid) { + perm = (mode >> 6) & 7; /* owner bits */ + } else if (current_process->egid == node->gid) { + perm = (mode >> 3) & 7; /* group bits */ + } else { + perm = mode & 7; /* other bits */ + } + + if ((want & perm) != (uint32_t)want) return -EACCES; + return 0; +} + static int syscall_open_impl(const char* user_path, uint32_t flags) { if (!user_path) return -EFAULT; @@ -908,6 +933,16 @@ static int syscall_open_impl(const char* user_path, uint32_t flags) { if (!node) return -ENOENT; } + /* Permission check based on open flags */ + { + int want = 4; /* default: read */ + uint32_t acc = flags & 3U; /* O_RDONLY=0, O_WRONLY=1, O_RDWR=2 */ + if (acc == 1) want = 2; /* write only */ + else if (acc == 2) want = 6; /* read + write */ + int perm_rc = vfs_check_permission(node, want); + if (perm_rc < 0) return perm_rc; + } + struct file* f = (struct file*)kmalloc(sizeof(*f)); if (!f) return -ENOMEM; f->node = node; @@ -1763,6 +1798,12 @@ static int syscall_chmod_impl(const char* user_path, uint32_t mode) { fs_node_t* node = vfs_lookup(path); if (!node) return -ENOENT; + /* Only root or file owner can chmod */ + if (current_process && current_process->euid != 0 && + current_process->euid != node->uid) { + return -EPERM; + } + node->mode = mode & 07777; return 0; } @@ -1777,6 +1818,11 @@ static int syscall_chown_impl(const char* user_path, uint32_t uid, uint32_t gid) fs_node_t* node = vfs_lookup(path); if (!node) return -ENOENT; + /* Only root can chown */ + if (current_process && current_process->euid != 0) { + return -EPERM; + } + node->uid = uid; node->gid = gid; return 0; @@ -2274,18 +2320,70 @@ void syscall_handler(struct registers* regs) { if (syscall_no == SYSCALL_SETUID) { if (!current_process) { regs->eax = (uint32_t)-EINVAL; return; } - current_process->uid = regs->ebx; + uint32_t new_uid = regs->ebx; + if (current_process->euid == 0) { + current_process->uid = new_uid; + current_process->euid = new_uid; + } else if (new_uid == current_process->uid) { + current_process->euid = new_uid; + } else { + regs->eax = (uint32_t)-EPERM; + return; + } regs->eax = 0; return; } if (syscall_no == SYSCALL_SETGID) { if (!current_process) { regs->eax = (uint32_t)-EINVAL; return; } - current_process->gid = regs->ebx; + uint32_t new_gid = regs->ebx; + if (current_process->euid == 0) { + current_process->gid = new_gid; + current_process->egid = new_gid; + } else if (new_gid == current_process->gid) { + current_process->egid = new_gid; + } else { + regs->eax = (uint32_t)-EPERM; + return; + } regs->eax = 0; return; } + if (syscall_no == SYSCALL_GETEUID) { + regs->eax = current_process ? current_process->euid : 0; + return; + } + + if (syscall_no == SYSCALL_GETEGID) { + regs->eax = current_process ? current_process->egid : 0; + return; + } + + if (syscall_no == SYSCALL_SETEUID) { + if (!current_process) { regs->eax = (uint32_t)-EINVAL; return; } + uint32_t new_euid = regs->ebx; + if (current_process->euid == 0 || new_euid == current_process->uid) { + current_process->euid = new_euid; + regs->eax = 0; + } else { + regs->eax = (uint32_t)-EPERM; + } + return; + } + + if (syscall_no == SYSCALL_SETEGID) { + if (!current_process) { regs->eax = (uint32_t)-EINVAL; return; } + uint32_t new_egid = regs->ebx; + if (current_process->euid == 0 || new_egid == current_process->gid) { + current_process->egid = new_egid; + regs->eax = 0; + } else { + regs->eax = (uint32_t)-EPERM; + } + return; + } + if (syscall_no == SYSCALL_FLOCK) { int fd = (int)regs->ebx; if (!current_process || fd < 0 || fd >= PROCESS_MAX_FILES || !current_process->files[fd]) { diff --git a/user/ulibc/include/syscall.h b/user/ulibc/include/syscall.h index f322fdd..a059588 100644 --- a/user/ulibc/include/syscall.h +++ b/user/ulibc/include/syscall.h @@ -58,6 +58,10 @@ enum { SYS_PWRITE = 73, SYS_ACCESS = 74, SYS_UMASK = 75, + SYS_CHMOD = 50, + SYS_CHOWN = 51, + SYS_GETUID = 52, + SYS_GETGID = 53, SYS_SETUID = 76, SYS_SETGID = 77, SYS_TRUNCATE = 78, @@ -70,6 +74,10 @@ enum { SYS_FUTEX = 85, SYS_SIGALTSTACK = 86, SYS_FLOCK = 87, + SYS_GETEUID = 88, + SYS_GETEGID = 89, + SYS_SETEUID = 90, + SYS_SETEGID = 91, }; /* 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 e993417..14c275b 100644 --- a/user/ulibc/include/unistd.h +++ b/user/ulibc/include/unistd.h @@ -38,8 +38,14 @@ 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 getuid(void); +int getgid(void); +int geteuid(void); +int getegid(void); int setuid(int uid); int setgid(int gid); +int seteuid(int euid); +int setegid(int egid); int truncate(const char* path, int length); int ftruncate(int fd, int length); unsigned int alarm(unsigned int seconds); diff --git a/user/ulibc/src/unistd.c b/user/ulibc/src/unistd.c index 8d6294c..ff56387 100644 --- a/user/ulibc/src/unistd.c +++ b/user/ulibc/src/unistd.c @@ -106,6 +106,22 @@ int access(const char* path, int mode) { return __syscall_ret(_syscall2(SYS_ACCESS, (int)path, mode)); } +int getuid(void) { + return _syscall0(SYS_GETUID); +} + +int getgid(void) { + return _syscall0(SYS_GETGID); +} + +int geteuid(void) { + return _syscall0(SYS_GETEUID); +} + +int getegid(void) { + return _syscall0(SYS_GETEGID); +} + int setuid(int uid) { return __syscall_ret(_syscall1(SYS_SETUID, uid)); } @@ -114,6 +130,14 @@ int setgid(int gid) { return __syscall_ret(_syscall1(SYS_SETGID, gid)); } +int seteuid(int euid) { + return __syscall_ret(_syscall1(SYS_SETEUID, euid)); +} + +int setegid(int egid) { + return __syscall_ret(_syscall1(SYS_SETEGID, egid)); +} + int truncate(const char* path, int length) { return __syscall_ret(_syscall2(SYS_TRUNCATE, (int)path, length)); }