Skip to content

Commit

Permalink
Kernel: Add support for SA_SIGINFO
Browse files Browse the repository at this point in the history
We currently don't really populate most of the fields, but that can
wait :^)
  • Loading branch information
alimpfard authored and awesomekling committed Mar 4, 2022
1 parent 585054d commit 4bd01b7
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 193 deletions.
60 changes: 60 additions & 0 deletions Kernel/API/POSIX/ucontext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2022, Ali Mohammad Pur <[email protected]>
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <Kernel/API/POSIX/sys/types.h>
#include <Kernel/Arch/mcontext.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct __mcontext mcontext_t;

typedef struct __ucontext {
struct __ucontext* uc_link;
sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
} ucontext_t;

#define ILL_ILLOPC 0
#define ILL_ILLOPN 1
#define ILL_ILLADR 2
#define ILL_ILLTRP 3
#define ILL_PRVOPC 4
#define ILL_PRVREG 5
#define ILL_COPROC 6
#define ILL_BADSTK 7

#define FPE_INTDIV 0
#define FPE_INTOVF 1
#define FPE_FLTDIV 2
#define FPE_FLTOVF 3
#define FPE_FLTUND 4
#define FPE_FLTRES 5
#define FPE_FLTINV 6

#define SEGV_MAPERR 0
#define SEGV_ACCERR 1

#define BUS_ADRALN 0
#define BUS_ADRERR 1
#define BUS_OBJERR 2

#define TRAP_BRKPT 0
#define TRAP_TRACE 1

#define SI_USER 0x40000000
#define SI_QUEUE 0x40000001
#define SI_TIMER 0x40000002
#define SI_ASYNCIO 0x40000003
#define SI_MESGQ 0x40000004

#ifdef __cplusplus
}
#endif
15 changes: 15 additions & 0 deletions Kernel/Arch/mcontext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/Platform.h>

#if ARCH(X86_64) || ARCH(I386)
# include <Kernel/Arch/x86/mcontext.h>
#elif ARCH(AARCH64)
# error "Unknown architecture"
#endif
58 changes: 58 additions & 0 deletions Kernel/Arch/x86/mcontext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2022, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/

#pragma once

#include <AK/Platform.h>
#include <Kernel/API/POSIX/sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

struct __attribute__((packed)) __mcontext {
#if ARCH(I386)
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint32_t eip;
uint32_t eflags;
#else
uint64_t rax;
uint64_t rcx;
uint64_t rdx;
uint64_t rbx;
uint64_t rsp;
uint64_t rbp;
uint64_t rsi;
uint64_t rdi;
uint64_t rip;
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
uint64_t rflags;
#endif
uint32_t cs;
uint32_t ss;
uint32_t ds;
uint32_t es;
uint32_t fs;
uint32_t gs;
};

#ifdef __cplusplus
}
#endif
60 changes: 33 additions & 27 deletions Kernel/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -293,63 +293,69 @@ void signal_trampoline_dummy()
// blocking syscall, that syscall may return some special error code in eax;
// This error code would likely be overwritten by the signal handler, so it's
// necessary to preserve it here.
constexpr static auto offset_to_first_register_slot = sizeof(__ucontext) + sizeof(siginfo) + 5 * sizeof(FlatPtr);
asm(
".intel_syntax noprefix\n"
".globl asm_signal_trampoline\n"
"asm_signal_trampoline:\n"
// stack state: ret flags, ret ip, register dump, signal mask, signal, handler (alignment = 16), 0
// stack state: 0, ucontext, signal_info, (alignment = 16), 0, ucontext*, siginfo*, signal, (alignment = 16), handler

// save ebp
"push ebp\n"
"mov ebp, esp\n"
// Pop the handler into ecx
"pop ecx\n" // save handler
// we have to save eax 'cause it might be the return value from a syscall
"push eax\n"
// align the stack to 16 bytes (as our current offset is 12 from the fake return addr, saved ebp and saved eax)
"sub esp, 4\n"
// push the signal code
"mov eax, [ebp+12]\n"
"push eax\n"
"mov [esp+%P1], eax\n"
// Note that the stack is currently aligned to 16 bytes as we popped the extra entries above.
// and it's already setup to call the handler with the expected values on the stack.
// call the signal handler
"call [ebp+8]\n"
// Unroll stack back to the saved eax
"add esp, 8\n"
"call ecx\n"
// drop the 4 arguments
"add esp, 16\n"
// Current stack state is just saved_eax, ucontext, signal_info.
// syscall SC_sigreturn
"mov eax, %P0\n"
"int 0x82\n"
".globl asm_signal_trampoline_end\n"
"asm_signal_trampoline_end:\n"
".att_syntax" ::"i"(Syscall::SC_sigreturn));
".att_syntax"
:
: "i"(Syscall::SC_sigreturn),
"i"(offset_to_first_register_slot));
#elif ARCH(X86_64)
// The trampoline preserves the current rax, pushes the signal code and
// then calls the signal handler. We do this because, when interrupting a
// blocking syscall, that syscall may return some special error code in eax;
// This error code would likely be overwritten by the signal handler, so it's
// necessary to preserve it here.
constexpr static auto offset_to_first_register_slot = sizeof(__ucontext) + sizeof(siginfo) + 4 * sizeof(FlatPtr);
asm(
".intel_syntax noprefix\n"
".globl asm_signal_trampoline\n"
"asm_signal_trampoline:\n"
// stack state: ret flags, ret ip, register dump, signal mask, signal, handler (alignment = 16), 0
// stack state: 0, ucontext, signal_info (alignment = 16), ucontext*, siginfo*, signal, handler

// save rbp
"push rbp\n"
"mov rbp, rsp\n"
// Pop the handler into rcx
"pop rcx\n" // save handler
// we have to save rax 'cause it might be the return value from a syscall
"push rax\n"
// align the stack to 16 bytes (our offset is 24 bytes from the fake return addr, saved rbp and saved rax).
"sub rsp, 8\n"
// push the signal code
"mov rdi, [rbp+24]\n"
"mov [rsp+%P1], rax\n"
// pop signal number into rdi (first param)
"pop rdi\n"
// pop siginfo* into rsi (second param)
"pop rsi\n"
// pop ucontext* into rdx (third param)
"pop rdx\n"
// Note that the stack is currently aligned to 16 bytes as we popped the extra entries above.
// call the signal handler
"call [rbp+16]\n"
// unroll stack back to the saved rax
"add rsp, 8\n"
"call rcx\n"
// Current stack state is just saved_rax, ucontext, signal_info.
// syscall SC_sigreturn
"mov rax, %P0\n"
"int 0x82\n"
".globl asm_signal_trampoline_end\n"
"asm_signal_trampoline_end:\n"
".att_syntax" ::"i"(Syscall::SC_sigreturn));
".att_syntax"
:
: "i"(Syscall::SC_sigreturn),
"i"(offset_to_first_register_slot));
#endif
}

Expand Down
71 changes: 21 additions & 50 deletions Kernel/Syscalls/sigaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ ErrorOr<FlatPtr> Process::sys$sigaction(int signum, Userspace<const sigaction*>
}
if (user_act) {
auto act = TRY(copy_typed_from_user(user_act));
if (act.sa_flags & SA_SIGINFO)
return ENOTSUP;
action.mask = act.sa_mask;
action.flags = act.sa_flags;
action.handler_or_sigaction = VirtualAddress { reinterpret_cast<void*>(act.sa_sigaction) };
Expand All @@ -83,63 +81,36 @@ ErrorOr<FlatPtr> Process::sys$sigreturn([[maybe_unused]] RegisterState& register
TRY(require_promise(Pledge::stdio));
SmapDisabler disabler;

#if ARCH(I386)
// Stack state (created by the signal trampoline):
// ret flags, ret ip, register dump,
// signal mask, signal, handler (alignment = 16),
// 0, ebp, eax

// Here, we restore the state pushed by dispatch signal and asm_signal_trampoline.
FlatPtr* stack_ptr = bit_cast<FlatPtr*>(registers.userspace_esp);
FlatPtr smuggled_eax = *stack_ptr;

// pop the stored eax, ebp, return address, handler and signal code
stack_ptr += 5;

Thread::current()->m_signal_mask = *stack_ptr;
stack_ptr++;

// pop edi, esi, ebp, esp, ebx, edx, ecx and eax
memcpy(&registers.edi, stack_ptr, 8 * sizeof(FlatPtr));
stack_ptr += 8;

registers.eip = *stack_ptr;
stack_ptr++;
auto stack_ptr = registers.userspace_sp();

registers.eflags = (registers.eflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask);
stack_ptr++;

registers.userspace_esp = registers.esp;
return smuggled_eax;
#else
// Stack state (created by the signal trampoline):
// ret flags, ret ip, register dump,
// signal mask, signal, handler (alignment = 16),
// 0, ebp, eax

// Here, we restore the state pushed by dispatch signal and asm_signal_trampoline.
FlatPtr* stack_ptr = (FlatPtr*)registers.userspace_rsp;
FlatPtr smuggled_rax = *stack_ptr;
// saved_ax, ucontext, signal_info.
stack_ptr += sizeof(siginfo); // We don't need this here.

// pop the stored rax, rbp, return address, handler and signal code
stack_ptr += 5;
auto ucontext = TRY(copy_typed_from_user<__ucontext>(stack_ptr));
stack_ptr += sizeof(__ucontext);

Thread::current()->m_signal_mask = *stack_ptr;
stack_ptr++;
auto saved_ax = TRY(copy_typed_from_user<FlatPtr>(stack_ptr));

// pop rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, r8, r9, r10, r11, r12, r13, r14 and r15
memcpy(&registers.rdi, stack_ptr, 16 * sizeof(FlatPtr));
stack_ptr += 16;

registers.rip = *stack_ptr;
stack_ptr++;
Thread::current()->m_signal_mask = ucontext.uc_sigmask;
#if ARCH(X86_64)
auto sp = registers.rsp;
#elif ARCH(I386)
auto sp = registers.esp;
#endif

registers.rflags = (registers.rflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask);
stack_ptr++;
copy_ptrace_registers_into_kernel_registers(registers, static_cast<PtraceRegisters const&>(ucontext.uc_mcontext));

registers.userspace_rsp = registers.rsp;
return smuggled_rax;
#if ARCH(X86_64)
registers.set_userspace_sp(registers.rsp);
registers.rsp = sp;
#elif ARCH(I386)
registers.set_userspace_sp(registers.esp);
registers.esp = sp;
#endif

return saved_ax;
}

ErrorOr<void> Process::remap_range_as_stack(FlatPtr address, size_t size)
Expand Down
Loading

0 comments on commit 4bd01b7

Please sign in to comment.