* [PATCH] linux-user/i386: Properly align signal frame
@ 2023-05-24 5:46 Richard Henderson
2023-05-24 5:50 ` Richard Henderson
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Richard Henderson @ 2023-05-24 5:46 UTC (permalink / raw)
To: qemu-devel; +Cc: fanwj, laurent
The beginning of the structure, with pretaddr, should be just below
16-byte alignment. Disconnect fpstate from sigframe, just like the
kernel does.
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
linux-user/i386/signal.c | 104 +++++++++++++++++--------------
tests/tcg/x86_64/sigstack.c | 33 ++++++++++
tests/tcg/x86_64/Makefile.target | 1 +
3 files changed, 90 insertions(+), 48 deletions(-)
create mode 100644 tests/tcg/x86_64/sigstack.c
diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
index 60fa07d6f9..c49467de78 100644
--- a/linux-user/i386/signal.c
+++ b/linux-user/i386/signal.c
@@ -191,16 +191,7 @@ struct sigframe {
struct target_fpstate fpstate_unused;
abi_ulong extramask[TARGET_NSIG_WORDS-1];
char retcode[8];
-
- /*
- * This field will be 16-byte aligned in memory. Applying QEMU_ALIGNED
- * to it ensures that the base of the frame has an appropriate alignment
- * too.
- */
- struct target_fpstate fpstate QEMU_ALIGNED(8);
};
-#define TARGET_SIGFRAME_FXSAVE_OFFSET ( \
- offsetof(struct sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
struct rt_sigframe {
abi_ulong pretcode;
@@ -210,27 +201,21 @@ struct rt_sigframe {
struct target_siginfo info;
struct target_ucontext uc;
char retcode[8];
- struct target_fpstate fpstate QEMU_ALIGNED(8);
};
-#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
- offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
#else
-
struct rt_sigframe {
abi_ulong pretcode;
struct target_ucontext uc;
struct target_siginfo info;
- struct target_fpstate fpstate QEMU_ALIGNED(16);
};
-#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
- offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
#endif
/*
* Set up a signal frame.
*/
-static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
+static void xsave_sigcontext(CPUX86State *env,
+ struct target_fpstate_fxsave *fxsave,
abi_ulong fxsave_addr)
{
if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
@@ -266,8 +251,9 @@ static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxs
}
static void setup_sigcontext(struct target_sigcontext *sc,
- struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
- abi_ulong fpstate_addr)
+ struct target_fpstate *fpstate,
+ CPUX86State *env, abi_ulong mask,
+ abi_ulong fpstate_addr)
{
CPUState *cs = env_cpu(env);
#ifndef TARGET_X86_64
@@ -347,10 +333,11 @@ static void setup_sigcontext(struct target_sigcontext *sc,
* Determine which stack to use..
*/
-static inline abi_ulong
-get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset)
+static abi_ulong get_sigframe(struct target_sigaction *ka, CPUX86State *env,
+ size_t *frame_size, abi_ulong *fpsave_addr)
{
- unsigned long esp;
+ abi_ulong esp, orig;
+ size_t fpsave_size;
/* Default to using normal stack */
esp = get_sp_from_cpustate(env);
@@ -371,16 +358,23 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset
}
#endif
}
+ orig = esp;
- if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
- return (esp - (fxsave_offset + TARGET_FXSAVE_SIZE)) & -8ul;
- } else if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
- return ((esp - TARGET_FXSAVE_SIZE) & -16ul) - fxsave_offset;
+ if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
+ fpsave_size = TARGET_FXSAVE_SIZE;
+ esp = ROUND_DOWN(esp - fpsave_size, 16);
} else {
- size_t xstate_size =
- xsave_area_size(env->xcr0, false) + TARGET_FP_XSTATE_MAGIC2_SIZE;
- return ((esp - xstate_size) & -64ul) - fxsave_offset;
+ fpsave_size = xsave_area_size(env->xcr0, false)
+ + TARGET_FP_XSTATE_MAGIC2_SIZE;
+ esp = ROUND_DOWN(esp - fpsave_size, 64);
}
+ *fpsave_addr = esp;
+
+ esp = esp - *frame_size + sizeof(abi_ulong);
+ esp = ROUND_DOWN(esp, 16) - sizeof(abi_ulong);
+
+ *frame_size = orig - esp;
+ return esp;
}
#ifndef TARGET_X86_64
@@ -405,26 +399,34 @@ void setup_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUX86State *env)
{
abi_ulong frame_addr;
+ abi_ulong fpstate_addr;
+ size_t frame_size;
struct sigframe *frame;
+ struct target_fpstate *fpstate;
int i;
- frame_addr = get_sigframe(ka, env, TARGET_SIGFRAME_FXSAVE_OFFSET);
+ frame_size = sizeof(struct sigframe);
+ frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
trace_user_setup_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
+ if (!frame) {
goto give_sigsegv;
+ }
+ fpstate = (void *)frame + (fpstate_addr - frame_addr);
__put_user(sig, &frame->sig);
- setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
- frame_addr + offsetof(struct sigframe, fpstate));
+ setup_sigcontext(&frame->sc, fpstate, env, set->sig[0], fpstate_addr);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
+ for (i = 1; i < TARGET_NSIG_WORDS; i++) {
__put_user(set->sig[i], &frame->extramask[i - 1]);
}
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
+ /*
+ * Set up to return from userspace.
+ * If provided, use a stub already in userspace.
+ */
if (ka->sa_flags & TARGET_SA_RESTORER) {
__put_user(ka->sa_restorer, &frame->pretcode);
} else {
@@ -443,11 +445,10 @@ void setup_frame(int sig, struct target_sigaction *ka,
cpu_x86_load_seg(env, R_CS, __USER_CS);
env->eflags &= ~TF_MASK;
- unlock_user_struct(frame, frame_addr, 1);
-
+ unlock_user(frame, frame_addr, frame_size);
return;
-give_sigsegv:
+ give_sigsegv:
force_sigsegv(sig);
}
#endif
@@ -458,17 +459,24 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUX86State *env)
{
abi_ulong frame_addr;
+ abi_ulong fpstate_addr;
+ size_t frame_size;
#ifndef TARGET_X86_64
abi_ulong addr;
#endif
struct rt_sigframe *frame;
+ struct target_fpstate *fpstate;
int i;
- frame_addr = get_sigframe(ka, env, TARGET_RT_SIGFRAME_FXSAVE_OFFSET);
+ frame_size = sizeof(struct rt_sigframe);
+ frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
trace_user_setup_rt_frame(env, frame_addr);
- if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
+ frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
+ if (!frame) {
goto give_sigsegv;
+ }
+ fpstate = (void *)frame + (fpstate_addr - frame_addr);
/* These fields are only in rt_sigframe on 32 bit */
#ifndef TARGET_X86_64
@@ -490,10 +498,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
}
__put_user(0, &frame->uc.tuc_link);
target_save_altstack(&frame->uc.tuc_stack, env);
- setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
- set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
+ setup_sigcontext(&frame->uc.tuc_mcontext, fpstate, env,
+ set->sig[0], fpstate_addr);
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+ for (i = 0; i < TARGET_NSIG_WORDS; i++) {
__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
}
@@ -533,15 +541,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
cpu_x86_load_seg(env, R_SS, __USER_DS);
env->eflags &= ~TF_MASK;
- unlock_user_struct(frame, frame_addr, 1);
-
+ unlock_user(frame, frame_addr, frame_size);
return;
-give_sigsegv:
+ give_sigsegv:
force_sigsegv(sig);
}
-static int xrstor_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
+static int xrstor_sigcontext(CPUX86State *env,
+ struct target_fpstate_fxsave *fxsave,
abi_ulong fxsave_addr)
{
if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
diff --git a/tests/tcg/x86_64/sigstack.c b/tests/tcg/x86_64/sigstack.c
new file mode 100644
index 0000000000..06cb847569
--- /dev/null
+++ b/tests/tcg/x86_64/sigstack.c
@@ -0,0 +1,33 @@
+#include <stdlib.h>
+#include <assert.h>
+#include <signal.h>
+#include <stdint.h>
+
+void __attribute__((noinline)) bar(void)
+{
+ exit(EXIT_SUCCESS);
+}
+
+void __attribute__((noinline, ms_abi)) foo(void)
+{
+ /*
+ * With ms_abi, there are call-saved xmm registers, which are forced
+ * to the stack around the call to sysv_abi bar(). If the signal
+ * stack frame is not properly aligned, movaps will raise #GP.
+ */
+ bar();
+}
+
+void sighandler(int num)
+{
+ void* sp = __builtin_dwarf_cfa();
+ assert((uintptr_t)sp % 16 == 0);
+ foo();
+}
+
+int main(void)
+{
+ signal(SIGUSR1, sighandler);
+ raise(SIGUSR1);
+ abort();
+}
diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
index e64aab1b81..d961599f64 100644
--- a/tests/tcg/x86_64/Makefile.target
+++ b/tests/tcg/x86_64/Makefile.target
@@ -13,6 +13,7 @@ X86_64_TESTS += vsyscall
X86_64_TESTS += noexec
X86_64_TESTS += cmpxchg
X86_64_TESTS += adox
+X86_64_TESTS += sigstack
TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
else
TESTS=$(MULTIARCH_TESTS)
--
2.34.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-05-24 5:46 [PATCH] linux-user/i386: Properly align signal frame Richard Henderson
@ 2023-05-24 5:50 ` Richard Henderson
2023-05-26 2:56 ` fanwj--- via
2023-06-20 13:26 ` Richard Henderson
2023-10-26 6:35 ` Michael Tokarev
2 siblings, 1 reply; 11+ messages in thread
From: Richard Henderson @ 2023-05-24 5:50 UTC (permalink / raw)
To: qemu-devel; +Cc: fanwj, laurent
On 5/23/23 22:46, Richard Henderson wrote:
> The beginning of the structure, with pretaddr, should be just below
> 16-byte alignment. Disconnect fpstate from sigframe, just like the
> kernel does.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/i386/signal.c | 104 +++++++++++++++++--------------
> tests/tcg/x86_64/sigstack.c | 33 ++++++++++
> tests/tcg/x86_64/Makefile.target | 1 +
> 3 files changed, 90 insertions(+), 48 deletions(-)
> create mode 100644 tests/tcg/x86_64/sigstack.c
Oops, meant to add
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1648
r~
>
> diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
> index 60fa07d6f9..c49467de78 100644
> --- a/linux-user/i386/signal.c
> +++ b/linux-user/i386/signal.c
> @@ -191,16 +191,7 @@ struct sigframe {
> struct target_fpstate fpstate_unused;
> abi_ulong extramask[TARGET_NSIG_WORDS-1];
> char retcode[8];
> -
> - /*
> - * This field will be 16-byte aligned in memory. Applying QEMU_ALIGNED
> - * to it ensures that the base of the frame has an appropriate alignment
> - * too.
> - */
> - struct target_fpstate fpstate QEMU_ALIGNED(8);
> };
> -#define TARGET_SIGFRAME_FXSAVE_OFFSET ( \
> - offsetof(struct sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
>
> struct rt_sigframe {
> abi_ulong pretcode;
> @@ -210,27 +201,21 @@ struct rt_sigframe {
> struct target_siginfo info;
> struct target_ucontext uc;
> char retcode[8];
> - struct target_fpstate fpstate QEMU_ALIGNED(8);
> };
> -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
> - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
> #else
> -
> struct rt_sigframe {
> abi_ulong pretcode;
> struct target_ucontext uc;
> struct target_siginfo info;
> - struct target_fpstate fpstate QEMU_ALIGNED(16);
> };
> -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
> - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
> #endif
>
> /*
> * Set up a signal frame.
> */
>
> -static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
> +static void xsave_sigcontext(CPUX86State *env,
> + struct target_fpstate_fxsave *fxsave,
> abi_ulong fxsave_addr)
> {
> if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> @@ -266,8 +251,9 @@ static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxs
> }
>
> static void setup_sigcontext(struct target_sigcontext *sc,
> - struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
> - abi_ulong fpstate_addr)
> + struct target_fpstate *fpstate,
> + CPUX86State *env, abi_ulong mask,
> + abi_ulong fpstate_addr)
> {
> CPUState *cs = env_cpu(env);
> #ifndef TARGET_X86_64
> @@ -347,10 +333,11 @@ static void setup_sigcontext(struct target_sigcontext *sc,
> * Determine which stack to use..
> */
>
> -static inline abi_ulong
> -get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset)
> +static abi_ulong get_sigframe(struct target_sigaction *ka, CPUX86State *env,
> + size_t *frame_size, abi_ulong *fpsave_addr)
> {
> - unsigned long esp;
> + abi_ulong esp, orig;
> + size_t fpsave_size;
>
> /* Default to using normal stack */
> esp = get_sp_from_cpustate(env);
> @@ -371,16 +358,23 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset
> }
> #endif
> }
> + orig = esp;
>
> - if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
> - return (esp - (fxsave_offset + TARGET_FXSAVE_SIZE)) & -8ul;
> - } else if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> - return ((esp - TARGET_FXSAVE_SIZE) & -16ul) - fxsave_offset;
> + if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> + fpsave_size = TARGET_FXSAVE_SIZE;
> + esp = ROUND_DOWN(esp - fpsave_size, 16);
> } else {
> - size_t xstate_size =
> - xsave_area_size(env->xcr0, false) + TARGET_FP_XSTATE_MAGIC2_SIZE;
> - return ((esp - xstate_size) & -64ul) - fxsave_offset;
> + fpsave_size = xsave_area_size(env->xcr0, false)
> + + TARGET_FP_XSTATE_MAGIC2_SIZE;
> + esp = ROUND_DOWN(esp - fpsave_size, 64);
> }
> + *fpsave_addr = esp;
> +
> + esp = esp - *frame_size + sizeof(abi_ulong);
> + esp = ROUND_DOWN(esp, 16) - sizeof(abi_ulong);
> +
> + *frame_size = orig - esp;
> + return esp;
> }
>
> #ifndef TARGET_X86_64
> @@ -405,26 +399,34 @@ void setup_frame(int sig, struct target_sigaction *ka,
> target_sigset_t *set, CPUX86State *env)
> {
> abi_ulong frame_addr;
> + abi_ulong fpstate_addr;
> + size_t frame_size;
> struct sigframe *frame;
> + struct target_fpstate *fpstate;
> int i;
>
> - frame_addr = get_sigframe(ka, env, TARGET_SIGFRAME_FXSAVE_OFFSET);
> + frame_size = sizeof(struct sigframe);
> + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
> trace_user_setup_frame(env, frame_addr);
>
> - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
> + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
> + if (!frame) {
> goto give_sigsegv;
> + }
> + fpstate = (void *)frame + (fpstate_addr - frame_addr);
>
> __put_user(sig, &frame->sig);
>
> - setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
> - frame_addr + offsetof(struct sigframe, fpstate));
> + setup_sigcontext(&frame->sc, fpstate, env, set->sig[0], fpstate_addr);
>
> - for(i = 1; i < TARGET_NSIG_WORDS; i++) {
> + for (i = 1; i < TARGET_NSIG_WORDS; i++) {
> __put_user(set->sig[i], &frame->extramask[i - 1]);
> }
>
> - /* Set up to return from userspace. If provided, use a stub
> - already in userspace. */
> + /*
> + * Set up to return from userspace.
> + * If provided, use a stub already in userspace.
> + */
> if (ka->sa_flags & TARGET_SA_RESTORER) {
> __put_user(ka->sa_restorer, &frame->pretcode);
> } else {
> @@ -443,11 +445,10 @@ void setup_frame(int sig, struct target_sigaction *ka,
> cpu_x86_load_seg(env, R_CS, __USER_CS);
> env->eflags &= ~TF_MASK;
>
> - unlock_user_struct(frame, frame_addr, 1);
> -
> + unlock_user(frame, frame_addr, frame_size);
> return;
>
> -give_sigsegv:
> + give_sigsegv:
> force_sigsegv(sig);
> }
> #endif
> @@ -458,17 +459,24 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> target_sigset_t *set, CPUX86State *env)
> {
> abi_ulong frame_addr;
> + abi_ulong fpstate_addr;
> + size_t frame_size;
> #ifndef TARGET_X86_64
> abi_ulong addr;
> #endif
> struct rt_sigframe *frame;
> + struct target_fpstate *fpstate;
> int i;
>
> - frame_addr = get_sigframe(ka, env, TARGET_RT_SIGFRAME_FXSAVE_OFFSET);
> + frame_size = sizeof(struct rt_sigframe);
> + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
> trace_user_setup_rt_frame(env, frame_addr);
>
> - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
> + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
> + if (!frame) {
> goto give_sigsegv;
> + }
> + fpstate = (void *)frame + (fpstate_addr - frame_addr);
>
> /* These fields are only in rt_sigframe on 32 bit */
> #ifndef TARGET_X86_64
> @@ -490,10 +498,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> }
> __put_user(0, &frame->uc.tuc_link);
> target_save_altstack(&frame->uc.tuc_stack, env);
> - setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
> - set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
> + setup_sigcontext(&frame->uc.tuc_mcontext, fpstate, env,
> + set->sig[0], fpstate_addr);
>
> - for(i = 0; i < TARGET_NSIG_WORDS; i++) {
> + for (i = 0; i < TARGET_NSIG_WORDS; i++) {
> __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
> }
>
> @@ -533,15 +541,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> cpu_x86_load_seg(env, R_SS, __USER_DS);
> env->eflags &= ~TF_MASK;
>
> - unlock_user_struct(frame, frame_addr, 1);
> -
> + unlock_user(frame, frame_addr, frame_size);
> return;
>
> -give_sigsegv:
> + give_sigsegv:
> force_sigsegv(sig);
> }
>
> -static int xrstor_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
> +static int xrstor_sigcontext(CPUX86State *env,
> + struct target_fpstate_fxsave *fxsave,
> abi_ulong fxsave_addr)
> {
> if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
> diff --git a/tests/tcg/x86_64/sigstack.c b/tests/tcg/x86_64/sigstack.c
> new file mode 100644
> index 0000000000..06cb847569
> --- /dev/null
> +++ b/tests/tcg/x86_64/sigstack.c
> @@ -0,0 +1,33 @@
> +#include <stdlib.h>
> +#include <assert.h>
> +#include <signal.h>
> +#include <stdint.h>
> +
> +void __attribute__((noinline)) bar(void)
> +{
> + exit(EXIT_SUCCESS);
> +}
> +
> +void __attribute__((noinline, ms_abi)) foo(void)
> +{
> + /*
> + * With ms_abi, there are call-saved xmm registers, which are forced
> + * to the stack around the call to sysv_abi bar(). If the signal
> + * stack frame is not properly aligned, movaps will raise #GP.
> + */
> + bar();
> +}
> +
> +void sighandler(int num)
> +{
> + void* sp = __builtin_dwarf_cfa();
> + assert((uintptr_t)sp % 16 == 0);
> + foo();
> +}
> +
> +int main(void)
> +{
> + signal(SIGUSR1, sighandler);
> + raise(SIGUSR1);
> + abort();
> +}
> diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
> index e64aab1b81..d961599f64 100644
> --- a/tests/tcg/x86_64/Makefile.target
> +++ b/tests/tcg/x86_64/Makefile.target
> @@ -13,6 +13,7 @@ X86_64_TESTS += vsyscall
> X86_64_TESTS += noexec
> X86_64_TESTS += cmpxchg
> X86_64_TESTS += adox
> +X86_64_TESTS += sigstack
> TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
> else
> TESTS=$(MULTIARCH_TESTS)
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: Re: [PATCH] linux-user/i386: Properly align signal frame
2023-05-24 5:50 ` Richard Henderson
@ 2023-05-26 2:56 ` fanwj--- via
2023-05-26 14:27 ` Richard Henderson
0 siblings, 1 reply; 11+ messages in thread
From: fanwj--- via @ 2023-05-26 2:56 UTC (permalink / raw)
To: Richard Henderson; +Cc: qemu-devel, laurent
"The beginning of the structure, with pretaddr, should be just below 16-byte alignment."
It is incorrect! The beginning of the structure, with pretaddr not aligned as 16-byte!
On x86-64, It aligned as (16n - sizeof(void*)) because of instruction "call" !
> -----原始邮件-----
> 发件人: "Richard Henderson" <richard.henderson@linaro.org>
> 发送时间: 2023-05-24 13:50:43 (星期三)
> 收件人: qemu-devel@nongnu.org
> 抄送: fanwj@mail.ustc.edu.cn, laurent@vivier.eu
> 主题: Re: [PATCH] linux-user/i386: Properly align signal frame
>
> On 5/23/23 22:46, Richard Henderson wrote:
> > The beginning of the structure, with pretaddr, should be just below
> > 16-byte alignment. Disconnect fpstate from sigframe, just like the
> > kernel does.
> >
> > Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> > ---
> > linux-user/i386/signal.c | 104 +++++++++++++++++--------------
> > tests/tcg/x86_64/sigstack.c | 33 ++++++++++
> > tests/tcg/x86_64/Makefile.target | 1 +
> > 3 files changed, 90 insertions(+), 48 deletions(-)
> > create mode 100644 tests/tcg/x86_64/sigstack.c
>
> Oops, meant to add
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1648
>
> r~
>
> >
> > diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
> > index 60fa07d6f9..c49467de78 100644
> > --- a/linux-user/i386/signal.c
> > +++ b/linux-user/i386/signal.c
> > @@ -191,16 +191,7 @@ struct sigframe {
> > struct target_fpstate fpstate_unused;
> > abi_ulong extramask[TARGET_NSIG_WORDS-1];
> > char retcode[8];
> > -
> > - /*
> > - * This field will be 16-byte aligned in memory. Applying QEMU_ALIGNED
> > - * to it ensures that the base of the frame has an appropriate alignment
> > - * too.
> > - */
> > - struct target_fpstate fpstate QEMU_ALIGNED(8);
> > };
> > -#define TARGET_SIGFRAME_FXSAVE_OFFSET ( \
> > - offsetof(struct sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
> >
> > struct rt_sigframe {
> > abi_ulong pretcode;
> > @@ -210,27 +201,21 @@ struct rt_sigframe {
> > struct target_siginfo info;
> > struct target_ucontext uc;
> > char retcode[8];
> > - struct target_fpstate fpstate QEMU_ALIGNED(8);
> > };
> > -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
> > - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
> > #else
> > -
> > struct rt_sigframe {
> > abi_ulong pretcode;
> > struct target_ucontext uc;
> > struct target_siginfo info;
> > - struct target_fpstate fpstate QEMU_ALIGNED(16);
> > };
> > -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
> > - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
> > #endif
> >
> > /*
> > * Set up a signal frame.
> > */
> >
> > -static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
> > +static void xsave_sigcontext(CPUX86State *env,
> > + struct target_fpstate_fxsave *fxsave,
> > abi_ulong fxsave_addr)
> > {
> > if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> > @@ -266,8 +251,9 @@ static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxs
> > }
> >
> > static void setup_sigcontext(struct target_sigcontext *sc,
> > - struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
> > - abi_ulong fpstate_addr)
> > + struct target_fpstate *fpstate,
> > + CPUX86State *env, abi_ulong mask,
> > + abi_ulong fpstate_addr)
> > {
> > CPUState *cs = env_cpu(env);
> > #ifndef TARGET_X86_64
> > @@ -347,10 +333,11 @@ static void setup_sigcontext(struct target_sigcontext *sc,
> > * Determine which stack to use..
> > */
> >
> > -static inline abi_ulong
> > -get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset)
> > +static abi_ulong get_sigframe(struct target_sigaction *ka, CPUX86State *env,
> > + size_t *frame_size, abi_ulong *fpsave_addr)
> > {
> > - unsigned long esp;
> > + abi_ulong esp, orig;
> > + size_t fpsave_size;
> >
> > /* Default to using normal stack */
> > esp = get_sp_from_cpustate(env);
> > @@ -371,16 +358,23 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset
> > }
> > #endif
> > }
> > + orig = esp;
> >
> > - if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
> > - return (esp - (fxsave_offset + TARGET_FXSAVE_SIZE)) & -8ul;
> > - } else if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> > - return ((esp - TARGET_FXSAVE_SIZE) & -16ul) - fxsave_offset;
> > + if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> > + fpsave_size = TARGET_FXSAVE_SIZE;
> > + esp = ROUND_DOWN(esp - fpsave_size, 16);
> > } else {
> > - size_t xstate_size =
> > - xsave_area_size(env->xcr0, false) + TARGET_FP_XSTATE_MAGIC2_SIZE;
> > - return ((esp - xstate_size) & -64ul) - fxsave_offset;
> > + fpsave_size = xsave_area_size(env->xcr0, false)
> > + + TARGET_FP_XSTATE_MAGIC2_SIZE;
> > + esp = ROUND_DOWN(esp - fpsave_size, 64);
> > }
> > + *fpsave_addr = esp;
> > +
> > + esp = esp - *frame_size + sizeof(abi_ulong);
> > + esp = ROUND_DOWN(esp, 16) - sizeof(abi_ulong);
> > +
> > + *frame_size = orig - esp;
> > + return esp;
> > }
> >
> > #ifndef TARGET_X86_64
> > @@ -405,26 +399,34 @@ void setup_frame(int sig, struct target_sigaction *ka,
> > target_sigset_t *set, CPUX86State *env)
> > {
> > abi_ulong frame_addr;
> > + abi_ulong fpstate_addr;
> > + size_t frame_size;
> > struct sigframe *frame;
> > + struct target_fpstate *fpstate;
> > int i;
> >
> > - frame_addr = get_sigframe(ka, env, TARGET_SIGFRAME_FXSAVE_OFFSET);
> > + frame_size = sizeof(struct sigframe);
> > + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
> > trace_user_setup_frame(env, frame_addr);
> >
> > - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
> > + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
> > + if (!frame) {
> > goto give_sigsegv;
> > + }
> > + fpstate = (void *)frame + (fpstate_addr - frame_addr);
> >
> > __put_user(sig, &frame->sig);
> >
> > - setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
> > - frame_addr + offsetof(struct sigframe, fpstate));
> > + setup_sigcontext(&frame->sc, fpstate, env, set->sig[0], fpstate_addr);
> >
> > - for(i = 1; i < TARGET_NSIG_WORDS; i++) {
> > + for (i = 1; i < TARGET_NSIG_WORDS; i++) {
> > __put_user(set->sig[i], &frame->extramask[i - 1]);
> > }
> >
> > - /* Set up to return from userspace. If provided, use a stub
> > - already in userspace. */
> > + /*
> > + * Set up to return from userspace.
> > + * If provided, use a stub already in userspace.
> > + */
> > if (ka->sa_flags & TARGET_SA_RESTORER) {
> > __put_user(ka->sa_restorer, &frame->pretcode);
> > } else {
> > @@ -443,11 +445,10 @@ void setup_frame(int sig, struct target_sigaction *ka,
> > cpu_x86_load_seg(env, R_CS, __USER_CS);
> > env->eflags &= ~TF_MASK;
> >
> > - unlock_user_struct(frame, frame_addr, 1);
> > -
> > + unlock_user(frame, frame_addr, frame_size);
> > return;
> >
> > -give_sigsegv:
> > + give_sigsegv:
> > force_sigsegv(sig);
> > }
> > #endif
> > @@ -458,17 +459,24 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> > target_sigset_t *set, CPUX86State *env)
> > {
> > abi_ulong frame_addr;
> > + abi_ulong fpstate_addr;
> > + size_t frame_size;
> > #ifndef TARGET_X86_64
> > abi_ulong addr;
> > #endif
> > struct rt_sigframe *frame;
> > + struct target_fpstate *fpstate;
> > int i;
> >
> > - frame_addr = get_sigframe(ka, env, TARGET_RT_SIGFRAME_FXSAVE_OFFSET);
> > + frame_size = sizeof(struct rt_sigframe);
> > + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
> > trace_user_setup_rt_frame(env, frame_addr);
> >
> > - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
> > + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
> > + if (!frame) {
> > goto give_sigsegv;
> > + }
> > + fpstate = (void *)frame + (fpstate_addr - frame_addr);
> >
> > /* These fields are only in rt_sigframe on 32 bit */
> > #ifndef TARGET_X86_64
> > @@ -490,10 +498,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> > }
> > __put_user(0, &frame->uc.tuc_link);
> > target_save_altstack(&frame->uc.tuc_stack, env);
> > - setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
> > - set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
> > + setup_sigcontext(&frame->uc.tuc_mcontext, fpstate, env,
> > + set->sig[0], fpstate_addr);
> >
> > - for(i = 0; i < TARGET_NSIG_WORDS; i++) {
> > + for (i = 0; i < TARGET_NSIG_WORDS; i++) {
> > __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
> > }
> >
> > @@ -533,15 +541,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> > cpu_x86_load_seg(env, R_SS, __USER_DS);
> > env->eflags &= ~TF_MASK;
> >
> > - unlock_user_struct(frame, frame_addr, 1);
> > -
> > + unlock_user(frame, frame_addr, frame_size);
> > return;
> >
> > -give_sigsegv:
> > + give_sigsegv:
> > force_sigsegv(sig);
> > }
> >
> > -static int xrstor_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
> > +static int xrstor_sigcontext(CPUX86State *env,
> > + struct target_fpstate_fxsave *fxsave,
> > abi_ulong fxsave_addr)
> > {
> > if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
> > diff --git a/tests/tcg/x86_64/sigstack.c b/tests/tcg/x86_64/sigstack.c
> > new file mode 100644
> > index 0000000000..06cb847569
> > --- /dev/null
> > +++ b/tests/tcg/x86_64/sigstack.c
> > @@ -0,0 +1,33 @@
> > +#include <stdlib.h>
> > +#include <assert.h>
> > +#include <signal.h>
> > +#include <stdint.h>
> > +
> > +void __attribute__((noinline)) bar(void)
> > +{
> > + exit(EXIT_SUCCESS);
> > +}
> > +
> > +void __attribute__((noinline, ms_abi)) foo(void)
> > +{
> > + /*
> > + * With ms_abi, there are call-saved xmm registers, which are forced
> > + * to the stack around the call to sysv_abi bar(). If the signal
> > + * stack frame is not properly aligned, movaps will raise #GP.
> > + */
> > + bar();
> > +}
> > +
> > +void sighandler(int num)
> > +{
> > + void* sp = __builtin_dwarf_cfa();
> > + assert((uintptr_t)sp % 16 == 0);
> > + foo();
> > +}
> > +
> > +int main(void)
> > +{
> > + signal(SIGUSR1, sighandler);
> > + raise(SIGUSR1);
> > + abort();
> > +}
> > diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
> > index e64aab1b81..d961599f64 100644
> > --- a/tests/tcg/x86_64/Makefile.target
> > +++ b/tests/tcg/x86_64/Makefile.target
> > @@ -13,6 +13,7 @@ X86_64_TESTS += vsyscall
> > X86_64_TESTS += noexec
> > X86_64_TESTS += cmpxchg
> > X86_64_TESTS += adox
> > +X86_64_TESTS += sigstack
> > TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
> > else
> > TESTS=$(MULTIARCH_TESTS)
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-05-26 2:56 ` fanwj--- via
@ 2023-05-26 14:27 ` Richard Henderson
0 siblings, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2023-05-26 14:27 UTC (permalink / raw)
To: fanwj; +Cc: qemu-devel, laurent
On 5/25/23 19:56, fanwj@mail.ustc.edu.cn wrote:
>
> "The beginning of the structure, with pretaddr, should be just below 16-byte alignment."
>
> It is incorrect! The beginning of the structure, with pretaddr not aligned as 16-byte!
> On x86-64, It aligned as (16n - sizeof(void*)) because of instruction "call" !
Exactly: 16n - sizeof(void*) is why I mean by "just below 16-byte alignment".
Which is exactly what I have done...
>>> + esp = esp - *frame_size + sizeof(abi_ulong);
>>> + esp = ROUND_DOWN(esp, 16) - sizeof(abi_ulong);
... here.
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-05-24 5:46 [PATCH] linux-user/i386: Properly align signal frame Richard Henderson
2023-05-24 5:50 ` Richard Henderson
@ 2023-06-20 13:26 ` Richard Henderson
2023-06-30 17:53 ` Richard Henderson
2023-10-26 6:35 ` Michael Tokarev
2 siblings, 1 reply; 11+ messages in thread
From: Richard Henderson @ 2023-06-20 13:26 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent
Ping.
On 5/24/23 07:46, Richard Henderson wrote:
> The beginning of the structure, with pretaddr, should be just below
> 16-byte alignment. Disconnect fpstate from sigframe, just like the
> kernel does.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> linux-user/i386/signal.c | 104 +++++++++++++++++--------------
> tests/tcg/x86_64/sigstack.c | 33 ++++++++++
> tests/tcg/x86_64/Makefile.target | 1 +
> 3 files changed, 90 insertions(+), 48 deletions(-)
> create mode 100644 tests/tcg/x86_64/sigstack.c
>
> diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
> index 60fa07d6f9..c49467de78 100644
> --- a/linux-user/i386/signal.c
> +++ b/linux-user/i386/signal.c
> @@ -191,16 +191,7 @@ struct sigframe {
> struct target_fpstate fpstate_unused;
> abi_ulong extramask[TARGET_NSIG_WORDS-1];
> char retcode[8];
> -
> - /*
> - * This field will be 16-byte aligned in memory. Applying QEMU_ALIGNED
> - * to it ensures that the base of the frame has an appropriate alignment
> - * too.
> - */
> - struct target_fpstate fpstate QEMU_ALIGNED(8);
> };
> -#define TARGET_SIGFRAME_FXSAVE_OFFSET ( \
> - offsetof(struct sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
>
> struct rt_sigframe {
> abi_ulong pretcode;
> @@ -210,27 +201,21 @@ struct rt_sigframe {
> struct target_siginfo info;
> struct target_ucontext uc;
> char retcode[8];
> - struct target_fpstate fpstate QEMU_ALIGNED(8);
> };
> -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
> - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
> #else
> -
> struct rt_sigframe {
> abi_ulong pretcode;
> struct target_ucontext uc;
> struct target_siginfo info;
> - struct target_fpstate fpstate QEMU_ALIGNED(16);
> };
> -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
> - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
> #endif
>
> /*
> * Set up a signal frame.
> */
>
> -static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
> +static void xsave_sigcontext(CPUX86State *env,
> + struct target_fpstate_fxsave *fxsave,
> abi_ulong fxsave_addr)
> {
> if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> @@ -266,8 +251,9 @@ static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxs
> }
>
> static void setup_sigcontext(struct target_sigcontext *sc,
> - struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
> - abi_ulong fpstate_addr)
> + struct target_fpstate *fpstate,
> + CPUX86State *env, abi_ulong mask,
> + abi_ulong fpstate_addr)
> {
> CPUState *cs = env_cpu(env);
> #ifndef TARGET_X86_64
> @@ -347,10 +333,11 @@ static void setup_sigcontext(struct target_sigcontext *sc,
> * Determine which stack to use..
> */
>
> -static inline abi_ulong
> -get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset)
> +static abi_ulong get_sigframe(struct target_sigaction *ka, CPUX86State *env,
> + size_t *frame_size, abi_ulong *fpsave_addr)
> {
> - unsigned long esp;
> + abi_ulong esp, orig;
> + size_t fpsave_size;
>
> /* Default to using normal stack */
> esp = get_sp_from_cpustate(env);
> @@ -371,16 +358,23 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset
> }
> #endif
> }
> + orig = esp;
>
> - if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
> - return (esp - (fxsave_offset + TARGET_FXSAVE_SIZE)) & -8ul;
> - } else if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> - return ((esp - TARGET_FXSAVE_SIZE) & -16ul) - fxsave_offset;
> + if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
> + fpsave_size = TARGET_FXSAVE_SIZE;
> + esp = ROUND_DOWN(esp - fpsave_size, 16);
> } else {
> - size_t xstate_size =
> - xsave_area_size(env->xcr0, false) + TARGET_FP_XSTATE_MAGIC2_SIZE;
> - return ((esp - xstate_size) & -64ul) - fxsave_offset;
> + fpsave_size = xsave_area_size(env->xcr0, false)
> + + TARGET_FP_XSTATE_MAGIC2_SIZE;
> + esp = ROUND_DOWN(esp - fpsave_size, 64);
> }
> + *fpsave_addr = esp;
> +
> + esp = esp - *frame_size + sizeof(abi_ulong);
> + esp = ROUND_DOWN(esp, 16) - sizeof(abi_ulong);
> +
> + *frame_size = orig - esp;
> + return esp;
> }
>
> #ifndef TARGET_X86_64
> @@ -405,26 +399,34 @@ void setup_frame(int sig, struct target_sigaction *ka,
> target_sigset_t *set, CPUX86State *env)
> {
> abi_ulong frame_addr;
> + abi_ulong fpstate_addr;
> + size_t frame_size;
> struct sigframe *frame;
> + struct target_fpstate *fpstate;
> int i;
>
> - frame_addr = get_sigframe(ka, env, TARGET_SIGFRAME_FXSAVE_OFFSET);
> + frame_size = sizeof(struct sigframe);
> + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
> trace_user_setup_frame(env, frame_addr);
>
> - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
> + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
> + if (!frame) {
> goto give_sigsegv;
> + }
> + fpstate = (void *)frame + (fpstate_addr - frame_addr);
>
> __put_user(sig, &frame->sig);
>
> - setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
> - frame_addr + offsetof(struct sigframe, fpstate));
> + setup_sigcontext(&frame->sc, fpstate, env, set->sig[0], fpstate_addr);
>
> - for(i = 1; i < TARGET_NSIG_WORDS; i++) {
> + for (i = 1; i < TARGET_NSIG_WORDS; i++) {
> __put_user(set->sig[i], &frame->extramask[i - 1]);
> }
>
> - /* Set up to return from userspace. If provided, use a stub
> - already in userspace. */
> + /*
> + * Set up to return from userspace.
> + * If provided, use a stub already in userspace.
> + */
> if (ka->sa_flags & TARGET_SA_RESTORER) {
> __put_user(ka->sa_restorer, &frame->pretcode);
> } else {
> @@ -443,11 +445,10 @@ void setup_frame(int sig, struct target_sigaction *ka,
> cpu_x86_load_seg(env, R_CS, __USER_CS);
> env->eflags &= ~TF_MASK;
>
> - unlock_user_struct(frame, frame_addr, 1);
> -
> + unlock_user(frame, frame_addr, frame_size);
> return;
>
> -give_sigsegv:
> + give_sigsegv:
> force_sigsegv(sig);
> }
> #endif
> @@ -458,17 +459,24 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> target_sigset_t *set, CPUX86State *env)
> {
> abi_ulong frame_addr;
> + abi_ulong fpstate_addr;
> + size_t frame_size;
> #ifndef TARGET_X86_64
> abi_ulong addr;
> #endif
> struct rt_sigframe *frame;
> + struct target_fpstate *fpstate;
> int i;
>
> - frame_addr = get_sigframe(ka, env, TARGET_RT_SIGFRAME_FXSAVE_OFFSET);
> + frame_size = sizeof(struct rt_sigframe);
> + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
> trace_user_setup_rt_frame(env, frame_addr);
>
> - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
> + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
> + if (!frame) {
> goto give_sigsegv;
> + }
> + fpstate = (void *)frame + (fpstate_addr - frame_addr);
>
> /* These fields are only in rt_sigframe on 32 bit */
> #ifndef TARGET_X86_64
> @@ -490,10 +498,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> }
> __put_user(0, &frame->uc.tuc_link);
> target_save_altstack(&frame->uc.tuc_stack, env);
> - setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
> - set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
> + setup_sigcontext(&frame->uc.tuc_mcontext, fpstate, env,
> + set->sig[0], fpstate_addr);
>
> - for(i = 0; i < TARGET_NSIG_WORDS; i++) {
> + for (i = 0; i < TARGET_NSIG_WORDS; i++) {
> __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
> }
>
> @@ -533,15 +541,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
> cpu_x86_load_seg(env, R_SS, __USER_DS);
> env->eflags &= ~TF_MASK;
>
> - unlock_user_struct(frame, frame_addr, 1);
> -
> + unlock_user(frame, frame_addr, frame_size);
> return;
>
> -give_sigsegv:
> + give_sigsegv:
> force_sigsegv(sig);
> }
>
> -static int xrstor_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
> +static int xrstor_sigcontext(CPUX86State *env,
> + struct target_fpstate_fxsave *fxsave,
> abi_ulong fxsave_addr)
> {
> if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
> diff --git a/tests/tcg/x86_64/sigstack.c b/tests/tcg/x86_64/sigstack.c
> new file mode 100644
> index 0000000000..06cb847569
> --- /dev/null
> +++ b/tests/tcg/x86_64/sigstack.c
> @@ -0,0 +1,33 @@
> +#include <stdlib.h>
> +#include <assert.h>
> +#include <signal.h>
> +#include <stdint.h>
> +
> +void __attribute__((noinline)) bar(void)
> +{
> + exit(EXIT_SUCCESS);
> +}
> +
> +void __attribute__((noinline, ms_abi)) foo(void)
> +{
> + /*
> + * With ms_abi, there are call-saved xmm registers, which are forced
> + * to the stack around the call to sysv_abi bar(). If the signal
> + * stack frame is not properly aligned, movaps will raise #GP.
> + */
> + bar();
> +}
> +
> +void sighandler(int num)
> +{
> + void* sp = __builtin_dwarf_cfa();
> + assert((uintptr_t)sp % 16 == 0);
> + foo();
> +}
> +
> +int main(void)
> +{
> + signal(SIGUSR1, sighandler);
> + raise(SIGUSR1);
> + abort();
> +}
> diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
> index e64aab1b81..d961599f64 100644
> --- a/tests/tcg/x86_64/Makefile.target
> +++ b/tests/tcg/x86_64/Makefile.target
> @@ -13,6 +13,7 @@ X86_64_TESTS += vsyscall
> X86_64_TESTS += noexec
> X86_64_TESTS += cmpxchg
> X86_64_TESTS += adox
> +X86_64_TESTS += sigstack
> TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
> else
> TESTS=$(MULTIARCH_TESTS)
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-06-20 13:26 ` Richard Henderson
@ 2023-06-30 17:53 ` Richard Henderson
2023-07-02 18:41 ` Michael Tokarev
2023-08-05 21:56 ` Michael Tokarev
0 siblings, 2 replies; 11+ messages in thread
From: Richard Henderson @ 2023-06-30 17:53 UTC (permalink / raw)
To: qemu-devel; +Cc: laurent
Ping 2.
On 6/20/23 15:26, Richard Henderson wrote:
> Ping.
>
> On 5/24/23 07:46, Richard Henderson wrote:
>> The beginning of the structure, with pretaddr, should be just below
>> 16-byte alignment. Disconnect fpstate from sigframe, just like the
>> kernel does.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>> linux-user/i386/signal.c | 104 +++++++++++++++++--------------
>> tests/tcg/x86_64/sigstack.c | 33 ++++++++++
>> tests/tcg/x86_64/Makefile.target | 1 +
>> 3 files changed, 90 insertions(+), 48 deletions(-)
>> create mode 100644 tests/tcg/x86_64/sigstack.c
>>
>> diff --git a/linux-user/i386/signal.c b/linux-user/i386/signal.c
>> index 60fa07d6f9..c49467de78 100644
>> --- a/linux-user/i386/signal.c
>> +++ b/linux-user/i386/signal.c
>> @@ -191,16 +191,7 @@ struct sigframe {
>> struct target_fpstate fpstate_unused;
>> abi_ulong extramask[TARGET_NSIG_WORDS-1];
>> char retcode[8];
>> -
>> - /*
>> - * This field will be 16-byte aligned in memory. Applying QEMU_ALIGNED
>> - * to it ensures that the base of the frame has an appropriate alignment
>> - * too.
>> - */
>> - struct target_fpstate fpstate QEMU_ALIGNED(8);
>> };
>> -#define TARGET_SIGFRAME_FXSAVE_OFFSET ( \
>> - offsetof(struct sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
>> struct rt_sigframe {
>> abi_ulong pretcode;
>> @@ -210,27 +201,21 @@ struct rt_sigframe {
>> struct target_siginfo info;
>> struct target_ucontext uc;
>> char retcode[8];
>> - struct target_fpstate fpstate QEMU_ALIGNED(8);
>> };
>> -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
>> - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
>> #else
>> -
>> struct rt_sigframe {
>> abi_ulong pretcode;
>> struct target_ucontext uc;
>> struct target_siginfo info;
>> - struct target_fpstate fpstate QEMU_ALIGNED(16);
>> };
>> -#define TARGET_RT_SIGFRAME_FXSAVE_OFFSET ( \
>> - offsetof(struct rt_sigframe, fpstate) + TARGET_FPSTATE_FXSAVE_OFFSET)
>> #endif
>> /*
>> * Set up a signal frame.
>> */
>> -static void xsave_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
>> +static void xsave_sigcontext(CPUX86State *env,
>> + struct target_fpstate_fxsave *fxsave,
>> abi_ulong fxsave_addr)
>> {
>> if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
>> @@ -266,8 +251,9 @@ static void xsave_sigcontext(CPUX86State *env, struct
>> target_fpstate_fxsave *fxs
>> }
>> static void setup_sigcontext(struct target_sigcontext *sc,
>> - struct target_fpstate *fpstate, CPUX86State *env, abi_ulong mask,
>> - abi_ulong fpstate_addr)
>> + struct target_fpstate *fpstate,
>> + CPUX86State *env, abi_ulong mask,
>> + abi_ulong fpstate_addr)
>> {
>> CPUState *cs = env_cpu(env);
>> #ifndef TARGET_X86_64
>> @@ -347,10 +333,11 @@ static void setup_sigcontext(struct target_sigcontext *sc,
>> * Determine which stack to use..
>> */
>> -static inline abi_ulong
>> -get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t fxsave_offset)
>> +static abi_ulong get_sigframe(struct target_sigaction *ka, CPUX86State *env,
>> + size_t *frame_size, abi_ulong *fpsave_addr)
>> {
>> - unsigned long esp;
>> + abi_ulong esp, orig;
>> + size_t fpsave_size;
>> /* Default to using normal stack */
>> esp = get_sp_from_cpustate(env);
>> @@ -371,16 +358,23 @@ get_sigframe(struct target_sigaction *ka, CPUX86State *env, size_t
>> fxsave_offset
>> }
>> #endif
>> }
>> + orig = esp;
>> - if (!(env->features[FEAT_1_EDX] & CPUID_FXSR)) {
>> - return (esp - (fxsave_offset + TARGET_FXSAVE_SIZE)) & -8ul;
>> - } else if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
>> - return ((esp - TARGET_FXSAVE_SIZE) & -16ul) - fxsave_offset;
>> + if (!(env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE)) {
>> + fpsave_size = TARGET_FXSAVE_SIZE;
>> + esp = ROUND_DOWN(esp - fpsave_size, 16);
>> } else {
>> - size_t xstate_size =
>> - xsave_area_size(env->xcr0, false) + TARGET_FP_XSTATE_MAGIC2_SIZE;
>> - return ((esp - xstate_size) & -64ul) - fxsave_offset;
>> + fpsave_size = xsave_area_size(env->xcr0, false)
>> + + TARGET_FP_XSTATE_MAGIC2_SIZE;
>> + esp = ROUND_DOWN(esp - fpsave_size, 64);
>> }
>> + *fpsave_addr = esp;
>> +
>> + esp = esp - *frame_size + sizeof(abi_ulong);
>> + esp = ROUND_DOWN(esp, 16) - sizeof(abi_ulong);
>> +
>> + *frame_size = orig - esp;
>> + return esp;
>> }
>> #ifndef TARGET_X86_64
>> @@ -405,26 +399,34 @@ void setup_frame(int sig, struct target_sigaction *ka,
>> target_sigset_t *set, CPUX86State *env)
>> {
>> abi_ulong frame_addr;
>> + abi_ulong fpstate_addr;
>> + size_t frame_size;
>> struct sigframe *frame;
>> + struct target_fpstate *fpstate;
>> int i;
>> - frame_addr = get_sigframe(ka, env, TARGET_SIGFRAME_FXSAVE_OFFSET);
>> + frame_size = sizeof(struct sigframe);
>> + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
>> trace_user_setup_frame(env, frame_addr);
>> - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
>> + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
>> + if (!frame) {
>> goto give_sigsegv;
>> + }
>> + fpstate = (void *)frame + (fpstate_addr - frame_addr);
>> __put_user(sig, &frame->sig);
>> - setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0],
>> - frame_addr + offsetof(struct sigframe, fpstate));
>> + setup_sigcontext(&frame->sc, fpstate, env, set->sig[0], fpstate_addr);
>> - for(i = 1; i < TARGET_NSIG_WORDS; i++) {
>> + for (i = 1; i < TARGET_NSIG_WORDS; i++) {
>> __put_user(set->sig[i], &frame->extramask[i - 1]);
>> }
>> - /* Set up to return from userspace. If provided, use a stub
>> - already in userspace. */
>> + /*
>> + * Set up to return from userspace.
>> + * If provided, use a stub already in userspace.
>> + */
>> if (ka->sa_flags & TARGET_SA_RESTORER) {
>> __put_user(ka->sa_restorer, &frame->pretcode);
>> } else {
>> @@ -443,11 +445,10 @@ void setup_frame(int sig, struct target_sigaction *ka,
>> cpu_x86_load_seg(env, R_CS, __USER_CS);
>> env->eflags &= ~TF_MASK;
>> - unlock_user_struct(frame, frame_addr, 1);
>> -
>> + unlock_user(frame, frame_addr, frame_size);
>> return;
>> -give_sigsegv:
>> + give_sigsegv:
>> force_sigsegv(sig);
>> }
>> #endif
>> @@ -458,17 +459,24 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
>> target_sigset_t *set, CPUX86State *env)
>> {
>> abi_ulong frame_addr;
>> + abi_ulong fpstate_addr;
>> + size_t frame_size;
>> #ifndef TARGET_X86_64
>> abi_ulong addr;
>> #endif
>> struct rt_sigframe *frame;
>> + struct target_fpstate *fpstate;
>> int i;
>> - frame_addr = get_sigframe(ka, env, TARGET_RT_SIGFRAME_FXSAVE_OFFSET);
>> + frame_size = sizeof(struct rt_sigframe);
>> + frame_addr = get_sigframe(ka, env, &frame_size, &fpstate_addr);
>> trace_user_setup_rt_frame(env, frame_addr);
>> - if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0))
>> + frame = lock_user(VERIFY_WRITE, frame_addr, frame_size, false);
>> + if (!frame) {
>> goto give_sigsegv;
>> + }
>> + fpstate = (void *)frame + (fpstate_addr - frame_addr);
>> /* These fields are only in rt_sigframe on 32 bit */
>> #ifndef TARGET_X86_64
>> @@ -490,10 +498,10 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
>> }
>> __put_user(0, &frame->uc.tuc_link);
>> target_save_altstack(&frame->uc.tuc_stack, env);
>> - setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate, env,
>> - set->sig[0], frame_addr + offsetof(struct rt_sigframe, fpstate));
>> + setup_sigcontext(&frame->uc.tuc_mcontext, fpstate, env,
>> + set->sig[0], fpstate_addr);
>> - for(i = 0; i < TARGET_NSIG_WORDS; i++) {
>> + for (i = 0; i < TARGET_NSIG_WORDS; i++) {
>> __put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]);
>> }
>> @@ -533,15 +541,15 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
>> cpu_x86_load_seg(env, R_SS, __USER_DS);
>> env->eflags &= ~TF_MASK;
>> - unlock_user_struct(frame, frame_addr, 1);
>> -
>> + unlock_user(frame, frame_addr, frame_size);
>> return;
>> -give_sigsegv:
>> + give_sigsegv:
>> force_sigsegv(sig);
>> }
>> -static int xrstor_sigcontext(CPUX86State *env, struct target_fpstate_fxsave *fxsave,
>> +static int xrstor_sigcontext(CPUX86State *env,
>> + struct target_fpstate_fxsave *fxsave,
>> abi_ulong fxsave_addr)
>> {
>> if (env->features[FEAT_1_ECX] & CPUID_EXT_XSAVE) {
>> diff --git a/tests/tcg/x86_64/sigstack.c b/tests/tcg/x86_64/sigstack.c
>> new file mode 100644
>> index 0000000000..06cb847569
>> --- /dev/null
>> +++ b/tests/tcg/x86_64/sigstack.c
>> @@ -0,0 +1,33 @@
>> +#include <stdlib.h>
>> +#include <assert.h>
>> +#include <signal.h>
>> +#include <stdint.h>
>> +
>> +void __attribute__((noinline)) bar(void)
>> +{
>> + exit(EXIT_SUCCESS);
>> +}
>> +
>> +void __attribute__((noinline, ms_abi)) foo(void)
>> +{
>> + /*
>> + * With ms_abi, there are call-saved xmm registers, which are forced
>> + * to the stack around the call to sysv_abi bar(). If the signal
>> + * stack frame is not properly aligned, movaps will raise #GP.
>> + */
>> + bar();
>> +}
>> +
>> +void sighandler(int num)
>> +{
>> + void* sp = __builtin_dwarf_cfa();
>> + assert((uintptr_t)sp % 16 == 0);
>> + foo();
>> +}
>> +
>> +int main(void)
>> +{
>> + signal(SIGUSR1, sighandler);
>> + raise(SIGUSR1);
>> + abort();
>> +}
>> diff --git a/tests/tcg/x86_64/Makefile.target b/tests/tcg/x86_64/Makefile.target
>> index e64aab1b81..d961599f64 100644
>> --- a/tests/tcg/x86_64/Makefile.target
>> +++ b/tests/tcg/x86_64/Makefile.target
>> @@ -13,6 +13,7 @@ X86_64_TESTS += vsyscall
>> X86_64_TESTS += noexec
>> X86_64_TESTS += cmpxchg
>> X86_64_TESTS += adox
>> +X86_64_TESTS += sigstack
>> TESTS=$(MULTIARCH_TESTS) $(X86_64_TESTS) test-x86_64
>> else
>> TESTS=$(MULTIARCH_TESTS)
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-06-30 17:53 ` Richard Henderson
@ 2023-07-02 18:41 ` Michael Tokarev
2023-08-05 21:56 ` Michael Tokarev
1 sibling, 0 replies; 11+ messages in thread
From: Michael Tokarev @ 2023-07-02 18:41 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: laurent
30.06.2023 20:53, Richard Henderson wrote:
> Ping 2.
>
> On 6/20/23 15:26, Richard Henderson wrote:
>> Ping.
>>
>> On 5/24/23 07:46, Richard Henderson wrote:
>>> The beginning of the structure, with pretaddr, should be just below
>>> 16-byte alignment. Disconnect fpstate from sigframe, just like the
>>> kernel does.
This smells like a -stable material too (I tagged it "stable" in my inbox
a month ago already), as it is fixing real bug which people are hitting.
/mjt
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-06-30 17:53 ` Richard Henderson
2023-07-02 18:41 ` Michael Tokarev
@ 2023-08-05 21:56 ` Michael Tokarev
2023-08-06 2:29 ` Richard Henderson
1 sibling, 1 reply; 11+ messages in thread
From: Michael Tokarev @ 2023-08-05 21:56 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: laurent
30.06.2023 20:53, Richard Henderson wrote:
> Ping 2.
>
> On 6/20/23 15:26, Richard Henderson wrote:
>> Ping.
>>
>> On 5/24/23 07:46, Richard Henderson wrote:
>>> The beginning of the structure, with pretaddr, should be just below
>>> 16-byte alignment. Disconnect fpstate from sigframe, just like the
>>> kernel does.
Whom we're pinging here? :)
Ping 3 ;)
(This is https://gitlab.com/qemu-project/qemu/-/issues/1648 and is a
-stable material too, it seems)
/mjt
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-08-05 21:56 ` Michael Tokarev
@ 2023-08-06 2:29 ` Richard Henderson
0 siblings, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2023-08-06 2:29 UTC (permalink / raw)
To: Michael Tokarev, qemu-devel; +Cc: laurent
On 8/5/23 14:56, Michael Tokarev wrote:
> 30.06.2023 20:53, Richard Henderson wrote:
>> Ping 2.
>>
>> On 6/20/23 15:26, Richard Henderson wrote:
>>> Ping.
>>>
>>> On 5/24/23 07:46, Richard Henderson wrote:
>>>> The beginning of the structure, with pretaddr, should be just below
>>>> 16-byte alignment. Disconnect fpstate from sigframe, just like the
>>>> kernel does.
>
> Whom we're pinging here? :)
> Ping 3 ;)
>
> (This is https://gitlab.com/qemu-project/qemu/-/issues/1648 and is a
> -stable material too, it seems)
In the month since, I've discovered that fpstate needs even more work.
This is extremely fiddly stuff, and we need a complete rewrite to match the kernel and the
required alignments.
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-05-24 5:46 [PATCH] linux-user/i386: Properly align signal frame Richard Henderson
2023-05-24 5:50 ` Richard Henderson
2023-06-20 13:26 ` Richard Henderson
@ 2023-10-26 6:35 ` Michael Tokarev
2023-10-27 4:07 ` Richard Henderson
2 siblings, 1 reply; 11+ messages in thread
From: Michael Tokarev @ 2023-10-26 6:35 UTC (permalink / raw)
To: Richard Henderson, qemu-devel; +Cc: fanwj, laurent
24.05.2023 08:46, Richard Henderson:
> The beginning of the structure, with pretaddr, should be just below
> 16-byte alignment. Disconnect fpstate from sigframe, just like the
> kernel does.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1648
Ping? Has this been forgotten? It's been 5 months already..
/mjt
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] linux-user/i386: Properly align signal frame
2023-10-26 6:35 ` Michael Tokarev
@ 2023-10-27 4:07 ` Richard Henderson
0 siblings, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2023-10-27 4:07 UTC (permalink / raw)
To: Michael Tokarev, qemu-devel; +Cc: fanwj, laurent
On 10/25/23 23:35, Michael Tokarev wrote:
> 24.05.2023 08:46, Richard Henderson:
>> The beginning of the structure, with pretaddr, should be just below
>> 16-byte alignment. Disconnect fpstate from sigframe, just like the
>> kernel does.
>
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1648
>
> Ping? Has this been forgotten? It's been 5 months already..
I have not returned to this problem yet.
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2023-10-27 4:07 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-24 5:46 [PATCH] linux-user/i386: Properly align signal frame Richard Henderson
2023-05-24 5:50 ` Richard Henderson
2023-05-26 2:56 ` fanwj--- via
2023-05-26 14:27 ` Richard Henderson
2023-06-20 13:26 ` Richard Henderson
2023-06-30 17:53 ` Richard Henderson
2023-07-02 18:41 ` Michael Tokarev
2023-08-05 21:56 ` Michael Tokarev
2023-08-06 2:29 ` Richard Henderson
2023-10-26 6:35 ` Michael Tokarev
2023-10-27 4:07 ` Richard Henderson
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.