Skip to content

Commit

Permalink
Kernel: Unblock SignalBlocker if a signal was just unmarked as pending
Browse files Browse the repository at this point in the history
When updating the signal mask, there is a small frame where we might set
up the receiving process for handing the signal and therefore remove
that signal from the list of pending signals before SignalBlocker has a
chance to block. In turn, this might cause SignalBlocker to never notice
that the signal arrives and it will never unblock once blocked.

Track the currently handled signal separately and include it when
determining if SignalBlocker should be unblocking.
  • Loading branch information
timschumi authored and bgianfo committed Jul 8, 2022
1 parent cd18999 commit edbffb3
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 1 deletion.
1 change: 1 addition & 0 deletions Kernel/Syscalls/sigaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ ErrorOr<FlatPtr> Process::sys$sigreturn([[maybe_unused]] RegisterState& register
auto saved_ax = TRY(copy_typed_from_user<FlatPtr>(stack_ptr));

Thread::current()->m_signal_mask = ucontext.uc_sigmask;
Thread::current()->m_currently_handled_signal = 0;
#if ARCH(X86_64)
auto sp = registers.rsp;
#elif ARCH(I386)
Expand Down
2 changes: 2 additions & 0 deletions Kernel/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,8 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)

ScopedAddressSpaceSwitcher switcher(m_process);

m_currently_handled_signal = signal;

u32 old_signal_mask = m_signal_mask;
u32 new_signal_mask = m_signal_action_masks[signal].value_or(action.mask);
if ((action.flags & SA_NODEFER) == SA_NODEFER)
Expand Down
1 change: 1 addition & 0 deletions Kernel/Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,7 @@ class Thread
u32 m_ticks_in_user { 0 };
u32 m_ticks_in_kernel { 0 };
u32 m_pending_signals { 0 };
u8 m_currently_handled_signal { 0 };
u32 m_signal_mask { 0 };
FlatPtr m_alternative_signal_stack { 0 };
FlatPtr m_alternative_signal_stack_size { 0 };
Expand Down
10 changes: 9 additions & 1 deletion Kernel/ThreadBlockers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,15 @@ bool Thread::SignalBlocker::check_pending_signals(bool from_add_blocker)
if (m_did_unblock)
return false;

auto matching_pending_signal = bit_scan_forward(thread().pending_signals() & m_pending_set);
auto pending_signals = thread().pending_signals() & m_pending_set;

// Also unblock if we have just "handled" that signal and are in the procecss
// of running their signal handler (i.e. we just unmarked the signal as pending).
if (thread().m_currently_handled_signal)
pending_signals |= (1 << (thread().m_currently_handled_signal - 1)) & m_pending_set;

auto matching_pending_signal = bit_scan_forward(pending_signals);

if (matching_pending_signal == 0)
return false;

Expand Down

0 comments on commit edbffb3

Please sign in to comment.