linux-user: Map unsupported signals to an out-of-bounds value

Do not return a valid signal number in one domain
when given an invalid signal number in the other domain.

Acked-by: Helge Deller <deller@gmx.de>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-08-22 20:45:38 -07:00
parent dbde2c0c0e
commit b60b91aa8f

View File

@ -44,9 +44,8 @@ abi_ulong default_sigreturn;
abi_ulong default_rt_sigreturn; abi_ulong default_rt_sigreturn;
/* /*
* System includes define _NSIG as SIGRTMAX + 1, * System includes define _NSIG as SIGRTMAX + 1, but qemu (like the kernel)
* but qemu (like the kernel) defines TARGET_NSIG as TARGET_SIGRTMAX * defines TARGET_NSIG as TARGET_SIGRTMAX and the first signal is 1.
* and the first signal is SIGHUP defined as 1
* Signal number 0 is reserved for use as kill(pid, 0), to test whether * Signal number 0 is reserved for use as kill(pid, 0), to test whether
* a process exists without sending it a signal. * a process exists without sending it a signal.
*/ */
@ -57,7 +56,6 @@ static uint8_t host_to_target_signal_table[_NSIG] = {
#define MAKE_SIG_ENTRY(sig) [sig] = TARGET_##sig, #define MAKE_SIG_ENTRY(sig) [sig] = TARGET_##sig,
MAKE_SIGNAL_LIST MAKE_SIGNAL_LIST
#undef MAKE_SIG_ENTRY #undef MAKE_SIG_ENTRY
/* next signals stay the same */
}; };
static uint8_t target_to_host_signal_table[TARGET_NSIG + 1]; static uint8_t target_to_host_signal_table[TARGET_NSIG + 1];
@ -65,18 +63,24 @@ static uint8_t target_to_host_signal_table[TARGET_NSIG + 1];
/* valid sig is between 1 and _NSIG - 1 */ /* valid sig is between 1 and _NSIG - 1 */
int host_to_target_signal(int sig) int host_to_target_signal(int sig)
{ {
if (sig < 1 || sig >= _NSIG) { if (sig < 1) {
return sig; return sig;
} }
if (sig >= _NSIG) {
return TARGET_NSIG + 1;
}
return host_to_target_signal_table[sig]; return host_to_target_signal_table[sig];
} }
/* valid sig is between 1 and TARGET_NSIG */ /* valid sig is between 1 and TARGET_NSIG */
int target_to_host_signal(int sig) int target_to_host_signal(int sig)
{ {
if (sig < 1 || sig > TARGET_NSIG) { if (sig < 1) {
return sig; return sig;
} }
if (sig > TARGET_NSIG) {
return _NSIG;
}
return target_to_host_signal_table[sig]; return target_to_host_signal_table[sig];
} }
@ -507,48 +511,48 @@ static int core_dump_signal(int sig)
static void signal_table_init(void) static void signal_table_init(void)
{ {
int host_sig, target_sig, count; int hsig, tsig, count;
/* /*
* Signals are supported starting from TARGET_SIGRTMIN and going up * Signals are supported starting from TARGET_SIGRTMIN and going up
* until we run out of host realtime signals. * until we run out of host realtime signals. Glibc uses the lower 2
* glibc at least uses only the lower 2 rt signals and probably * RT signals and (hopefully) nobody uses the upper ones.
* nobody's using the upper ones. * This is why SIGRTMIN (34) is generally greater than __SIGRTMIN (32).
* it's why SIGRTMIN (34) is generally greater than __SIGRTMIN (32) * To fix this properly we would need to do manual signal delivery
* To fix this properly we need to do manual signal delivery multiplexed * multiplexed over a single host signal.
* over a single host signal.
* Attempts for configure "missing" signals via sigaction will be * Attempts for configure "missing" signals via sigaction will be
* silently ignored. * silently ignored.
*/ */
for (host_sig = SIGRTMIN; host_sig <= SIGRTMAX; host_sig++) { for (hsig = SIGRTMIN; hsig <= SIGRTMAX; hsig++) {
target_sig = host_sig - SIGRTMIN + TARGET_SIGRTMIN; tsig = hsig - SIGRTMIN + TARGET_SIGRTMIN;
if (target_sig <= TARGET_NSIG) { if (tsig <= TARGET_NSIG) {
host_to_target_signal_table[host_sig] = target_sig; host_to_target_signal_table[hsig] = tsig;
} }
} }
/* generate signal conversion tables */ /* Invert the mapping that has already been assigned. */
for (target_sig = 1; target_sig <= TARGET_NSIG; target_sig++) { for (hsig = 1; hsig < _NSIG; hsig++) {
target_to_host_signal_table[target_sig] = _NSIG; /* poison */ tsig = host_to_target_signal_table[hsig];
} if (tsig) {
for (host_sig = 1; host_sig < _NSIG; host_sig++) { assert(target_to_host_signal_table[tsig] == 0);
if (host_to_target_signal_table[host_sig] == 0) { target_to_host_signal_table[tsig] = hsig;
host_to_target_signal_table[host_sig] = host_sig;
}
target_sig = host_to_target_signal_table[host_sig];
if (target_sig <= TARGET_NSIG) {
target_to_host_signal_table[target_sig] = host_sig;
} }
} }
if (trace_event_get_state_backends(TRACE_SIGNAL_TABLE_INIT)) { /* Map everything else out-of-bounds. */
for (target_sig = 1, count = 0; target_sig <= TARGET_NSIG; target_sig++) { for (hsig = 1; hsig < _NSIG; hsig++) {
if (target_to_host_signal_table[target_sig] == _NSIG) { if (host_to_target_signal_table[hsig] == 0) {
count++; host_to_target_signal_table[hsig] = TARGET_NSIG + 1;
}
} }
trace_signal_table_init(count);
} }
for (count = 0, tsig = 1; tsig <= TARGET_NSIG; tsig++) {
if (target_to_host_signal_table[tsig] == 0) {
target_to_host_signal_table[tsig] = _NSIG;
count++;
}
}
trace_signal_table_init(count);
} }
void signal_init(void) void signal_init(void)