diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2016-05-27 15:51:59 +0100 |
---|---|---|
committer | Riku Voipio <riku.voipio@linaro.org> | 2016-06-07 16:39:08 +0300 |
commit | a70dadc7f1a3e96a7179c6c3a6ccd1a0ea65760a (patch) | |
tree | e34ceed685ce773412484873c9be584f71c19348 /linux-user/syscall_defs.h | |
parent | 7d92d34ee4c7988f5ef6c8a5ed23d2c3e0837253 (diff) |
linux-user: Use both si_code and si_signo when converting siginfo_t
The siginfo_t struct includes a union. The correct way to identify
which fields of the union are relevant is complicated, because we
have to use a combination of the si_code and si_signo to figure out
which of the union's members are valid. (Within the host kernel it
is always possible to tell, but the kernel carefully avoids giving
userspace the high 16 bits of si_code, so we don't have the
information to do this the easy way...) We therefore make our best
guess, bearing in mind that a guest can spoof most of the si_codes
via rt_sigqueueinfo() if it likes. Once we have made our guess, we
record it in the top 16 bits of the si_code, so that tswap_siginfo()
later can use it. tswap_siginfo() then strips these top bits out
before writing si_code to the guest (sign-extending the lower bits).
This fixes a bug where fields were sometimes wrong; in particular
the LTP kill10 test went into an infinite loop because its signal
handler got a si_pid value of 0 rather than the pid of the sending
process.
As part of this change, we switch to using __put_user() in the
tswap_siginfo code which writes out the byteswapped values to
the target memory, in case the target memory pointer is not
sufficiently aligned for the host CPU's requirements.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
Diffstat (limited to 'linux-user/syscall_defs.h')
-rw-r--r-- | linux-user/syscall_defs.h | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 34af15a683..124754f8bd 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -673,6 +673,21 @@ typedef struct { #define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE - TARGET_SI_PREAMBLE_SIZE) / sizeof(int)) +/* Within QEMU the top 16 bits of si_code indicate which of the parts of + * the union in target_siginfo is valid. This only applies between + * host_to_target_siginfo_noswap() and tswap_siginfo(); it does not + * appear either within host siginfo_t or in target_siginfo structures + * which we get from the guest userspace program. (The Linux kernel + * does a similar thing with using the top bits for its own internal + * purposes but not letting them be visible to userspace.) + */ +#define QEMU_SI_KILL 0 +#define QEMU_SI_TIMER 1 +#define QEMU_SI_POLL 2 +#define QEMU_SI_FAULT 3 +#define QEMU_SI_CHLD 4 +#define QEMU_SI_RT 5 + typedef struct target_siginfo { #ifdef TARGET_MIPS int si_signo; |