Kernel: Add support for SA_SIGINFO

This commit is contained in:
2025-11-13 04:19:06 +02:00
parent a44c45ff9e
commit dd636ffcb2
13 changed files with 260 additions and 96 deletions

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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
{

View File

@@ -36,7 +36,7 @@ namespace Kernel
ARPTable::~ARPTable()
{
if (m_thread)
m_thread->add_signal(SIGKILL);
m_thread->add_signal(SIGKILL, {});
m_thread = nullptr;
}

View File

@@ -47,7 +47,7 @@ namespace Kernel
IPv4Layer::~IPv4Layer()
{
if (m_thread)
m_thread->add_signal(SIGKILL);
m_thread->add_signal(SIGKILL, {});
m_thread = nullptr;
}

View File

@@ -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())

View File

@@ -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<void> Process::kill(pid_t pid, int signal)
BAN::ErrorOr<void> 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;
}

View File

@@ -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<vaddr_t>(handler.sa_sigaction)
: reinterpret_cast<vaddr_t>(handler.sa_handler);
}
if (signal_handler == (vaddr_t)SIG_IGN)
if (signal_handler == reinterpret_cast<vaddr_t>(SIG_IGN))
continue;
if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(i))
if (signal_handler == reinterpret_cast<vaddr_t>(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<InterruptStack*>(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<vaddr_t>(handler.sa_handler);
if (handler.sa_flags & SA_RESETHAND)
handler.sa_handler = SIG_DFL;
signal_handler = (handler.sa_flags & SA_SIGINFO)
? reinterpret_cast<vaddr_t>(handler.sa_sigaction)
: reinterpret_cast<vaddr_t>(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<vaddr_t>(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<void*>(interrupt_stack.ip);
interrupt_stack.sp -= sizeof(siginfo_t);
*reinterpret_cast<siginfo_t*>(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<vaddr_t>(handler.sa_sigaction)
: reinterpret_cast<vaddr_t>(handler.sa_handler);
}
if (signal_handler == (vaddr_t)SIG_IGN)
if (signal_handler == reinterpret_cast<vaddr_t>(SIG_IGN))
return;
if (signal_handler == (vaddr_t)SIG_DFL && is_default_ignored_signal(signal))
if (signal_handler == reinterpret_cast<vaddr_t>(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);