mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-11 13:36:13 +03:00
Kernel: Add support for SA_SIGINFO
We currently don't really populate most of the fields, but that can wait :^)
This commit is contained in:
parent
585054d68b
commit
4bd01b7fe9
Notes:
sideshowbarker
2024-07-17 17:57:13 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/4bd01b7fe9 Pull-request: https://github.com/SerenityOS/serenity/pull/12762
60
Kernel/API/POSIX/ucontext.h
Normal file
60
Kernel/API/POSIX/ucontext.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||
*
|
||||
* 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
Kernel/Arch/mcontext.h
Normal file
15
Kernel/Arch/mcontext.h
Normal file
@ -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
Kernel/Arch/x86/mcontext.h
Normal file
58
Kernel/Arch/x86/mcontext.h
Normal file
@ -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
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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) };
|
||||
@ -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;
|
||||
auto stack_ptr = registers.userspace_sp();
|
||||
|
||||
// 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(®isters.edi, stack_ptr, 8 * sizeof(FlatPtr));
|
||||
stack_ptr += 8;
|
||||
|
||||
registers.eip = *stack_ptr;
|
||||
stack_ptr++;
|
||||
|
||||
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
|
||||
// saved_ax, ucontext, signal_info.
|
||||
stack_ptr += sizeof(siginfo); // We don't need this here.
|
||||
|
||||
// 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;
|
||||
auto ucontext = TRY(copy_typed_from_user<__ucontext>(stack_ptr));
|
||||
stack_ptr += sizeof(__ucontext);
|
||||
|
||||
// pop the stored rax, rbp, return address, handler and signal code
|
||||
stack_ptr += 5;
|
||||
auto saved_ax = TRY(copy_typed_from_user<FlatPtr>(stack_ptr));
|
||||
|
||||
Thread::current()->m_signal_mask = *stack_ptr;
|
||||
stack_ptr++;
|
||||
|
||||
// pop rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, r8, r9, r10, r11, r12, r13, r14 and r15
|
||||
memcpy(®isters.rdi, stack_ptr, 16 * sizeof(FlatPtr));
|
||||
stack_ptr += 16;
|
||||
|
||||
registers.rip = *stack_ptr;
|
||||
stack_ptr++;
|
||||
|
||||
registers.rflags = (registers.rflags & ~safe_eflags_mask) | (*stack_ptr & safe_eflags_mask);
|
||||
stack_ptr++;
|
||||
|
||||
registers.userspace_rsp = registers.rsp;
|
||||
return smuggled_rax;
|
||||
Thread::current()->m_signal_mask = ucontext.uc_sigmask;
|
||||
#if ARCH(X86_64)
|
||||
auto sp = registers.rsp;
|
||||
#elif ARCH(I386)
|
||||
auto sp = registers.esp;
|
||||
#endif
|
||||
|
||||
copy_ptrace_registers_into_kernel_registers(registers, static_cast<PtraceRegisters const&>(ucontext.uc_mcontext));
|
||||
|
||||
#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)
|
||||
|
@ -938,6 +938,13 @@ static ErrorOr<void> push_value_on_user_stack(FlatPtr& stack, FlatPtr data)
|
||||
return copy_to_user((FlatPtr*)stack, &data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static ErrorOr<void> copy_value_on_user_stack(FlatPtr& stack, T const& data)
|
||||
{
|
||||
stack -= sizeof(data);
|
||||
return copy_to_user((RemoveCVReference<T>*)stack, &data);
|
||||
}
|
||||
|
||||
void Thread::resume_from_stopped()
|
||||
{
|
||||
VERIFY(is_stopped());
|
||||
@ -976,8 +983,6 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)
|
||||
}
|
||||
|
||||
auto& action = m_process->m_signal_action_data[signal];
|
||||
// FIXME: Implement SA_SIGINFO signal handlers.
|
||||
VERIFY(!(action.flags & SA_SIGINFO));
|
||||
|
||||
if (!current_trap() && !action.handler_or_sigaction.is_null()) {
|
||||
// We're trying dispatch a handled signal to a user process that was scheduled
|
||||
@ -1057,83 +1062,89 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)
|
||||
bool use_alternative_stack = ((action.flags & SA_ONSTACK) != 0) && has_alternative_signal_stack() && !is_in_alternative_signal_stack();
|
||||
|
||||
auto setup_stack = [&](RegisterState& state) -> ErrorOr<void> {
|
||||
FlatPtr old_sp = state.userspace_sp();
|
||||
FlatPtr stack;
|
||||
if (use_alternative_stack)
|
||||
stack = m_alternative_signal_stack + m_alternative_signal_stack_size;
|
||||
else
|
||||
stack = old_sp;
|
||||
stack = state.userspace_sp();
|
||||
|
||||
FlatPtr ret_ip = state.ip();
|
||||
FlatPtr ret_flags = state.flags();
|
||||
dbgln_if(SIGNAL_DEBUG, "Setting up user stack to return to IP {:p}, SP {:p}", state.ip(), state.userspace_sp());
|
||||
|
||||
dbgln_if(SIGNAL_DEBUG, "Setting up user stack to return to IP {:p}, SP {:p}", ret_ip, old_sp);
|
||||
__ucontext ucontext {
|
||||
.uc_link = nullptr,
|
||||
.uc_sigmask = old_signal_mask,
|
||||
.uc_stack = {
|
||||
.ss_sp = nullptr,
|
||||
.ss_flags = 0,
|
||||
.ss_size = 0,
|
||||
},
|
||||
.uc_mcontext = {},
|
||||
};
|
||||
copy_kernel_registers_into_ptrace_registers(static_cast<PtraceRegisters&>(ucontext.uc_mcontext), state);
|
||||
|
||||
siginfo signal_info {
|
||||
.si_signo = signal,
|
||||
.si_code = 0, // FIXME: Signal-specific value, fill this in.
|
||||
.si_errno = 0,
|
||||
// FIXME: Plumb sender information here.
|
||||
.si_pid = 0,
|
||||
.si_uid = 0,
|
||||
// FIXME: Fill these in.
|
||||
.si_addr = 0,
|
||||
.si_status = 0,
|
||||
.si_band = 0,
|
||||
.si_value = {
|
||||
.sival_int = 0,
|
||||
},
|
||||
};
|
||||
|
||||
FlatPtr start_of_stack;
|
||||
#if ARCH(I386)
|
||||
// Align the stack to 16 bytes.
|
||||
// Note that we push some elements on to the stack before the return address,
|
||||
// so we need to account for this here.
|
||||
constexpr static FlatPtr elements_pushed_on_stack_before_return_address = 13;
|
||||
FlatPtr stack_alignment = (stack - elements_pushed_on_stack_before_return_address * sizeof(FlatPtr)) % 16;
|
||||
stack -= stack_alignment;
|
||||
start_of_stack = stack;
|
||||
|
||||
TRY(push_value_on_user_stack(stack, ret_flags));
|
||||
|
||||
TRY(push_value_on_user_stack(stack, ret_ip));
|
||||
TRY(push_value_on_user_stack(stack, state.eax));
|
||||
TRY(push_value_on_user_stack(stack, state.ecx));
|
||||
TRY(push_value_on_user_stack(stack, state.edx));
|
||||
TRY(push_value_on_user_stack(stack, state.ebx));
|
||||
TRY(push_value_on_user_stack(stack, old_sp));
|
||||
TRY(push_value_on_user_stack(stack, state.ebp));
|
||||
TRY(push_value_on_user_stack(stack, state.esi));
|
||||
TRY(push_value_on_user_stack(stack, state.edi));
|
||||
constexpr static FlatPtr thread_red_zone_size = 0;
|
||||
#elif ARCH(X86_64)
|
||||
constexpr static FlatPtr thread_red_zone_size = 128;
|
||||
#else
|
||||
// Align the stack to 16 bytes.
|
||||
// Note that we push some elements on to the stack before the return address,
|
||||
// so we need to account for this here.
|
||||
// We also are not allowed to touch the thread's red-zone of 128 bytes
|
||||
constexpr static FlatPtr elements_pushed_on_stack_before_return_address = 21;
|
||||
FlatPtr stack_alignment = (stack - elements_pushed_on_stack_before_return_address * sizeof(FlatPtr)) % 16;
|
||||
stack -= 128 + stack_alignment;
|
||||
start_of_stack = stack;
|
||||
|
||||
TRY(push_value_on_user_stack(stack, ret_flags));
|
||||
|
||||
TRY(push_value_on_user_stack(stack, ret_ip));
|
||||
TRY(push_value_on_user_stack(stack, state.r15));
|
||||
TRY(push_value_on_user_stack(stack, state.r14));
|
||||
TRY(push_value_on_user_stack(stack, state.r13));
|
||||
TRY(push_value_on_user_stack(stack, state.r12));
|
||||
TRY(push_value_on_user_stack(stack, state.r11));
|
||||
TRY(push_value_on_user_stack(stack, state.r10));
|
||||
TRY(push_value_on_user_stack(stack, state.r9));
|
||||
TRY(push_value_on_user_stack(stack, state.r8));
|
||||
TRY(push_value_on_user_stack(stack, state.rax));
|
||||
TRY(push_value_on_user_stack(stack, state.rcx));
|
||||
TRY(push_value_on_user_stack(stack, state.rdx));
|
||||
TRY(push_value_on_user_stack(stack, state.rbx));
|
||||
TRY(push_value_on_user_stack(stack, old_sp));
|
||||
TRY(push_value_on_user_stack(stack, state.rbp));
|
||||
TRY(push_value_on_user_stack(stack, state.rsi));
|
||||
TRY(push_value_on_user_stack(stack, state.rdi));
|
||||
# error Unknown architecture in dispatch_signal
|
||||
#endif
|
||||
|
||||
// PUSH old_signal_mask
|
||||
TRY(push_value_on_user_stack(stack, old_signal_mask));
|
||||
// Align the stack to 16 bytes.
|
||||
// Note that we push some elements on to the stack before the return address,
|
||||
// so we need to account for this here.
|
||||
constexpr static FlatPtr elements_pushed_on_stack_before_handler_address = 1; // one slot for a saved register
|
||||
FlatPtr const extra_bytes_pushed_on_stack_before_handler_address = sizeof(ucontext) + sizeof(signal_info);
|
||||
FlatPtr stack_alignment = (stack - elements_pushed_on_stack_before_handler_address * sizeof(FlatPtr) + extra_bytes_pushed_on_stack_before_handler_address) % 16;
|
||||
// Also note that we have to skip the thread red-zone (if needed), so do that here.
|
||||
stack -= thread_red_zone_size + stack_alignment;
|
||||
auto start_of_stack = stack;
|
||||
|
||||
TRY(push_value_on_user_stack(stack, signal));
|
||||
TRY(push_value_on_user_stack(stack, handler_vaddr.get()));
|
||||
TRY(push_value_on_user_stack(stack, 0)); // syscall return value slot
|
||||
|
||||
TRY(copy_value_on_user_stack(stack, ucontext));
|
||||
auto pointer_to_ucontext = stack;
|
||||
|
||||
TRY(copy_value_on_user_stack(stack, signal_info));
|
||||
auto pointer_to_signal_info = stack;
|
||||
|
||||
// Make sure we actually pushed as many elements as we claimed to have pushed.
|
||||
if (start_of_stack - stack != elements_pushed_on_stack_before_return_address * sizeof(FlatPtr))
|
||||
PANIC("Stack in invalid state after signal trampoline, expected {:x} but got {:x}", start_of_stack - elements_pushed_on_stack_before_return_address * sizeof(FlatPtr), stack);
|
||||
if (start_of_stack - stack != elements_pushed_on_stack_before_handler_address * sizeof(FlatPtr) + extra_bytes_pushed_on_stack_before_handler_address) {
|
||||
PANIC("Stack in invalid state after signal trampoline, expected {:x} but got {:x}",
|
||||
start_of_stack - elements_pushed_on_stack_before_handler_address * sizeof(FlatPtr) - extra_bytes_pushed_on_stack_before_handler_address, stack);
|
||||
}
|
||||
|
||||
VERIFY(stack % 16 == 0);
|
||||
|
||||
TRY(push_value_on_user_stack(stack, 0)); // push fake return address
|
||||
#if ARCH(I386)
|
||||
// Leave one empty slot to align the stack for a handler call.
|
||||
TRY(push_value_on_user_stack(stack, 0));
|
||||
#endif
|
||||
TRY(push_value_on_user_stack(stack, pointer_to_ucontext));
|
||||
TRY(push_value_on_user_stack(stack, pointer_to_signal_info));
|
||||
TRY(push_value_on_user_stack(stack, signal));
|
||||
|
||||
#if ARCH(I386)
|
||||
VERIFY(stack % 16 == 0);
|
||||
#endif
|
||||
|
||||
TRY(push_value_on_user_stack(stack, handler_vaddr.get()));
|
||||
|
||||
// We write back the adjusted stack value into the register state.
|
||||
// We have to do this because we can't just pass around a reference to a packed field, as it's UB.
|
||||
|
@ -31,4 +31,5 @@
|
||||
#include <Kernel/API/POSIX/sys/wait.h>
|
||||
#include <Kernel/API/POSIX/termios.h>
|
||||
#include <Kernel/API/POSIX/time.h>
|
||||
#include <Kernel/API/POSIX/ucontext.h>
|
||||
#include <Kernel/API/POSIX/unistd.h>
|
||||
|
@ -15,6 +15,7 @@ set(TEST_SOURCES
|
||||
path-resolution-race.cpp
|
||||
pthread-cond-timedwait-example.cpp
|
||||
setpgid-across-sessions-without-leader.cpp
|
||||
siginfo-example.cpp
|
||||
stress-truncate.cpp
|
||||
stress-writeread.cpp
|
||||
uaf-close-while-blocked-in-read.cpp
|
||||
|
108
Tests/Kernel/siginfo-example.cpp
Normal file
108
Tests/Kernel/siginfo-example.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2022, the SerenityOS developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// Supposed to use volatile everywhere here but good lord does C++ make that a pain
|
||||
volatile sig_atomic_t saved_signal;
|
||||
volatile siginfo_t saved_siginfo;
|
||||
volatile ucontext_t saved_ucontext;
|
||||
siginfo_t* sig_info_addr;
|
||||
ucontext_t* ucontext_addr;
|
||||
void* stack_ptr;
|
||||
volatile bool signal_was_delivered = false;
|
||||
|
||||
static void signal_handler(int sig, siginfo_t* sig_info, void* u_context)
|
||||
{
|
||||
int x;
|
||||
stack_ptr = &x;
|
||||
signal_was_delivered = true;
|
||||
|
||||
saved_signal = sig;
|
||||
// grumble grumble, assignment operator on volatile types not a thing
|
||||
// grumble grumble more, can't memcpy voltile either, that casts away volatile
|
||||
// grumble grumble even more, can't std::copy to volatile.
|
||||
// screw it, just write all the fields
|
||||
sig_info_addr = sig_info;
|
||||
saved_siginfo.si_status = sig_info->si_status;
|
||||
saved_siginfo.si_signo = sig_info->si_signo;
|
||||
saved_siginfo.si_code = sig_info->si_code;
|
||||
saved_siginfo.si_pid = sig_info->si_pid;
|
||||
saved_siginfo.si_uid = sig_info->si_uid;
|
||||
saved_siginfo.si_value.sival_int = sig_info->si_value.sival_int;
|
||||
auto user_context = (ucontext_t*)u_context;
|
||||
ucontext_addr = user_context;
|
||||
saved_ucontext.uc_link = user_context->uc_link;
|
||||
saved_ucontext.uc_sigmask = user_context->uc_sigmask;
|
||||
saved_ucontext.uc_stack.ss_sp = user_context->uc_stack.ss_sp;
|
||||
saved_ucontext.uc_stack.ss_size = user_context->uc_stack.ss_size;
|
||||
saved_ucontext.uc_stack.ss_flags = user_context->uc_stack.ss_flags;
|
||||
// saved_ucontext.uc_mcontext = user_context->uc_mcontext;
|
||||
}
|
||||
|
||||
static int print_signal_results()
|
||||
{
|
||||
if (!signal_was_delivered) {
|
||||
fprintf(stderr, "Where was my signal bro?\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
sig_atomic_t read_the_signal = saved_signal;
|
||||
siginfo_t read_the_siginfo = {};
|
||||
read_the_siginfo.si_status = saved_siginfo.si_status;
|
||||
read_the_siginfo.si_signo = saved_siginfo.si_signo;
|
||||
read_the_siginfo.si_code = saved_siginfo.si_code;
|
||||
read_the_siginfo.si_pid = saved_siginfo.si_pid;
|
||||
read_the_siginfo.si_uid = saved_siginfo.si_uid;
|
||||
read_the_siginfo.si_value.sival_int = saved_siginfo.si_value.sival_int;
|
||||
|
||||
ucontext_t read_the_ucontext = {};
|
||||
read_the_ucontext.uc_link = saved_ucontext.uc_link;
|
||||
read_the_ucontext.uc_sigmask = saved_ucontext.uc_sigmask;
|
||||
read_the_ucontext.uc_stack.ss_sp = saved_ucontext.uc_stack.ss_sp;
|
||||
read_the_ucontext.uc_stack.ss_size = saved_ucontext.uc_stack.ss_size;
|
||||
read_the_ucontext.uc_stack.ss_flags = saved_ucontext.uc_stack.ss_flags;
|
||||
// read_the_ucontext.uc_mcontext = saved_ucontext.uc_mcontext;
|
||||
|
||||
printf("Handled signal: %d\n", read_the_signal);
|
||||
printf("Stack sorta started as %p\n", stack_ptr);
|
||||
printf("Siginfo was stored at %p:\n", sig_info_addr);
|
||||
printf("\tsi_signo: %d\n", read_the_siginfo.si_signo);
|
||||
printf("\tsi_code, %x\n", read_the_siginfo.si_code);
|
||||
printf("\tsi_pid, %d\n", read_the_siginfo.si_pid);
|
||||
printf("\tsi_uid, %d\n", read_the_siginfo.si_uid);
|
||||
printf("\tsi_status, %x\n", read_the_siginfo.si_status);
|
||||
printf("\tsi_value.sival_int, %x\n", read_the_siginfo.si_value.sival_int);
|
||||
printf("ucontext was stored at %p:\n", ucontext_addr);
|
||||
printf("\tuc_link, %p\n", read_the_ucontext.uc_link);
|
||||
printf("\tuc_sigmask, %d\n", read_the_ucontext.uc_sigmask);
|
||||
printf("\tuc_stack.ss_sp, %p\n", read_the_ucontext.uc_stack.ss_sp);
|
||||
printf("\tuc_stack.ss_size, %zu\n", read_the_ucontext.uc_stack.ss_size);
|
||||
printf("\tuc_stack.ss_flags, %d\n", read_the_ucontext.uc_stack.ss_flags);
|
||||
// printf("\tuc_mcontext, %d\n", read_the_ucontext.uc_mcontext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
struct sigaction action = {};
|
||||
action.sa_flags = SA_SIGINFO;
|
||||
sigemptyset(&action.sa_mask);
|
||||
action.sa_sigaction = signal_handler;
|
||||
|
||||
for (size_t i = 0; i < NSIG; ++i)
|
||||
(void)sigaction(i, &action, nullptr);
|
||||
|
||||
printf("Sleeping for a long time waiting for kill -<N> %d\n", getpid());
|
||||
|
||||
sleep(1000);
|
||||
return print_signal_results();
|
||||
}
|
@ -350,9 +350,21 @@ pushd "$DIR/Build/$ARCH"
|
||||
pushd "$BUILD"
|
||||
mkdir -p Root/usr/include/
|
||||
SRC_ROOT=$($REALPATH "$DIR"/..)
|
||||
FILES=$(find "$SRC_ROOT"/Kernel/API "$SRC_ROOT"/Userland/Libraries/LibC "$SRC_ROOT"/Userland/Libraries/LibM "$SRC_ROOT"/Userland/Libraries/LibPthread -name '*.h' -print)
|
||||
FILES=$(find \
|
||||
"$SRC_ROOT"/AK \
|
||||
"$SRC_ROOT"/Kernel/API \
|
||||
"$SRC_ROOT"/Kernel/Arch \
|
||||
"$SRC_ROOT"/Userland/Libraries/LibC \
|
||||
"$SRC_ROOT"/Userland/Libraries/LibM \
|
||||
"$SRC_ROOT"/Userland/Libraries/LibPthread \
|
||||
-name '*.h' -print)
|
||||
for header in $FILES; do
|
||||
target=$(echo "$header" | sed -e "s@$SRC_ROOT/Userland/Libraries/LibC@@" -e "s@$SRC_ROOT/Userland/Libraries/LibM@@" -e "s@$SRC_ROOT/Userland/Libraries/LibPthread@@" -e "s@$SRC_ROOT/Kernel/@Kernel/@")
|
||||
target=$(echo "$header" | sed \
|
||||
-e "s@$SRC_ROOT/AK/@AK/@" \
|
||||
-e "s@$SRC_ROOT/Userland/Libraries/LibC@@" \
|
||||
-e "s@$SRC_ROOT/Userland/Libraries/LibM@@" \
|
||||
-e "s@$SRC_ROOT/Userland/Libraries/LibPthread@@" \
|
||||
-e "s@$SRC_ROOT/Kernel/@Kernel/@")
|
||||
buildstep "system_headers" $INSTALL -D "$header" "Root/usr/include/$target"
|
||||
done
|
||||
unset SRC_ROOT
|
||||
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/API/POSIX/signal.h>
|
||||
#include <Kernel/API/POSIX/ucontext.h>
|
||||
#include <bits/sighow.h>
|
||||
#include <signal_numbers.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -14,80 +14,49 @@
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
|
||||
struct [[gnu::packed]] PtraceRegisters {
|
||||
#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;
|
||||
#include <Kernel/Arch/mcontext.h>
|
||||
|
||||
#if defined(__cplusplus) && defined(__cpp_concepts)
|
||||
#ifdef __cplusplus
|
||||
struct [[gnu::packed]] PtraceRegisters : public __mcontext {
|
||||
# if defined(__cplusplus) && defined(__cpp_concepts)
|
||||
FlatPtr ip() const
|
||||
{
|
||||
# if ARCH(I386)
|
||||
# if ARCH(I386)
|
||||
return eip;
|
||||
# else
|
||||
# else
|
||||
return rip;
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
void set_ip(FlatPtr ip)
|
||||
{
|
||||
# if ARCH(I386)
|
||||
# if ARCH(I386)
|
||||
eip = ip;
|
||||
# else
|
||||
# else
|
||||
rip = ip;
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
FlatPtr bp() const
|
||||
{
|
||||
# if ARCH(I386)
|
||||
# if ARCH(I386)
|
||||
return ebp;
|
||||
# else
|
||||
# else
|
||||
return rbp;
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
|
||||
void set_bp(FlatPtr bp)
|
||||
{
|
||||
# if ARCH(I386)
|
||||
# if ARCH(I386)
|
||||
ebp = bp;
|
||||
# else
|
||||
# else
|
||||
rbp = bp;
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
};
|
||||
|
||||
#else
|
||||
typedef struct __mcontext PthreadRegisters;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user