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.hender...@linaro.org> --- linux-user/syscall.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 154cb1c7e8..8071a5191d 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -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; -- 2.25.1