Viewing: signal.c
📄 signal.c (Read Only) ⬅ To go back
#include "arch_signal.h"
#include "arch/x86/signal.h"
#include "process.h"
#include "uaccess.h"
#include "errno.h"

#if defined(__i386__)

int arch_sigreturn(void* opaque, const void* user_frame)
{
    struct registers* regs = (struct registers*)opaque;
    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__ */