]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
feat: proper uid/gid + euid/egid implementation with permission enforcement
authorTulio A M Mendes <[email protected]>
Thu, 12 Feb 2026 08:34:46 +0000 (05:34 -0300)
committerTulio A M Mendes <[email protected]>
Fri, 13 Feb 2026 02:44:55 +0000 (23:44 -0300)
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.

include/errno.h
include/process.h
include/syscall.h
src/kernel/scheduler.c
src/kernel/syscall.c
user/ulibc/include/syscall.h
user/ulibc/include/unistd.h
user/ulibc/src/unistd.c

index c0f3cc365b7a390a753c256ac708290a43ff28ca..27199271167ad6e55a64da6820fdb34a1cadf7c2 100644 (file)
@@ -3,6 +3,7 @@
 
 #define EPERM 1
 #define ENOENT 2
+#define EACCES 13
 #define EIO 5
 #define EINTR 4
 #define E2BIG 7
index fee54f5a709790aac0e94689f5852e572be0eafc..aaf1ace89268dc74560b5c0aed0c20e83e1eea91 100644 (file)
@@ -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;
index 33d63ba4d0a23f40c4b80e3c05099f147aff8c22..decd7e72320634b53e7e9e4dfe2852d1ddcde1cc 100644 (file)
@@ -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
index 7e0c05854c2726c322a751e73ea4289c27925d2a..ae87d434497f7edc61b0d1f9e14e7cb8ba52eb12 100644 (file)
@@ -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;
 
index c32c9c9c5acddac7bb7d00ff7d8ffa22f1e59d0e..6454f1c3c5fcaa205a83944311267d3df3e6e9f8 100644 (file)
@@ -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]) {
index f322fddbe526d561e28be633933291f16a46442d..a0595889e12cff918b243c96cf3ab8c27240fae0 100644 (file)
@@ -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 */
index e9934174a6ed3bb6cf15c13732784ca466e70b77..14c275b162adc7bfada44207a5254a062d490b0b 100644 (file)
@@ -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);
index 8d6294c20637a14befe7b79ac1598e53b639fc50..ff56387e6661d6c1e1faa450c904cc1d3b97c127 100644 (file)
@@ -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));
 }