Skip to content

Guard sentinel signal dispositions before SA_SIGINFO - #16

Merged
huangminghuang merged 1 commit into
masterfrom
fix/signal-handler-sentinels
Nov 10, 2026
Merged

huangminghuang merged 1 commit into
masterfrom
fix/signal-handler-sentinels

Conversation

@huangminghuang

Copy link
Copy Markdown
Contributor

A previous signal action can carry SA_SIGINFO together with SIG_IGN or SIG_DFL. chain_previous_signal_handler currently decodes sa_sigaction first and calls the sentinel as an address, crashing an ignored action or terminating a default action with the wrong signal.

Check the default and ignored dispositions before interpreting the callback union. Ignored signals return; default actions restore the saved disposition and re-raise the original signal. Legacy and three-argument callbacks retain their existing arguments, and a previous VM handler still uses the recursion fallback.

Regression tests round-trip default and ignored actions through the kernel with either flag setting, isolate termination in child processes, verify callback argument forwarding, and cover the VM self-predecessor guard. The new tests fail against the original header in both sentinel cases.

Validation on Linux x86-64:

  • Clang 18 Release: complete unit-test build and all 269 cases / 1,506 assertions pass.
  • GCC 14.2: focused predecessor regression passes all 4 cases / 26 assertions.
  • Clang 18 with AddressSanitizer, UBSan, and function-call sanitization: the same 4 cases / 26 assertions pass.
  • clangd checks of the signal header and new test translation unit report zero errors; whitespace checks pass.

Sysio consumers need a registry port revision after this change is merged; this PR does not update the registry.

Handle SIG_DFL and SIG_IGN before inspecting the sigaction callback union. Preserve the original terminating signal, real handler arguments, and the VM self-predecessor fallback. Add subprocess regressions that round-trip the sentinel actions through sigaction.
Comment on lines +112 to +113
} else if (prev_action->sa_handler == SIG_IGN) {
// Ignore the signal even when SA_SIGINFO is set on the saved disposition.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning is right for a signal sent with kill(), but for a real fault the faulting instruction re-executes, so the process spins instead of dying. With SIGSEGV ignored and the VM handler installed, a null write in host code never terminates; without the VM handler the kernel kills it despite SIG_IGN. Master already does this without SA_SIGINFO; this extends it to the SA_SIGINFO case, which used to crash. The OC adapter in wire-sysio#757 terminates for an ignored predecessor. Could this take the default branch when fault_is_synchronous(sig, info) (it would need the SIGFPE codes)? Not blocking.

sigaction(chained_signal, &action, nullptr) != 0 ||
sigaction(chained_signal, nullptr, &sysio::vm::prev_signal_handler<chained_signal>) != 0)
_exit(child_setup_failure);
std::signal(chained_signal, SIG_DFL);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resetting SIGILL to SIG_DFL here hides the restore in the default branch: with the sigaction(sig, prev_action, nullptr) line removed the suite still passes, although in production raise would then recurse through the VM handler. Installing signal_handler as the current disposition instead keeps all four cases passing and fails the default case without the restore.

@huangminghuang
huangminghuang merged commit 2c8d4b2 into master Nov 10, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants