diff --git a/kernel/arch/i686/Signal.S b/kernel/arch/i686/Signal.S index 654e62b6..6059608d 100644 --- a/kernel/arch/i686/Signal.S +++ b/kernel/arch/i686/Signal.S @@ -2,15 +2,41 @@ // stack contains // return address +// return stack +// return rflags +// siginfo_t // signal number // signal handler .global signal_trampoline signal_trampoline: - pusha + pushl %esi // gregs + pushl %edi + pushl %edx + pushl %ecx + pushl %ebx + pushl %eax + pushl %ebp - movl 40(%esp), %edi - movl 36(%esp), %eax + movl 76(%esp), %eax // return sp + addl $4, %eax // return address + movl 80(%esp), %ebx // return ip + pushl %eax; + pushl %ebx + + // FIXME: populate these + xorl %eax, %eax + pushl %eax // stack + pushl %eax + pushl %eax + pushl %eax // sigset + pushl %eax + pushl %eax // link + + movl %esp, %edx // ucontext + leal 68(%esp), %esi // siginfo + movl 64(%esp), %edi // signal number + movl 60(%esp), %eax // handlers // align stack to 16 bytes movl %esp, %ebp @@ -19,7 +45,9 @@ signal_trampoline: subl $512, %esp fxsave (%esp) - subl $12, %esp + subl $4, %esp + pushl %edx + pushl %esi pushl %edi call *%eax addl $16, %esp @@ -29,9 +57,21 @@ signal_trampoline: // restore stack movl %ebp, %esp - popa + addl $32, %esp - addl $8, %esp + // restore registers + popl %ebp + popl %eax + popl %ebx + popl %ecx + popl %edx + popl %edi + popl %esi + + // skip handler, number, siginfo_t + addl $44, %esp + + // restore flags popf movl (%esp), %esp diff --git a/kernel/arch/x86_64/Signal.S b/kernel/arch/x86_64/Signal.S index fd21d33b..dc815e33 100644 --- a/kernel/arch/x86_64/Signal.S +++ b/kernel/arch/x86_64/Signal.S @@ -2,29 +2,48 @@ // stack contains // return address +// return stack +// return rflags +// siginfo_t // signal number // signal handler .global signal_trampoline signal_trampoline: - pushq %rax - pushq %rbx - pushq %rcx - pushq %rdx - pushq %rbp - pushq %rdi - pushq %rsi - pushq %r8 - pushq %r9 - pushq %r10 - pushq %r11 - pushq %r12 - pushq %r13 + pushq %r15 // gregs pushq %r14 - pushq %r15 + pushq %r13 + pushq %r12 + pushq %r11 + pushq %r10 + pushq %r9 + pushq %r8 + pushq %rsi + pushq %rdi + pushq %rdx + pushq %rcx + pushq %rbx + pushq %rax + pushq %rbp - movq 128(%rsp), %rdi - movq 120(%rsp), %rax + movq 200(%rsp), %rax // return sp + addq $(128 + 8), %rax // red-zone and return address + movq 208(%rsp), %rbx // return ip + pushq %rax; + pushq %rbx + + // FIXME: populate these + xorq %rax, %rax + pushq %rax // stack + pushq %rax + pushq %rax + pushq %rax // sigset + pushq %rax // link + + movq %rsp, %rdx // ucontext + leaq 192(%rsp), %rsi // siginfo + movq 184(%rsp), %rdi // signal number + movq 176(%rsp), %rax // handler // align stack to 16 bytes movq %rsp, %rbp @@ -40,26 +59,32 @@ signal_trampoline: // restore stack movq %rbp, %rsp - popq %r15 - popq %r14 - popq %r13 - popq %r12 - popq %r11 - popq %r10 - popq %r9 - popq %r8 - popq %rsi - popq %rdi - popq %rbp - popq %rdx - popq %rcx - popq %rbx - popq %rax + addq $56, %rsp - addq $16, %rsp + // restore registers + popq %rbp + popq %rax + popq %rbx + popq %rcx + popq %rdx + popq %rdi + popq %rsi + popq %r8 + popq %r9 + popq %r10 + popq %r11 + popq %r12 + popq %r13 + popq %r14 + popq %r15 + + // skip handler, number, siginfo_t + addq $72, %rsp + + // restore flags popfq movq (%rsp), %rsp - // return over red-zone + // return over red-zone and siginfo_t ret $128 diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index f7077612..a1b4a2e5 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -192,7 +192,7 @@ namespace Kernel void set_stopped(bool stopped, int signal); void wait_while_stopped(); - static BAN::ErrorOr kill(pid_t pid, int signal); + static BAN::ErrorOr kill(pid_t pid, int signal, const siginfo_t& = {}); BAN::ErrorOr sys_kill(pid_t pid, int signal); BAN::ErrorOr sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact); BAN::ErrorOr sys_sigpending(sigset_t* set); @@ -290,7 +290,7 @@ namespace Kernel return m_signal_pending_mask; } - void add_pending_signal(uint8_t signal) + void add_pending_signal(uint8_t signal, const siginfo_t& info) { ASSERT(signal >= _SIGMIN); ASSERT(signal <= _SIGMAX); @@ -302,6 +302,7 @@ namespace Kernel if (handler == SIG_DFL && (signal == SIGCHLD || signal == SIGURG)) return; m_signal_pending_mask |= 1ull << signal; + m_signal_infos[signal] = info; } void remove_pending_signal(uint8_t signal) @@ -354,6 +355,7 @@ namespace Kernel uint64_t m_alarm_wake_time_ns { 0 }; mutable SpinLock m_signal_lock; + siginfo_t m_signal_infos[_SIGMAX + 1] { }; struct sigaction m_signal_handlers[_SIGMAX + 1] { }; uint64_t m_signal_pending_mask { 0 }; diff --git a/kernel/include/kernel/Thread.h b/kernel/include/kernel/Thread.h index 60c869b1..8833a8ab 100644 --- a/kernel/include/kernel/Thread.h +++ b/kernel/include/kernel/Thread.h @@ -59,8 +59,8 @@ namespace Kernel bool can_add_signal_to_execute() const; bool will_execute_signal() const; // Returns true if handled signal had SA_RESTART - bool handle_signal(int signal = 0); - void add_signal(int signal); + bool handle_signal(int signal = 0, const siginfo_t& signal_info = {}); + void add_signal(int signal, const siginfo_t& info); void set_suspend_signal_mask(uint64_t sigmask); static bool is_stopping_signal(int signal); @@ -174,6 +174,7 @@ namespace Kernel InterruptStack m_interrupt_stack { }; InterruptRegisters m_interrupt_registers { }; + siginfo_t m_signal_infos[_SIGMAX + 1] { }; uint64_t m_signal_pending_mask { 0 }; uint64_t m_signal_block_mask { 0 }; BAN::Optional m_signal_suspend_mask; diff --git a/kernel/kernel/ACPI/EmbeddedController.cpp b/kernel/kernel/ACPI/EmbeddedController.cpp index 18605b2b..7811f0bd 100644 --- a/kernel/kernel/ACPI/EmbeddedController.cpp +++ b/kernel/kernel/ACPI/EmbeddedController.cpp @@ -56,7 +56,7 @@ namespace Kernel::ACPI EmbeddedController::~EmbeddedController() { if (m_thread) - m_thread->add_signal(SIGKILL); + m_thread->add_signal(SIGKILL, {}); m_thread = nullptr; } diff --git a/kernel/kernel/FS/Pipe.cpp b/kernel/kernel/FS/Pipe.cpp index d261e2b8..c3823b7e 100644 --- a/kernel/kernel/FS/Pipe.cpp +++ b/kernel/kernel/FS/Pipe.cpp @@ -106,7 +106,7 @@ namespace Kernel { if (m_reading_count == 0) { - Thread::current().add_signal(SIGPIPE); + Thread::current().add_signal(SIGPIPE, {}); return BAN::Error::from_errno(EPIPE); } TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); diff --git a/kernel/kernel/IDT.cpp b/kernel/kernel/IDT.cpp index e2e9b2ae..6e4f5669 100644 --- a/kernel/kernel/IDT.cpp +++ b/kernel/kernel/IDT.cpp @@ -203,7 +203,7 @@ namespace Kernel if (result.is_error()) { dwarnln("Demand paging: {}", result.error()); - Thread::current().handle_signal(SIGKILL); + Thread::current().handle_signal(SIGKILL, {}); goto done; } } @@ -273,30 +273,48 @@ namespace Kernel { // TODO: Confirm and fix the exception to signal mappings - int signal = 0; + siginfo_t signal_info {}; switch (isr) { case ISR::DivisionError: + signal_info.si_signo = SIGFPE; + signal_info.si_code = FPE_INTDIV; + break; case ISR::SIMDFloatingPointException: case ISR::x87FloatingPointException: - signal = SIGFPE; + // FIXME: this is probably not correct? + signal_info.si_signo = SIGFPE; + signal_info.si_code = FPE_FLTDIV; break; case ISR::AlignmentCheck: - signal = SIGBUS; + signal_info.si_signo = SIGBUS; + signal_info.si_code = BUS_ADRALN; + break; + case ISR::GeneralProtectionFault: + // TODO: this assumes unaligned operand but GP can be also caused by + // a privileged instruction or uncanonical address in which case + // the generated signal should be different + signal_info.si_signo = SIGBUS; + signal_info.si_code = BUS_ADRALN; break; case ISR::InvalidOpcode: - signal = SIGILL; + signal_info.si_signo = SIGILL; + signal_info.si_code = ILL_ILLOPC; break; case ISR::PageFault: - signal = SIGSEGV; + signal_info.si_signo = SIGSEGV; + if (PageTable::current().get_page_flags(regs->cr2 & PAGE_ADDR_MASK) & PageTable::Flags::Present) + signal_info.si_code = SEGV_ACCERR; + else + signal_info.si_code = SEGV_MAPERR; break; default: dwarnln("Unhandled exception"); - signal = SIGABRT; + signal_info.si_signo = SIGABRT; break; } - Thread::current().handle_signal(signal); + Thread::current().handle_signal(signal_info.si_signo, signal_info); } else { diff --git a/kernel/kernel/Networking/ARPTable.cpp b/kernel/kernel/Networking/ARPTable.cpp index 381fb41b..b255ec71 100644 --- a/kernel/kernel/Networking/ARPTable.cpp +++ b/kernel/kernel/Networking/ARPTable.cpp @@ -36,7 +36,7 @@ namespace Kernel ARPTable::~ARPTable() { if (m_thread) - m_thread->add_signal(SIGKILL); + m_thread->add_signal(SIGKILL, {}); m_thread = nullptr; } diff --git a/kernel/kernel/Networking/IPv4Layer.cpp b/kernel/kernel/Networking/IPv4Layer.cpp index 3a9dc8b1..0304db5c 100644 --- a/kernel/kernel/Networking/IPv4Layer.cpp +++ b/kernel/kernel/Networking/IPv4Layer.cpp @@ -47,7 +47,7 @@ namespace Kernel IPv4Layer::~IPv4Layer() { if (m_thread) - m_thread->add_signal(SIGKILL); + m_thread->add_signal(SIGKILL, {}); m_thread = nullptr; } diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index a88e7a2d..b18367b5 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -502,7 +502,7 @@ namespace Kernel LockGuard _(inode->m_mutex); if (inode->has_error()) { - Thread::current().add_signal(SIGPIPE); + Thread::current().add_signal(SIGPIPE, {}); return BAN::Error::from_errno(EPIPE); } if (is_nonblock && !inode->can_write()) @@ -588,7 +588,7 @@ namespace Kernel LockGuard _(inode->m_mutex); if (inode->has_hungup()) { - Thread::current().add_signal(SIGPIPE); + Thread::current().add_signal(SIGPIPE, {}); return BAN::Error::from_errno(EPIPE); } if (is_nonblock && !inode->can_write()) diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 424a2a42..301725d6 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -313,7 +313,17 @@ namespace Kernel child.status = __WGENEXITCODE(status, signal); - parent_process->add_pending_signal(SIGCHLD); + parent_process->add_pending_signal(SIGCHLD, { + .si_signo = SIGCHLD, + .si_code = signal ? CLD_KILLED : CLD_EXITED, + .si_errno = 0, + .si_pid = pid(), + .si_uid = m_credentials.ruid(), + .si_addr = nullptr, + .si_status = __WGENEXITCODE(status, signal), + .si_band = 0, + .si_value = {}, + }); if (!parent_process->m_threads.empty()) Processor::scheduler().unblock_thread(parent_process->m_threads.front()); @@ -328,7 +338,7 @@ namespace Kernel LockGuard _(m_process_lock); for (auto* thread : m_threads) if (thread != &Thread::current()) - thread->add_signal(SIGKILL); + thread->add_signal(SIGKILL, {}); } while (m_threads.size() > 1) @@ -1054,7 +1064,17 @@ namespace Kernel if (current_ns < process->m_alarm_wake_time_ns) break; - process->add_pending_signal(SIGALRM); + process->add_pending_signal(SIGALRM, { + .si_signo = SIGALRM, + .si_code = SI_TIMER, + .si_errno = 0, + .si_pid = 0, + .si_uid = 0, + .si_addr = nullptr, + .si_status = 0, + .si_band = 0, + .si_value = {}, + }); ASSERT(!process->m_threads.empty()); Processor::scheduler().unblock_thread(process->m_threads.front()); @@ -2765,7 +2785,18 @@ namespace Kernel if (!(m_signal_handlers[SIGCHLD].sa_flags & SA_NOCLDSTOP)) { - parent->add_pending_signal(SIGCHLD); + parent->add_pending_signal(SIGCHLD, { + .si_signo = SIGCHLD, + .si_code = stopped ? CLD_STOPPED : CLD_CONTINUED, + .si_errno = 0, + .si_pid = pid(), + .si_uid = m_credentials.ruid(), + .si_addr = nullptr, + .si_status = __WGENEXITCODE(0, signal), + .si_band = 0, + .si_value = { .sival_int = 0 }, + }); + if (!parent->m_threads.empty()) Processor::scheduler().unblock_thread(parent->m_threads.front()); } @@ -2791,7 +2822,7 @@ namespace Kernel } } - BAN::ErrorOr Process::kill(pid_t pid, int signal) + BAN::ErrorOr Process::kill(pid_t pid, int signal, const siginfo_t& signal_info) { if (pid == 0 || pid == -1) return BAN::Error::from_errno(ENOTSUP); @@ -2815,7 +2846,7 @@ namespace Kernel process.set_stopped(false, signal); else { - process.add_pending_signal(signal); + process.add_pending_signal(signal, signal_info); if (!process.m_threads.empty()) Processor::scheduler().unblock_thread(process.m_threads.front()); process.m_stop_blocker.unblock(); @@ -2837,6 +2868,18 @@ namespace Kernel if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX)) return BAN::Error::from_errno(EINVAL); + const siginfo_t signal_info { + .si_signo = signal, + .si_code = SI_USER, + .si_errno = 0, + .si_pid = this->pid(), + .si_uid = m_credentials.ruid(), + .si_addr = nullptr, + .si_status = 0, + .si_band = 0, + .si_value = {}, + }; + if (pid == m_pid) { if (signal == 0) @@ -2847,13 +2890,13 @@ namespace Kernel set_stopped(false, signal); else { - add_pending_signal(signal); + add_pending_signal(signal, signal_info); m_stop_blocker.unblock(); } return 0; } - TRY(kill(pid, signal)); + TRY(kill(pid, signal, signal_info)); return 0; } @@ -3196,8 +3239,19 @@ namespace Kernel { if (thread->tid() != tid) continue; - if (signal != 0) - thread->add_signal(signal); + if (signal == 0) + return 0; + thread->add_signal(signal, { + .si_signo = signal, + .si_code = SI_USER, + .si_errno = 0, + .si_pid = pid(), + .si_uid = m_credentials.ruid(), + .si_addr = nullptr, + .si_status = 0, + .si_band = 0, + .si_value = {}, + }); return 0; } diff --git a/kernel/kernel/Thread.cpp b/kernel/kernel/Thread.cpp index 6c396700..a0dcaccd 100644 --- a/kernel/kernel/Thread.cpp +++ b/kernel/kernel/Thread.cpp @@ -550,12 +550,14 @@ namespace Kernel vaddr_t signal_handler; { SpinLockGuard _(m_process->m_signal_lock); - ASSERT(!(m_process->m_signal_handlers[i].sa_flags & SA_SIGINFO)); - signal_handler = (vaddr_t)m_process->m_signal_handlers[i].sa_handler; + const auto& handler = m_process->m_signal_handlers[i]; + signal_handler = (handler.sa_flags & SA_SIGINFO) + ? reinterpret_cast(handler.sa_sigaction) + : reinterpret_cast(handler.sa_handler); } - if (signal_handler == (vaddr_t)SIG_IGN) + if (signal_handler == reinterpret_cast(SIG_IGN)) continue; - if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(i)) + if (signal_handler == reinterpret_cast(SIG_DFL) && is_default_ignored_signal(i)) continue; return true; } @@ -586,7 +588,7 @@ namespace Kernel return false; } - bool Thread::handle_signal(int signal) + bool Thread::handle_signal(int signal, const siginfo_t& _signal_info) { ASSERT(&Thread::current() == this); ASSERT(is_userspace()); @@ -596,16 +598,23 @@ namespace Kernel auto& interrupt_stack = *reinterpret_cast(kernel_stack_top() - sizeof(InterruptStack)); ASSERT(GDT::is_user_segment(interrupt_stack.cs)); + auto signal_info = _signal_info; + if (signal == 0) { - uint64_t full_pending_mask = m_signal_pending_mask | process().signal_pending_mask(); + const uint64_t process_signal_pending_mask = process().signal_pending_mask(); + const uint64_t full_pending_mask = m_signal_pending_mask | process_signal_pending_mask; for (signal = _SIGMIN; signal <= _SIGMAX; signal++) { - uint64_t mask = 1ull << signal; + const uint64_t mask = 1ull << signal; if ((full_pending_mask & mask) && !(m_signal_block_mask & mask)) break; } ASSERT(signal <= _SIGMAX); + if (process_signal_pending_mask & (1ull << signal)) + signal_info = process().m_signal_infos[signal]; + else + signal_info = m_signal_infos[signal]; } else { @@ -616,19 +625,20 @@ namespace Kernel vaddr_t signal_handler; bool has_sa_restart; vaddr_t signal_stack_top = 0; + { SpinLockGuard _(m_process->m_signal_lock); auto& handler = m_process->m_signal_handlers[signal]; - ASSERT(!(handler.sa_flags & SA_SIGINFO)); - - signal_handler = reinterpret_cast(handler.sa_handler); - if (handler.sa_flags & SA_RESETHAND) - handler.sa_handler = SIG_DFL; - + signal_handler = (handler.sa_flags & SA_SIGINFO) + ? reinterpret_cast(handler.sa_sigaction) + : reinterpret_cast(handler.sa_handler); has_sa_restart = !!(handler.sa_flags & SA_RESTART); + if (handler.sa_flags & SA_RESETHAND) + handler = { .sa_handler = SIG_DFL, .sa_mask = 0, .sa_flags = 0 }; + const auto& alt_stack = m_signal_alt_stack; if (alt_stack.ss_flags != SS_DISABLE && (handler.sa_flags & SA_ONSTACK) && !currently_on_alternate_stack()) signal_stack_top = reinterpret_cast(alt_stack.ss_sp) + alt_stack.ss_size; @@ -662,15 +672,15 @@ namespace Kernel if (signal_stack_top == 0) { - pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK; - pages[1] = (interrupt_stack.sp - 5 * sizeof(uintptr_t)) & PAGE_ADDR_MASK; + pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK; + pages[1] = (interrupt_stack.sp - 5 * sizeof(uintptr_t) - sizeof(siginfo_t)) & PAGE_ADDR_MASK; page_count = 2; } else { - pages[0] = (interrupt_stack.sp - sizeof(uintptr_t)) & PAGE_ADDR_MASK; - pages[1] = (signal_stack_top - 4 * sizeof(uintptr_t)) & PAGE_ADDR_MASK; - pages[2] = (signal_stack_top - 1 * sizeof(uintptr_t)) & PAGE_ADDR_MASK; + pages[0] = (interrupt_stack.sp - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK; + pages[2] = (signal_stack_top - 1 * sizeof(uintptr_t) ) & PAGE_ADDR_MASK; + pages[1] = (signal_stack_top - 4 * sizeof(uintptr_t) - sizeof(siginfo_t)) & PAGE_ADDR_MASK; page_count = 3; } @@ -691,6 +701,16 @@ namespace Kernel interrupt_stack.sp = signal_stack_top; write_to_stack(interrupt_stack.sp, old_stack); write_to_stack(interrupt_stack.sp, interrupt_stack.flags); + + { + signal_info.si_signo = signal; + signal_info.si_addr = reinterpret_cast(interrupt_stack.ip); + + interrupt_stack.sp -= sizeof(siginfo_t); + *reinterpret_cast(interrupt_stack.sp) = signal_info; + static_assert(sizeof(siginfo_t) % sizeof(uintptr_t) == 0); + } + write_to_stack(interrupt_stack.sp, signal); write_to_stack(interrupt_stack.sp, signal_handler); interrupt_stack.ip = (uintptr_t)signal_trampoline; @@ -728,25 +748,29 @@ namespace Kernel return has_sa_restart; } - void Thread::add_signal(int signal) + void Thread::add_signal(int signal, const siginfo_t& info) { SpinLockGuard _(m_signal_lock); + if (m_process) { vaddr_t signal_handler; { SpinLockGuard _(m_process->m_signal_lock); - ASSERT(!(m_process->m_signal_handlers[signal].sa_flags & SA_SIGINFO)); - signal_handler = (vaddr_t)m_process->m_signal_handlers[signal].sa_handler; + const auto& handler = m_process->m_signal_handlers[signal]; + signal_handler = (handler.sa_flags & SA_SIGINFO) + ? reinterpret_cast(handler.sa_sigaction) + : reinterpret_cast(handler.sa_handler); } - if (signal_handler == (vaddr_t)SIG_IGN) + if (signal_handler == reinterpret_cast(SIG_IGN)) return; - if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(signal)) + if (signal_handler == reinterpret_cast(SIG_DFL) && is_default_ignored_signal(signal)) return; } const uint64_t mask = 1ull << signal; m_signal_pending_mask |= mask; + m_signal_infos[signal] = info; if (this != &Thread::current()) Processor::scheduler().unblock_thread(this); diff --git a/userspace/libraries/LibC/include/signal.h b/userspace/libraries/LibC/include/signal.h index e0b29d26..fc0f0f28 100644 --- a/userspace/libraries/LibC/include/signal.h +++ b/userspace/libraries/LibC/include/signal.h @@ -152,15 +152,15 @@ typedef struct enum { #if defined(__x86_64__) + REG_RIP, + REG_RSP, + REG_RBP, REG_RAX, REG_RBX, REG_RCX, REG_RDX, REG_RDI, REG_RSI, - REG_RSP, - REG_RBP, - REG_RIP, REG_R8, REG_R9, REG_R10, @@ -170,15 +170,15 @@ enum REG_R14, REG_R15, #elif defined(__i686__) + REG_EIP, + REG_ESP, + REG_EBP, REG_EAX, REG_EBX, REG_ECX, REG_EDX, REG_EDI, REG_ESI, - REG_ESP, - REG_EBP, - REG_EIP, #else #error #endif