aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-03-15 01:43:05 -0700
committerLaurent Vivier <laurent@vivier.eu>2022-03-22 13:06:21 +0100
commit0a99f09383a0f08e5b7cd0c187166f7eff6014ad (patch)
tree2abdbdbe06597f322edc415cf59e6a05d45f835c /linux-user
parent7fb5ef350bb434644fe1ac8eeb973543e017c932 (diff)
linux-user: Split out helpers for sigsuspend
Two new functions: process_sigsuspend_mask and finish_sigsuspend_mask. Move the size check and copy-from-user code. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Laurent Vivier <laurent@vivier.eu> Message-Id: <20220315084308.433109-3-richard.henderson@linaro.org> Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/signal-common.h26
-rw-r--r--linux-user/signal.c23
-rw-r--r--linux-user/syscall.c40
3 files changed, 66 insertions, 23 deletions
diff --git a/linux-user/signal-common.h b/linux-user/signal-common.h
index 2113165a75..6a7e4a93fc 100644
--- a/linux-user/signal-common.h
+++ b/linux-user/signal-common.h
@@ -92,4 +92,30 @@ abi_long do_swapcontext(CPUArchState *env, abi_ulong uold_ctx,
*/
int block_signals(void); /* Returns non zero if signal pending */
+/**
+ * process_sigsuspend_mask: read and apply syscall-local signal mask
+ *
+ * Read the guest signal mask from @sigset, length @sigsize.
+ * Convert that to a host signal mask and save it to sigpending_mask.
+ *
+ * Return value: negative target errno, or zero;
+ * store &sigpending_mask into *pset on success.
+ */
+int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
+ target_ulong sigsize);
+
+/**
+ * finish_sigsuspend_mask: finish a sigsuspend-like syscall
+ *
+ * Set in_sigsuspend if we need to use the modified sigset
+ * during process_pending_signals.
+ */
+static inline void finish_sigsuspend_mask(int ret)
+{
+ if (ret != -QEMU_ERESTARTSYS) {
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ ts->in_sigsuspend = 1;
+ }
+}
+
#endif
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 2a3f3cc23f..092e70b80c 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1199,3 +1199,26 @@ void process_pending_signals(CPUArchState *cpu_env)
}
ts->in_sigsuspend = 0;
}
+
+int process_sigsuspend_mask(sigset_t **pset, target_ulong sigset,
+ target_ulong sigsize)
+{
+ TaskState *ts = (TaskState *)thread_cpu->opaque;
+ sigset_t *host_set = &ts->sigsuspend_mask;
+ target_sigset_t *target_sigset;
+
+ if (sigsize != sizeof(*target_sigset)) {
+ /* Like the kernel, we enforce correct size sigsets */
+ return -TARGET_EINVAL;
+ }
+
+ target_sigset = lock_user(VERIFY_READ, sigset, sigsize, 1);
+ if (!target_sigset) {
+ return -TARGET_EFAULT;
+ }
+ target_to_host_sigset(host_set, target_sigset);
+ unlock_user(target_sigset, sigset, 0);
+
+ *pset = host_set;
+ return 0;
+}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 77cd88b537..d9b5662ff8 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -9557,41 +9557,35 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1,
#ifdef TARGET_NR_sigsuspend
case TARGET_NR_sigsuspend:
{
- TaskState *ts = cpu->opaque;
+ sigset_t *set;
+
#if defined(TARGET_ALPHA)
+ TaskState *ts = cpu->opaque;
/* target_to_host_old_sigset will bswap back */
abi_ulong mask = tswapal(arg1);
- target_to_host_old_sigset(&ts->sigsuspend_mask, &mask);
+ set = &ts->sigsuspend_mask;
+ target_to_host_old_sigset(set, &mask);
#else
- if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
- return -TARGET_EFAULT;
- target_to_host_old_sigset(&ts->sigsuspend_mask, p);
- unlock_user(p, arg1, 0);
-#endif
- ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
- SIGSET_T_SIZE));
- if (ret != -QEMU_ERESTARTSYS) {
- ts->in_sigsuspend = 1;
+ ret = process_sigsuspend_mask(&set, arg1, sizeof(target_sigset_t));
+ if (ret != 0) {
+ return ret;
}
+#endif
+ ret = get_errno(safe_rt_sigsuspend(set, SIGSET_T_SIZE));
+ finish_sigsuspend_mask(ret);
}
return ret;
#endif
case TARGET_NR_rt_sigsuspend:
{
- TaskState *ts = cpu->opaque;
+ sigset_t *set;
- if (arg2 != sizeof(target_sigset_t)) {
- return -TARGET_EINVAL;
- }
- if (!(p = lock_user(VERIFY_READ, arg1, sizeof(target_sigset_t), 1)))
- return -TARGET_EFAULT;
- target_to_host_sigset(&ts->sigsuspend_mask, p);
- unlock_user(p, arg1, 0);
- ret = get_errno(safe_rt_sigsuspend(&ts->sigsuspend_mask,
- SIGSET_T_SIZE));
- if (ret != -QEMU_ERESTARTSYS) {
- ts->in_sigsuspend = 1;
+ ret = process_sigsuspend_mask(&set, arg1, arg2);
+ if (ret != 0) {
+ return ret;
}
+ ret = get_errno(safe_rt_sigsuspend(set, SIGSET_T_SIZE));
+ finish_sigsuspend_mask(ret);
}
return ret;
#ifdef TARGET_NR_rt_sigtimedwait