mirror of
https://github.com/RGBCube/serenity
synced 2025-05-20 13:35:07 +00:00
Add some basic signal support.
It only works for sending a signal to a process that's in userspace code. We implement reception by synthesizing a PUSHA+PUSHF in the receiving process (operating on values in the TSS.) The TSS CS:EIP is then rerouted to the signal handler and a tiny return trampoline is constructed in a dedicated region in the receiving process. Also hacked up /bin/kill to be able to send arbitrary signals (kill -N PID)
This commit is contained in:
parent
52d502e11f
commit
153ea704af
13 changed files with 240 additions and 30 deletions
|
@ -731,17 +731,18 @@ void Process::sys$exit(int status)
|
|||
switchNow();
|
||||
}
|
||||
|
||||
void Process::send_signal(int signal, Process* sender)
|
||||
void Process::terminate_due_to_signal(int signal, Process* sender)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
bool wasCurrent = current == sender;
|
||||
bool wasCurrent = this == current;
|
||||
|
||||
set_state(Exiting);
|
||||
s_processes->remove(this);
|
||||
|
||||
notify_waiters(m_pid, 0, signal);
|
||||
|
||||
if (wasCurrent) {
|
||||
kprintf("Current process committing suicide!\n");
|
||||
kprintf("Current process (%u) committing suicide!\n", pid());
|
||||
if (!scheduleNewProcess()) {
|
||||
kprintf("Process::send_signal: Failed to schedule a new process :(\n");
|
||||
HANG;
|
||||
|
@ -752,6 +753,75 @@ void Process::send_signal(int signal, Process* sender)
|
|||
switchNow();
|
||||
}
|
||||
|
||||
void Process::send_signal(int signal, Process* sender)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
ASSERT(signal < 32);
|
||||
|
||||
// FIXME: Handle send_signal to self.
|
||||
ASSERT(this != current);
|
||||
|
||||
auto& action = m_signal_action_data[signal];
|
||||
// FIXME: Implement SA_SIGINFO signal handlers.
|
||||
ASSERT(!(action.flags & SA_SIGINFO));
|
||||
|
||||
auto handler_laddr = action.handler_or_sigaction;
|
||||
if (handler_laddr.is_null())
|
||||
return terminate_due_to_signal(signal, sender);
|
||||
|
||||
word ret_cs = m_tss.cs;
|
||||
dword ret_eip = m_tss.eip;
|
||||
dword ret_eflags = m_tss.eflags;
|
||||
|
||||
if ((ret_cs & 3) == 0) {
|
||||
// FIXME: Handle send_signal to process currently in kernel code.
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
ProcessPagingScope pagingScope(*this);
|
||||
dword old_esp = m_tss.esp;
|
||||
push_value_on_stack(ret_eip);
|
||||
push_value_on_stack(ret_eflags);
|
||||
push_value_on_stack(m_tss.eax);
|
||||
push_value_on_stack(m_tss.ecx);
|
||||
push_value_on_stack(m_tss.edx);
|
||||
push_value_on_stack(m_tss.ebx);
|
||||
push_value_on_stack(old_esp);
|
||||
push_value_on_stack(m_tss.ebp);
|
||||
push_value_on_stack(m_tss.esi);
|
||||
push_value_on_stack(m_tss.edi);
|
||||
m_tss.eax = (dword)signal;
|
||||
m_tss.cs = 0x1b;
|
||||
m_tss.eip = handler_laddr.get();
|
||||
|
||||
if (m_return_from_signal_trampoline.is_null()) {
|
||||
auto* region = allocate_region(LinearAddress(), PAGE_SIZE, "signal_trampoline", true, true); // FIXME: Remap as read-only after setup.
|
||||
m_return_from_signal_trampoline = region->linearAddress;
|
||||
byte* code_ptr = m_return_from_signal_trampoline.asPtr();
|
||||
*code_ptr++ = 0x61; // popa
|
||||
*code_ptr++ = 0x9d; // popf
|
||||
*code_ptr++ = 0xc3; // ret
|
||||
*code_ptr++ = 0x0f; // ud2
|
||||
*code_ptr++ = 0x0b;
|
||||
}
|
||||
|
||||
push_value_on_stack(m_return_from_signal_trampoline.get());
|
||||
|
||||
dbgprintf("signal: %s(%u) sent %d to %s(%u)\n", sender->name().characters(), sender->pid(), signal, name().characters(), pid());
|
||||
|
||||
if (sender == this) {
|
||||
yield();
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
void Process::push_value_on_stack(dword value)
|
||||
{
|
||||
m_tss.esp -= 4;
|
||||
dword* stack_ptr = (dword*)m_tss.esp;
|
||||
*stack_ptr = value;
|
||||
}
|
||||
|
||||
void Process::processDidCrash(Process* crashedProcess)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
|
@ -1183,12 +1253,6 @@ int Process::sys$isatty(int fd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
Unix::sighandler_t Process::sys$signal(int signum, Unix::sighandler_t handler)
|
||||
{
|
||||
dbgprintf("sys$signal: %d => L%x\n", signum, handler);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Process::sys$kill(pid_t pid, int signal)
|
||||
{
|
||||
if (pid == 0) {
|
||||
|
@ -1466,3 +1530,26 @@ int Process::sys$dup2(int old_fd, int new_fd)
|
|||
m_file_descriptors[new_fd] = handle;
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
Unix::sighandler_t Process::sys$signal(int signum, Unix::sighandler_t handler)
|
||||
{
|
||||
// FIXME: Fail with -EINVAL if attepmting to catch or ignore SIGKILL or SIGSTOP.
|
||||
if (signum >= 32)
|
||||
return (Unix::sighandler_t)-EINVAL;
|
||||
dbgprintf("sys$signal: %d => L%x\n", signum, handler);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int Process::sys$sigaction(int signum, const Unix::sigaction* act, Unix::sigaction* old_act)
|
||||
{
|
||||
// FIXME: Fail with -EINVAL if attepmting to change action for SIGKILL or SIGSTOP.
|
||||
if (signum >= 32)
|
||||
return -EINVAL;
|
||||
VALIDATE_USER_READ(act, sizeof(Unix::sigaction));
|
||||
InterruptDisabler disabler; // FIXME: This should use a narrower lock.
|
||||
auto& action = m_signal_action_data[signum];
|
||||
action.restorer = LinearAddress((dword)act->sa_restorer);
|
||||
action.flags = act->sa_flags;
|
||||
action.handler_or_sigaction = LinearAddress((dword)act->sa_sigaction);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue