On Sun, 9 Jan 2022 at 16:23, Warner Losh <i...@bsdimp.com> wrote:
>
> Start to implement the force_sig_fault code. This currently just calls
> queue_signal(). The bsd-user fork version of that will handle this the
> synchronous nature of this call. Add signal-common.h to hold signal
> helper functions like force_sig_fault.
>
> Signed-off-by: Stacey Son <s...@freebsd.org>
> Signed-off-by: Kyle Evans <kev...@freebsd.org>
> Signed-off-by: Warner Losh <i...@bsdimp.com>

> +/*
> + * Force a synchronously taken QEMU_SI_FAULT signal. For QEMU the
> + * 'force' part is handled in process_pending_signals().
> + */
> +void force_sig_fault(int sig, int code, abi_ulong addr)
> +{
> +    CPUState *cpu = thread_cpu;
> +    CPUArchState *env = cpu->env_ptr;
> +    target_siginfo_t info = {};
> +
> +    info.si_signo = sig;
> +    info.si_errno = 0;
> +    info.si_code = code;
> +    info.si_addr = addr;
> +    queue_signal(env, sig, &info);
> +}

In the linux-user implementation of this function, we pass in an extra
argument to queue_signal(), which is a QEMU_SI_* value (in this case
QEMU_SI_FAULT). The reason we do this is that the siginfo_t struct,
at least on Linux, is a pain: it has a union, and which field of the
union is the valid one is awkward to determine. Within the real
Linux kernel, the high bits of si_code are used to track what field
of the union is live, but those are masked out before handing the
signal to userspace. The effect is that QEMU sometimes has to
deal with siginfo_t structures where it knows exactly which field
of the union is valid because it generated the structure itself,
and sometimes with ones it got from guest userspace where it
has to make a best-guess. linux-user code deals with that using
the QEMU_SI_* codes: when we generate a siginfo_t ourselves and
know what field of the union is valid, we put the QEMU_SI_* into
the top part of si_code, and later when we need to byteswap it
for the guest we use tswap_siginfo(), which uses that to make a
known-correct choice. When we have to byteswap a siginfo_t which
we got from guest userspace, we use host_to_target_siginfo_noswap(),
which makes a best-guess based on things like the signal number.
And when we hand a siginfo_t to guest userspace, we mask out the
top part of si_code again, like the real kernel.

I'm not sure how the BSDs handle this, but at the moment in
this patchset you add both a host_to_target_siginfo_noswap()
(patch 16) and a tswap_siginfo(), but you've given them both
the guess-which-union-field-is-valid logic.

You don't need to address this in this patch series, but I wanted
to lay out the logic of why linux-user is doing things the
way it does so you can determine whether bsd-user needs to do
the same or not. (That might depend on which BSD: judging by
the target_siginfo definitions in bsd_user, freebsd puts
si_pid/si_uid in top-level struct fields, but netbsd and
openbsd put them in sub-fields of the union the same way
Linux does. For eg a SIGSEGV sent via kill() you want to swap
the pid/uid fields, but for a SIGSEGV generated by QEMU
you want to swap the si_addr. The other thing to check is
to what extent the BSD kernel ABI lets userspace spoof the
si_code field in a siginfo_t: Linux's rt_sigqueueinfo syscall
is quite lax in this regard.)

Anyway, for this patch:
Reviewed-by: Peter Maydell <peter.mayd...@linaro.org>

thanks
-- PMM

Reply via email to