linux-user: Properly handle sigset arg to pselect
Unblocked signals are never delivered, because we didn't record the new mask for process_pending_signals. Handle this with the same mechanism as sigsuspend. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/834 Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <20220315084308.433109-4-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
parent
0a99f09383
commit
cb22603444
@ -1391,14 +1391,12 @@ static abi_long do_pselect6(abi_long arg1, abi_long arg2, abi_long arg3,
|
||||
* The 6th arg is actually two args smashed together,
|
||||
* so we cannot use the C library.
|
||||
*/
|
||||
sigset_t set;
|
||||
struct {
|
||||
sigset_t *set;
|
||||
size_t size;
|
||||
} sig, *sig_ptr;
|
||||
|
||||
abi_ulong arg_sigset, arg_sigsize, *arg7;
|
||||
target_sigset_t *target_sigset;
|
||||
|
||||
n = arg1;
|
||||
rfd_addr = arg2;
|
||||
@ -1439,10 +1437,8 @@ static abi_long do_pselect6(abi_long arg1, abi_long arg2, abi_long arg3,
|
||||
}
|
||||
|
||||
/* Extract the two packed args for the sigset */
|
||||
sig_ptr = NULL;
|
||||
if (arg6) {
|
||||
sig_ptr = &sig;
|
||||
sig.size = SIGSET_T_SIZE;
|
||||
|
||||
arg7 = lock_user(VERIFY_READ, arg6, sizeof(*arg7) * 2, 1);
|
||||
if (!arg7) {
|
||||
return -TARGET_EFAULT;
|
||||
@ -1452,28 +1448,22 @@ static abi_long do_pselect6(abi_long arg1, abi_long arg2, abi_long arg3,
|
||||
unlock_user(arg7, arg6, 0);
|
||||
|
||||
if (arg_sigset) {
|
||||
sig.set = &set;
|
||||
if (arg_sigsize != sizeof(*target_sigset)) {
|
||||
/* Like the kernel, we enforce correct size sigsets */
|
||||
return -TARGET_EINVAL;
|
||||
ret = process_sigsuspend_mask(&sig.set, arg_sigset, arg_sigsize);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
target_sigset = lock_user(VERIFY_READ, arg_sigset,
|
||||
sizeof(*target_sigset), 1);
|
||||
if (!target_sigset) {
|
||||
return -TARGET_EFAULT;
|
||||
}
|
||||
target_to_host_sigset(&set, target_sigset);
|
||||
unlock_user(target_sigset, arg_sigset, 0);
|
||||
} else {
|
||||
sig.set = NULL;
|
||||
sig_ptr = &sig;
|
||||
sig.size = SIGSET_T_SIZE;
|
||||
}
|
||||
} else {
|
||||
sig_ptr = NULL;
|
||||
}
|
||||
|
||||
ret = get_errno(safe_pselect6(n, rfds_ptr, wfds_ptr, efds_ptr,
|
||||
ts_ptr, sig_ptr));
|
||||
|
||||
if (sig_ptr) {
|
||||
finish_sigsuspend_mask(ret);
|
||||
}
|
||||
|
||||
if (!is_error(ret)) {
|
||||
if (rfd_addr && copy_to_user_fdset(rfd_addr, &rfds, n)) {
|
||||
return -TARGET_EFAULT;
|
||||
|
Loading…
Reference in New Issue
Block a user