]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
kernel: hardening and cleanup fixes (Round 4)
authorTulio A M Mendes <[email protected]>
Mon, 25 May 2026 14:34:19 +0000 (11:34 -0300)
committerTulio A M Mendes <[email protected]>
Wed, 3 Jun 2026 04:02:35 +0000 (01:02 -0300)
- Rename socket_syscall_dispatch to extended_syscall_dispatch (handles
  MQ, SEM, DLOPEN, EPOLL, INOTIFY, AIO, MOUNT, etc., not just sockets)
- Implement POSIX saved set-user-ID / set-group-ID:
  - Add suid/sgid fields to struct process (at end to preserve offsets)
  - setuid(2): when root, sets uid/euid/suid; non-root can set euid
    to uid or suid (POSIX spec)
  - setgid(2): same pattern for gid/egid/sgid
  - seteuid(2): saves old euid to suid, allows switch to suid
  - setegid(2): saves old egid to sgid, allows switch to sgid
  - suid/sgid inherited on fork and clone
- Add SYSCALL_REBOOT (142): root-only, cmd 0=halt, 1=reboot,
  2=poweroff. Uses hal_system_reboot() and new hal_system_shutdown()
  (QEMU ACPI port 0x604 for poweroff)

Fixes: L04 (saved set-user-ID), L05 (reboot syscall), L06 (naming)
include/hal/system.h
include/process.h
include/syscall.h
src/hal/x86/system.c
src/kernel/scheduler.c
src/kernel/syscall.c
user/ulibc/include/syscall.h

index fbcdfcfbd934632805529a297c775d9b921dd6c2..fd666c92c0f017d1588037e27e36b17325644208 100644 (file)
@@ -11,5 +11,6 @@
 #define HAL_SYSTEM_H
 
 void hal_system_reboot(void);
+void hal_system_shutdown(void);
 
 #endif
index 7f0ce7f040d635bdc4fa69e012e1f93ea360c8c3..5b56766f915835bcd0b93df6a3d08b47f9ca793a 100644 (file)
@@ -159,6 +159,9 @@ struct process {
     /* SMP: which CPU's runqueue this process is assigned to */
     uint32_t cpu_id;
 
+    uint32_t suid;  /* saved set-user-ID */
+    uint32_t sgid;  /* saved set-group-ID */
+
     uint8_t fpu_state[FPU_STATE_SIZE] __attribute__((aligned(FPU_STATE_ALIGN)));
 };
 
index 58d3ec8d3cb616e21f1c7b7ee334cf09832b1eb1..f2348965fa89c38e2ae941eaa553a3fea24ddb99 100644 (file)
@@ -183,6 +183,7 @@ enum {
     SYSCALL_WAIT4        = 139,
     SYSCALL_MADVISE      = 140,
     SYSCALL_EXECVEAT     = 141,
+    SYSCALL_REBOOT       = 142,
 };
 
 #endif
index 1e255905ebd4e5d12907d5fadd7505f702f1303f..7fa181a1b31aff580e9dc31d7101d1a70fb7b22d 100644 (file)
@@ -18,7 +18,14 @@ void hal_system_reboot(void) {
     while (good & 0x02) good = inb(0x64);
     outb(0x64, 0xFE);
 }
+
+void hal_system_shutdown(void) {
+    /* QEMU ACPI shutdown: write 0x2000 to port 0x604 */
+    outw(0x604, 0x2000);
+}
 #else
 void hal_system_reboot(void) {
 }
+void hal_system_shutdown(void) {
+}
 #endif
index 405f9e990d616e9ca657cfe10cad7856b80f8955..693072c580b5e70fc5afd32fa05acce3d4728f71 100644 (file)
@@ -673,6 +673,8 @@ struct process* process_fork_create(uintptr_t child_as, const void* child_regs)
     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->suid = current_process ? current_process->suid : 0;
+    proc->sgid = current_process ? current_process->sgid : 0;
     proc->priority = current_process ? current_process->priority : SCHED_DEFAULT_PRIO;
     proc->nice = current_process ? current_process->nice : 0;
     proc->state = PROCESS_READY;
@@ -874,6 +876,8 @@ struct process* process_clone_create(uint32_t clone_flags,
     proc->gid = current_process->gid;
     proc->euid = current_process->euid;
     proc->egid = current_process->egid;
+    proc->suid = current_process->suid;
+    proc->sgid = current_process->sgid;
     proc->heap_start = current_process->heap_start;
     proc->heap_break = current_process->heap_break;
     memcpy(proc->rlimits, current_process->rlimits, sizeof(proc->rlimits));
index 51a6f5f3eb66c2c2d744a0f91bbe99afdefc93f5..c48e193cbf32289f0ba6ff41ae3f31dae63ea82d 100644 (file)
@@ -34,6 +34,7 @@
 #include "hal/mm.h"
 
 #include "hal/cpu.h"
+#include "hal/system.h"
 #include "arch_signal.h"
 #include "arch_syscall.h"
 #include "arch_process.h"
@@ -830,7 +831,7 @@ static int path_resolve_user(const char* user_path, char* out, size_t out_sz);
 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 extended_syscall_dispatch(struct registers* regs, uint32_t syscall_no);
 static void posix_ext_syscall_dispatch(struct registers* regs, uint32_t syscall_no);
 
 /* ------------------------------------------------------------------ */
@@ -3948,7 +3949,8 @@ void syscall_handler(struct registers* regs) {
         if (current_process->euid == 0) {
             current_process->uid = new_uid;
             current_process->euid = new_uid;
-        } else if (new_uid == current_process->uid) {
+            current_process->suid = new_uid;
+        } else if (new_uid == current_process->uid || new_uid == current_process->suid) {
             current_process->euid = new_uid;
         } else {
             sc_ret(regs) = (uint32_t)-EPERM;
@@ -3964,7 +3966,8 @@ void syscall_handler(struct registers* regs) {
         if (current_process->euid == 0) {
             current_process->gid = new_gid;
             current_process->egid = new_gid;
-        } else if (new_gid == current_process->gid) {
+            current_process->sgid = new_gid;
+        } else if (new_gid == current_process->gid || new_gid == current_process->sgid) {
             current_process->egid = new_gid;
         } else {
             sc_ret(regs) = (uint32_t)-EPERM;
@@ -3987,7 +3990,9 @@ void syscall_handler(struct registers* regs) {
     if (syscall_no == SYSCALL_SETEUID) {
         if (!current_process) { sc_ret(regs) = (uint32_t)-EINVAL; return; }
         uint32_t new_euid = sc_arg0(regs);
-        if (current_process->euid == 0 || new_euid == current_process->uid) {
+        if (current_process->euid == 0 || new_euid == current_process->uid
+            || new_euid == current_process->suid) {
+            current_process->suid = current_process->euid;
             current_process->euid = new_euid;
             sc_ret(regs) = 0;
         } else {
@@ -3999,7 +4004,9 @@ void syscall_handler(struct registers* regs) {
     if (syscall_no == SYSCALL_SETEGID) {
         if (!current_process) { sc_ret(regs) = (uint32_t)-EINVAL; return; }
         uint32_t new_egid = sc_arg0(regs);
-        if (current_process->euid == 0 || new_egid == current_process->gid) {
+        if (current_process->euid == 0 || new_egid == current_process->gid
+            || new_egid == current_process->sgid) {
+            current_process->sgid = current_process->egid;
             current_process->egid = new_egid;
             sc_ret(regs) = 0;
         } else {
@@ -4214,6 +4221,24 @@ void syscall_handler(struct registers* regs) {
         return;
     }
 
+    if (syscall_no == SYSCALL_REBOOT) {
+        /* reboot(cmd): cmd 0 = halt, 1 = reboot, 2 = poweroff. Root-only. */
+        if (!current_process || current_process->euid != 0) {
+            sc_ret(regs) = (uint32_t)-EPERM; return;
+        }
+        int cmd = (int)sc_arg0(regs);
+        if (cmd == 1) {
+            hal_system_reboot();
+        } else if (cmd == 2) {
+            hal_system_shutdown();
+        }
+        /* halt or unknown: just loop */
+        hal_cpu_disable_interrupts();
+        for (;;) hal_cpu_idle();
+        sc_ret(regs) = 0;  /* unreachable */
+        return;
+    }
+
     if (syscall_no == SYSCALL_MPROTECT) {
         uintptr_t addr = (uintptr_t)sc_arg0(regs);
         uint32_t  len  = sc_arg1(regs);
@@ -4272,7 +4297,7 @@ void syscall_handler(struct registers* regs) {
     }
 
     /* ---- Socket syscalls ---- */
-    socket_syscall_dispatch(regs, syscall_no);
+    extended_syscall_dispatch(regs, syscall_no);
     /* If socket dispatch handled it, the return register is set and we return.
        If not, it sets ENOSYS. Either way, return. */
     return;
@@ -4662,7 +4687,7 @@ static int syscall_recvmsg_impl(int sockfd, void* user_msg, int flags) {
 
 /* 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) {
+static void extended_syscall_dispatch(struct registers* regs, uint32_t syscall_no) {
     if (syscall_no == SYSCALL_SOCKET) {
         int domain   = (int)sc_arg0(regs);
         int type     = (int)sc_arg1(regs);
index 9c583d21f6a93899e2e5d62bdd69a6cb1e441059..06a8f88010d0da1921954d472b3f1d0aff72c2fe 100644 (file)
@@ -153,6 +153,7 @@ enum {
     SYS_WAIT4 = 139,
     SYS_MADVISE = 140,
     SYS_EXECVEAT = 141,
+    SYS_REBOOT   = 142,
 };
 
 /* Raw syscall wrappers — up to 5 args via INT 0x80 */