From: Tulio A M Mendes Date: Fri, 13 Feb 2026 00:33:03 +0000 (-0300) Subject: refactor: move sigframe/sigreturn from syscall.c to arch/x86/signal.c X-Git-Url: https://projects.tadryanom.me/docs/POSIX_ROADMAP.md?a=commitdiff_plain;h=c833c0b22f67bf6cce987e368e92c9f6163ad189;p=AdrOS.git refactor: move sigframe/sigreturn from syscall.c to arch/x86/signal.c - New include/arch/x86/signal.h: shared struct sigframe + SIGFRAME_MAGIC - New include/arch_signal.h: arch-agnostic arch_sigreturn() prototype - New src/arch/x86/signal.c: x86 sigreturn implementation (eflags sanitize, CS/SS ring3 validation, IOPL clear) - src/arch/x86/idt.c: use shared arch/x86/signal.h instead of local copy - src/kernel/syscall.c: remove x86-specific sigframe struct and sigreturn_impl, call arch_sigreturn() via generic void* interface No x86 signal frame knowledge remains in generic kernel code. --- diff --git a/include/arch/x86/signal.h b/include/arch/x86/signal.h new file mode 100644 index 0000000..f94e0ac --- /dev/null +++ b/include/arch/x86/signal.h @@ -0,0 +1,14 @@ +#ifndef ARCH_X86_SIGNAL_H +#define ARCH_X86_SIGNAL_H + +#include +#include "arch/x86/idt.h" + +#define SIGFRAME_MAGIC 0x53494746U /* 'SIGF' */ + +struct sigframe { + uint32_t magic; + struct registers saved; +}; + +#endif /* ARCH_X86_SIGNAL_H */ diff --git a/include/arch_signal.h b/include/arch_signal.h new file mode 100644 index 0000000..d68dadd --- /dev/null +++ b/include/arch_signal.h @@ -0,0 +1,19 @@ +#ifndef ARCH_SIGNAL_H +#define ARCH_SIGNAL_H + +#include "interrupts.h" + +/* + * arch_sigreturn — Restore user registers from a signal frame on the + * user stack. Architecture-specific because the frame + * layout and register sanitisation depend on the ISA. + * + * regs : current trapframe (will be overwritten on success). + * user_frame : user-space pointer to the signal frame pushed by the + * signal delivery trampoline. + * + * Returns 0 on success, negative errno on failure. + */ +int arch_sigreturn(struct registers* regs, const void* user_frame); + +#endif /* ARCH_SIGNAL_H */ diff --git a/src/arch/x86/idt.c b/src/arch/x86/idt.c index c6c3cdf..720699f 100644 --- a/src/arch/x86/idt.c +++ b/src/arch/x86/idt.c @@ -10,14 +10,9 @@ #include "signal.h" #include -#define IDT_ENTRIES 256 - -static const uint32_t SIGFRAME_MAGIC = 0x53494746U; // 'SIGF' +#include "arch/x86/signal.h" -struct sigframe { - uint32_t magic; - struct registers saved; -}; +#define IDT_ENTRIES 256 struct idt_entry idt[IDT_ENTRIES]; struct idt_ptr idtp; diff --git a/src/arch/x86/signal.c b/src/arch/x86/signal.c new file mode 100644 index 0000000..b70badb --- /dev/null +++ b/src/arch/x86/signal.c @@ -0,0 +1,37 @@ +#include "arch_signal.h" +#include "arch/x86/signal.h" +#include "process.h" +#include "uaccess.h" +#include "errno.h" + +#if defined(__i386__) + +int arch_sigreturn(struct registers* regs, const void* user_frame) +{ + if (!regs) return -EINVAL; + if (!current_process) return -EINVAL; + if ((regs->cs & 3U) != 3U) return -EPERM; + if (!user_frame) return -EFAULT; + + if (user_range_ok(user_frame, sizeof(struct sigframe)) == 0) + return -EFAULT; + + struct sigframe f; + if (copy_from_user(&f, user_frame, sizeof(f)) < 0) + return -EFAULT; + if (f.magic != SIGFRAME_MAGIC) + return -EINVAL; + + if ((f.saved.cs & 3U) != 3U) return -EPERM; + if ((f.saved.ss & 3U) != 3U) return -EPERM; + + // Sanitize eflags: clear IOPL (bits 12-13) to prevent privilege escalation, + // ensure IF (bit 9) is set so interrupts remain enabled in usermode. + f.saved.eflags = (f.saved.eflags & ~0x3000U) | 0x200U; + + // Restore the full saved trapframe. The interrupt stub will pop these regs and iret. + *regs = f.saved; + return 0; +} + +#endif /* __i386__ */ diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 6454f1c..a2aa41e 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -28,6 +28,7 @@ extern void x86_sysenter_init(void); #include "hal/mm.h" #include "hal/cpu.h" +#include "arch_signal.h" #include @@ -55,14 +56,6 @@ enum { static int path_resolve_user(const char* user_path, char* out, size_t out_sz); -#if defined(__i386__) -static const uint32_t SIGFRAME_MAGIC = 0x53494746U; // 'SIGF' -struct sigframe { - uint32_t magic; - struct registers saved; -}; -#endif - static int fd_alloc(struct file* f); static int fd_close(int fd); static struct file* fd_get(int fd); @@ -1452,30 +1445,6 @@ static int syscall_sigprocmask_impl(uint32_t how, uint32_t mask, uint32_t* old_o return -EINVAL; } -static int syscall_sigreturn_impl(struct registers* regs, const struct sigframe* user_frame) { - if (!regs) return -EINVAL; - if (!current_process) return -EINVAL; - if ((regs->cs & 3U) != 3U) return -EPERM; - if (!user_frame) return -EFAULT; - - if (user_range_ok(user_frame, sizeof(*user_frame)) == 0) { return -EFAULT; } - - struct sigframe f; - if (copy_from_user(&f, user_frame, sizeof(f)) < 0) return -EFAULT; - if (f.magic != SIGFRAME_MAGIC) { return -EINVAL; } - - if ((f.saved.cs & 3U) != 3U) return -EPERM; - if ((f.saved.ss & 3U) != 3U) return -EPERM; - - // Sanitize eflags: clear IOPL (bits 12-13) to prevent privilege escalation, - // ensure IF (bit 9) is set so interrupts remain enabled in usermode. - f.saved.eflags = (f.saved.eflags & ~0x3000U) | 0x200U; - - // Restore the full saved trapframe. The interrupt stub will pop these regs and iret. - *regs = f.saved; - return 0; -} - struct timespec { uint32_t tv_sec; uint32_t tv_nsec; @@ -2090,8 +2059,8 @@ void syscall_handler(struct registers* regs) { } if (syscall_no == SYSCALL_SIGRETURN) { - const struct sigframe* user_frame = (const struct sigframe*)regs->ebx; - regs->eax = (uint32_t)syscall_sigreturn_impl(regs, user_frame); + const void* user_frame = (const void*)(uintptr_t)regs->ebx; + regs->eax = (uint32_t)arch_sigreturn(regs, user_frame); return; }