fix(libkernel): block guest signals by FreeBSD's bit n - 1

sigprocmask keeps the first word of the title's set as it is, where
FreeBSD keeps signal n at bit n - 1 (_SIG_BIT), but Dispatch tested bit
n. A title that blocked SIGTERM with a FreeBSD-built set (bit 14) was
not protected, and a set with bit 15 blocked SIGTERM instead of SIGURG.
Dispatch now tests bit n - 1; the stored mask and the set returned by
sigprocmask are unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jan Šlégl 2026-10-08 17:38:32 +02:00
parent ff8961dfbc
commit c26c1cae5b
2 changed files with 13 additions and 1 deletions

View File

@ -53,7 +53,7 @@ void Dispatch(int native) {
// Preserve the guest's persistent registration across CRT delivery.
std::signal(native, Dispatch);
#endif
if ((blockedMask.load() & (1u << guest)) != 0) return;
if ((blockedMask.load() & (1u << (guest - 1))) != 0) return;
const auto callback = handlers[guest].load();
if (reinterpret_cast<std::uintptr_t>(callback) > 1) callback(guest);
}

View File

@ -105,4 +105,16 @@ int main() {
Require(sigaction_nid_postfix(fixed, &defaults, &current) == 0 && current.handler == 0);
}
Require(sigaction_nid_postfix(15, nullptr, nullptr) == 0);
Require(signal_nid_postfix(15, Callback) != invalid);
GuestSignalSet termMask{{1u << 14, 0, 0, 0}};
received = 0;
Require(sigprocmask_nid_postfix(1, &termMask, nullptr) == 0);
Require(raise_nid_postfix(15) == 0 && received == 0);
Require(sigprocmask_nid_postfix(2, &termMask, nullptr) == 0);
Require(raise_nid_postfix(15) == 0 && received == 15);
GuestSignalSet urgMask{{1u << 15, 0, 0, 0}};
received = 0;
Require(sigprocmask_nid_postfix(1, &urgMask, nullptr) == 0);
Require(raise_nid_postfix(15) == 0 && received == 15);
Require(sigprocmask_nid_postfix(2, &urgMask, nullptr) == 0);
}