[CRIU] [PATCH 2/3] x86/compat: Use do_full_int80() instead of jump to ia32 mode

Dmitry Safonov dima at arista.com
Wed Oct 31 01:35:30 MSK 2018


Kernel will send signal with ABI of *syscall* that made rt_sigacation().
In sigaction_compat_abi():
>        if (in_ia32_syscall())
>                   act->sa.sa_flags |= SA_IA32_ABI;

So, we can omit switching to ia32 mode and just call int80 like in other places.
We still need 32-bit argument for syscall (sig action pointer).

As call32_from_64() switches mode, it's .text should be placed in lower 4Gb,
which was the reason of segfault if linker places criu code above 4Gb.
Oops, my bad.

Fixes: #567

Reported-by: Andrey Vagin <avagin at gmail.com>
Signed-off-by: Dmitry Safonov <dima at arista.com>
---
 criu/arch/x86/call32.S           |  7 +++++++
 criu/arch/x86/sigaction_compat.c | 18 ++++++++++++++----
 2 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/criu/arch/x86/call32.S b/criu/arch/x86/call32.S
index c2ddd9fc2682..8c32c4f7a3d6 100644
--- a/criu/arch/x86/call32.S
+++ b/criu/arch/x86/call32.S
@@ -23,6 +23,13 @@
 /*
  * @rdi: Stack to use
  * @esi: Pointer to function for calling
+ *
+ * Note: .code32 in this function doesn't guarantee that is will
+ *       be place under 4GB by linker.
+ *       Linker script would guarantee that, but it would break
+ *       -fpie address randomization. In the end, the caller is
+ *       responible for placing/checking that the code is
+ *       accessible in 32-bit mode.
  */
 ENTRY(call32_from_64)
 	/* Callee-saving registers due to ABI */
diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c
index 5965ef79fabe..b38ba8011889 100644
--- a/criu/arch/x86/sigaction_compat.c
+++ b/criu/arch/x86/sigaction_compat.c
@@ -29,17 +29,27 @@ extern char restore_rt_sigaction;
 int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act)
 {
 	int ret;
+	struct syscall_args32 arg = {};
+	unsigned long act_stack = (unsigned long)stack32;
+
+	/* To make sure the 32-bit stack was allocated in caller */
+	if (act_stack >= (uint32_t)-1) {
+		pr_err("compat rt_sigaction without 32-bit stack\n");
+		return -1;
+	}
 
 	/*
 	 * To be sure, that sigaction pointer lies under 4G,
 	 * coping it on the bottom of the stack.
 	 */
 	memcpy(stack32, act, sizeof(rt_sigaction_t_compat));
+	arg.nr		= __NR32_rt_sigaction;
+	arg.arg0	= sig;
+	arg.arg1	= (uint32_t)act_stack;			/* act */
+	arg.arg2	= 0;					/* oldact */
+	arg.arg3	= (uint32_t)sizeof(act->rt_sa_mask);	/* sigsetsize */
 
-	asm volatile ("\t movl %%ebx,%%ebx\n" : :"b"(sig));	/* signum */
-	asm volatile ("\t movl %%ecx,%%ecx\n" : :"c"(stack32));	/* act */
-	asm volatile ("\t movl %%edx,%%edx\n" : :"d"(sizeof(act->rt_sa_mask)));
-	call32_from_64(stack32 + PAGE_SIZE, &restore_rt_sigaction);
+	do_full_int80(&arg);
 	asm volatile ("\t movl %%eax,%0\n" : "=r"(ret));
 	return ret;
 }
-- 
2.19.1



More information about the CRIU mailing list