[CRIU] [PATCHv2 28/30] restore/x86: call int80 for compat sigaction restore

Dmitry Safonov dsafonov at virtuozzo.com
Mon Jun 27 11:03:58 PDT 2016


On 06/24/2016 06:08 PM, Dmitry Safonov wrote:
> TMP: fill desc
>
> Signed-off-by: Dmitry Safonov <dsafonov at virtuozzo.com>

Oh, crap - didn't fill the description before sending.
I was completely sure I did and did glance patches, but...
Will resend with filled message in reply to this mail.

> ---
>  criu/arch/aarch64/include/asm/restorer.h |   5 ++
>  criu/arch/arm/include/asm/restorer.h     |   5 ++
>  criu/arch/ppc64/include/asm/restorer.h   |   5 ++
>  criu/arch/x86/Makefile                   |   2 +
>  criu/arch/x86/include/asm/restorer.h     |  12 +++
>  criu/arch/x86/include/asm/types.h        |   7 ++
>  criu/arch/x86/restorer.c                 |  10 +--
>  criu/arch/x86/sigaction_compat.c         |  68 +++++++++++++++
>  criu/arch/x86/sigaction_compat_pie.c     |   1 +
>  criu/cr-restore.c                        | 144 ++++++++++++++++++++++++++-----
>  criu/include/parasite-compat.h           |   9 +-
>  criu/parasite-syscall.c                  |   7 +-
>  criu/pie/Makefile                        |   2 +
>  criu/pie/restorer.c                      |  15 +++-
>  images/sa.proto                          |   1 +
>  15 files changed, 257 insertions(+), 36 deletions(-)
>  create mode 100644 criu/arch/x86/sigaction_compat.c
>  create mode 120000 criu/arch/x86/sigaction_compat_pie.c
>
> diff --git a/criu/arch/aarch64/include/asm/restorer.h b/criu/arch/aarch64/include/asm/restorer.h
> index 19f459a0b08f..80f358c46a42 100644
> --- a/criu/arch/aarch64/include/asm/restorer.h
> +++ b/criu/arch/aarch64/include/asm/restorer.h
> @@ -125,4 +125,9 @@ static inline int ptrace_flush_breakpoints(pid_t pid)
>  	return 0;
>  }
>
> +static inline void *alloc_compat_syscall_stack(void) { return NULL; }
> +static inline void free_compat_syscall_stack(void *stack32) { }
> +static inline int
> +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; }
> +
>  #endif
> diff --git a/criu/arch/arm/include/asm/restorer.h b/criu/arch/arm/include/asm/restorer.h
> index e17a80e7a971..305311799e9a 100644
> --- a/criu/arch/arm/include/asm/restorer.h
> +++ b/criu/arch/arm/include/asm/restorer.h
> @@ -167,4 +167,9 @@ static inline int ptrace_flush_breakpoints(pid_t pid)
>  	return 0;
>  }
>
> +static inline void *alloc_compat_syscall_stack(void) { return NULL; }
> +static inline void free_compat_syscall_stack(void *stack32) { }
> +static inline int
> +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; }
> +
>  #endif
> diff --git a/criu/arch/ppc64/include/asm/restorer.h b/criu/arch/ppc64/include/asm/restorer.h
> index e1c08ef17eeb..e9d171a7b1df 100644
> --- a/criu/arch/ppc64/include/asm/restorer.h
> +++ b/criu/arch/ppc64/include/asm/restorer.h
> @@ -131,4 +131,9 @@ int sigreturn_prep_fpu_frame(struct rt_sigframe *sigframe,
>   */
>  unsigned long sys_shmat(int shmid, const void *shmaddr, int shmflg);
>
> +static inline void *alloc_compat_syscall_stack(void) { return NULL; }
> +static inline void free_compat_syscall_stack(void *stack32) { }
> +static inline int
> +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; }
> +
>  #endif /*__CR_ASM_RESTORER_H__*/
> diff --git a/criu/arch/x86/Makefile b/criu/arch/x86/Makefile
> index 5db577340a7d..d8e8251845bf 100644
> --- a/criu/arch/x86/Makefile
> +++ b/criu/arch/x86/Makefile
> @@ -4,3 +4,5 @@ ccflags-y		+= -iquote $(obj) -iquote $(SRC_DIR) -iquote $(obj)/include -iquote $
>
>  obj-y			+= cpu.o
>  obj-y			+= crtools.o
> +obj-y			+= sigaction_compat.o
> +obj-y			+= call32.o
> diff --git a/criu/arch/x86/include/asm/restorer.h b/criu/arch/x86/include/asm/restorer.h
> index 2ab68bad3d70..65af6cd86405 100644
> --- a/criu/arch/x86/include/asm/restorer.h
> +++ b/criu/arch/x86/include/asm/restorer.h
> @@ -96,8 +96,20 @@ static inline void __always_unused __check_compat_sigset_t(void)
>  {
>  	BUILD_BUG_ON(sizeof(compat_sigset_t) != sizeof(k_rtsigset_t));
>  }
> +
> +#define CONFIG_COMPAT
> +extern void *alloc_compat_syscall_stack(void);
> +extern void free_compat_syscall_stack(void *mem);
> +extern unsigned long call32_from_64(void *stack, void *func);
> +
> +extern int arch_compat_rt_sigaction(void *stack32, int sig,
> +		rt_sigaction_t_compat *act);
>  #else
>  #define rt_sigframe_ia32		rt_sigframe
> +static inline void *alloc_compat_syscall_stack(void) { return NULL; }
> +static inline void free_compat_syscall_stack(void *stack32) { }
> +static inline int
> +arch_compat_rt_sigaction(void *stack, int sig, void *act) { return -1; }
>  #endif
>
>  typedef struct compat_sigaltstack {
> diff --git a/criu/arch/x86/include/asm/types.h b/criu/arch/x86/include/asm/types.h
> index 7e3bb3c71bdb..bb9d3a0c6119 100644
> --- a/criu/arch/x86/include/asm/types.h
> +++ b/criu/arch/x86/include/asm/types.h
> @@ -49,6 +49,13 @@ typedef struct {
>  } rt_sigaction_t;
>
>  typedef struct {
> +	u32	rt_sa_handler;
> +	u32	rt_sa_flags;
> +	u32	rt_sa_restorer;
> +	k_rtsigset_t	rt_sa_mask;
> +} rt_sigaction_t_compat;
> +
> +typedef struct {
>  	unsigned int	entry_number;
>  	unsigned int	base_addr;
>  	unsigned int	limit;
> diff --git a/criu/arch/x86/restorer.c b/criu/arch/x86/restorer.c
> index d45c009e87ce..f16bdcaa5b68 100644
> --- a/criu/arch/x86/restorer.c
> +++ b/criu/arch/x86/restorer.c
> @@ -33,8 +33,6 @@ int restore_nonsigframe_gpregs(UserX86RegsEntry *r)
>  	return 0;
>  }
>
> -extern unsigned long call32_from_64(void *stack, void *func);
> -
>  asm (	"	.pushsection .text				\n"
>  	"	.global restore_set_thread_area			\n"
>  	"	.code32						\n"
> @@ -54,10 +52,8 @@ static int prepare_stack32(void)
>  	if (stack32)
>  		return 0;
>
> -	stack32 = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
> -				MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> -	if (stack32 == MAP_FAILED) {
> -		stack32 = NULL;
> +	stack32 = alloc_compat_syscall_stack();
> +	if (!stack32) {
>  		pr_err("Failed to allocate stack for 32-bit TLS restore\n");
>  		return -1;
>  	}
> @@ -91,5 +87,5 @@ void restore_tls(tls_t *ptls)
>  	}
>
>  	if (stack32)
> -		sys_munmap(stack32, PAGE_SIZE);
> +		free_compat_syscall_stack(stack32);
>  }
> diff --git a/criu/arch/x86/sigaction_compat.c b/criu/arch/x86/sigaction_compat.c
> new file mode 100644
> index 000000000000..ef6d13c9101f
> --- /dev/null
> +++ b/criu/arch/x86/sigaction_compat.c
> @@ -0,0 +1,68 @@
> +#include "asm/restorer.h"
> +#include "asm/fpu.h"
> +#include "asm/string.h"
> +
> +#include <sys/mman.h>
> +
> +#ifdef CR_NOGLIBC
> +# include "syscall.h"
> +#else
> +# define sys_mmap mmap
> +# define sys_munmap munmap
> +# ifndef  __NR32_rt_sigaction
> +#  define  __NR32_rt_sigaction 174
> +# endif
> +#endif
> +#include "log.h"
> +#include "cpu.h"
> +
> +void *alloc_compat_syscall_stack(void)
> +{
> +	void *mem = (void*)sys_mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
> +			MAP_32BIT | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
> +
> +	if (mem == MAP_FAILED)
> +		return 0;
> +	return mem;
> +}
> +
> +void free_compat_syscall_stack(void *mem)
> +{
> +	sys_munmap(mem, PAGE_SIZE);
> +}
> +
> +asm (	"	.pushsection .text				\n"
> +	"	.global restore_rt_sigaction			\n"
> +	"	.code32						\n"
> +	"restore_rt_sigaction:					\n"
> +	"	mov %edx, %esi					\n"
> +	"	mov $0, %edx					\n"
> +	"	movl $"__stringify(__NR32_rt_sigaction)",%eax	\n"
> +	"	int $0x80					\n"
> +	"	ret						\n"
> +	"	.popsection					\n"
> +	"	.code64");
> +extern char restore_rt_sigaction;
> +
> +/*
> + * Call raw rt_sigaction syscall through int80 - so the ABI kernel choses
> + * to deliver this signal would be i386.
> + */
> +int arch_compat_rt_sigaction(void *stack32, int sig, rt_sigaction_t_compat *act)
> +{
> +	int ret;
> +
> +	/*
> +	 * To be sure, that sigaction pointer lies under 4G,
> +	 * coping it on the bottom of the stack.
> +	 */
> +	builtin_memcpy(stack32, act, sizeof(rt_sigaction_t_compat));
> +
> +	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);
> +	asm volatile ("\t movl %%eax,%0\n" : "=r"(ret));
> +	return ret;
> +}
> +
> diff --git a/criu/arch/x86/sigaction_compat_pie.c b/criu/arch/x86/sigaction_compat_pie.c
> new file mode 120000
> index 000000000000..009ac3a87e71
> --- /dev/null
> +++ b/criu/arch/x86/sigaction_compat_pie.c
> @@ -0,0 +1 @@
> +sigaction_compat.c
> \ No newline at end of file
> diff --git a/criu/cr-restore.c b/criu/cr-restore.c
> index 8b21d27aa2ed..a8071ce62c83 100644
> --- a/criu/cr-restore.c
> +++ b/criu/cr-restore.c
> @@ -276,7 +276,15 @@ err:
>  }
>
>  static rt_sigaction_t sigchld_act;
> +/*
> + * If parent's sigaction has blocked SIGKILL (which is non-sence),
> + * this parent action is non-valid and shouldn't be inherited.
> + * Used to mark parent_act* no more valid.
> + */
>  static rt_sigaction_t parent_act[SIGMAX];
> +#ifdef CONFIG_COMPAT
> +static rt_sigaction_t_compat parent_act_compat[SIGMAX];
> +#endif
>
>  static bool sa_inherited(int sig, rt_sigaction_t *sa)
>  {
> @@ -288,6 +296,10 @@ static bool sa_inherited(int sig, rt_sigaction_t *sa)
>
>  	pa = &parent_act[sig];
>
> +	/* Omitting non-valid sigaction */
> +	if (pa->rt_sa_mask.sig[0] & (1 << SIGKILL))
> +		return false;
> +
>  	for (i = 0; i < _KNSIG_WORDS; i++)
>  		if (pa->rt_sa_mask.sig[i] != sa->rt_sa_mask.sig[i])
>  			return false;
> @@ -297,26 +309,10 @@ static bool sa_inherited(int sig, rt_sigaction_t *sa)
>  		pa->rt_sa_restorer == sa->rt_sa_restorer;
>  }
>
> -/* Returns number of restored signals, -1 or negative errno on fail */
> -static int restore_one_sigaction(int sig, struct cr_img *img, int pid)
> +static int restore_native_sigaction(int sig, SaEntry *e)
>  {
>  	rt_sigaction_t act;
> -	SaEntry *e;
> -	int ret = 0;
> -
> -	BUG_ON(sig == SIGKILL || sig == SIGSTOP);
> -
> -	ret = pb_read_one_eof(img, &e, PB_SIGACT);
> -	if (ret == 0) {
> -		if (sig != SIGMAX_OLD + 1) { /* backward compatibility */
> -			pr_err("Unexpected EOF %d\n", sig);
> -			return -1;
> -		}
> -		pr_warn("This format of sigacts-%d.img is deprecated\n", pid);
> -		return -1;
> -	}
> -	if (ret < 0)
> -		return ret;
> +	int ret;
>
>  	ASSIGN_TYPED(act.rt_sa_handler, decode_pointer(e->sigaction));
>  	ASSIGN_TYPED(act.rt_sa_flags, e->flags);
> @@ -324,8 +320,6 @@ static int restore_one_sigaction(int sig, struct cr_img *img, int pid)
>  	BUILD_BUG_ON(sizeof(e->mask) != sizeof(act.rt_sa_mask.sig));
>  	memcpy(act.rt_sa_mask.sig, &e->mask, sizeof(act.rt_sa_mask.sig));
>
> -	sa_entry__free_unpacked(e, NULL);
> -
>  	if (sig == SIGCHLD) {
>  		sigchld_act = act;
>  		return 0;
> @@ -345,10 +339,116 @@ static int restore_one_sigaction(int sig, struct cr_img *img, int pid)
>  	}
>
>  	parent_act[sig - 1] = act;
> +	/* Mark SIGKILL blocked which makes compat sigaction non-valid */
> +#ifdef CONFIG_COMPAT
> +	parent_act_compat[sig - 1].rt_sa_mask.sig[0] |= 1 << SIGKILL;
> +#endif
>
>  	return 1;
>  }
>
> +static void *stack32;
> +
> +#ifdef CONFIG_COMPAT
> +static bool sa_compat_inherited(int sig, rt_sigaction_t_compat *sa)
> +{
> +	rt_sigaction_t_compat *pa;
> +	int i;
> +
> +	if (current == root_item)
> +		return false;
> +
> +	pa = &parent_act_compat[sig];
> +
> +	/* Omitting non-valid sigaction */
> +	if (pa->rt_sa_mask.sig[0] & (1 << SIGKILL))
> +		return false;
> +
> +	for (i = 0; i < _KNSIG_WORDS; i++)
> +		if (pa->rt_sa_mask.sig[i] != sa->rt_sa_mask.sig[i])
> +			return false;
> +
> +	return pa->rt_sa_handler == sa->rt_sa_handler &&
> +		pa->rt_sa_flags == sa->rt_sa_flags &&
> +		pa->rt_sa_restorer == sa->rt_sa_restorer;
> +}
> +
> +static int restore_compat_sigaction(int sig, SaEntry *e)
> +{
> +	rt_sigaction_t_compat act;
> +	int ret;
> +
> +	ASSIGN_TYPED(act.rt_sa_handler, (u32)e->sigaction);
> +	ASSIGN_TYPED(act.rt_sa_flags, e->flags);
> +	ASSIGN_TYPED(act.rt_sa_restorer, (u32)e->restorer);
> +	BUILD_BUG_ON(sizeof(e->mask) != sizeof(act.rt_sa_mask.sig));
> +	memcpy(act.rt_sa_mask.sig, &e->mask, sizeof(act.rt_sa_mask.sig));
> +
> +	if (sig == SIGCHLD) {
> +		memcpy(&sigchld_act, &act, sizeof(rt_sigaction_t_compat));
> +		return 0;
> +	}
> +
> +	if (sa_compat_inherited(sig - 1, &act))
> +		return 1;
> +
> +	if (!stack32) {
> +		stack32 = alloc_compat_syscall_stack();
> +		if (!stack32)
> +			return -1;
> +	}
> +
> +	ret = arch_compat_rt_sigaction(stack32, sig, &act);
> +	if (ret < 0) {
> +		pr_err("Can't restore compat sigaction: %d\n", ret);
> +		return ret;
> +	}
> +
> +	parent_act_compat[sig - 1] = act;
> +	/* Mark SIGKILL blocked which makes native sigaction non-valid */
> +	parent_act[sig - 1].rt_sa_mask.sig[0] |= 1 << SIGKILL;
> +
> +	return 1;
> +}
> +#else
> +static int restore_compat_sigaction(int sig, SaEntry *e)
> +{
> +	return -1;
> +}
> +#endif
> +
> +/* Returns number of restored signals, -1 or negative errno on fail */
> +static int restore_one_sigaction(int sig, struct cr_img *img, int pid)
> +{
> +	bool sigaction_is_compat;
> +	SaEntry *e;
> +	int ret = 0;
> +
> +	BUG_ON(sig == SIGKILL || sig == SIGSTOP);
> +
> +	ret = pb_read_one_eof(img, &e, PB_SIGACT);
> +	if (ret == 0) {
> +		if (sig != SIGMAX_OLD + 1) { /* backward compatibility */
> +			pr_err("Unexpected EOF %d\n", sig);
> +			return -1;
> +		}
> +		pr_warn("This format of sigacts-%d.img is deprecated\n", pid);
> +		return -1;
> +	}
> +	if (ret < 0)
> +		return ret;
> +
> +	sigaction_is_compat = e->has_compat_sigaction && e->compat_sigaction;
> +	if (sigaction_is_compat)
> +		ret = restore_compat_sigaction(sig, e);
> +	else
> +		ret = restore_native_sigaction(sig, e);
> +
> +	sa_entry__free_unpacked(e, NULL);
> +
> +	return ret;
> +}
> +
>  static int prepare_sigactions(void)
>  {
>  	int pid = current->pid.virt;
> @@ -380,6 +480,10 @@ static int prepare_sigactions(void)
>  			SIGMAX - 3 /* KILL, STOP and CHLD */);
>
>  	close_image(img);
> +	if (stack32) {
> +		free_compat_syscall_stack(stack32);
> +		stack32 = NULL;
> +	}
>  	return ret;
>  }
>
> diff --git a/criu/include/parasite-compat.h b/criu/include/parasite-compat.h
> index a0629a950558..f17455ecf472 100644
> --- a/criu/include/parasite-compat.h
> +++ b/criu/include/parasite-compat.h
> @@ -7,12 +7,9 @@
>
>  #include "images/core.pb-c.h"
>
> -typedef struct {
> -	u32	rt_sa_handler;
> -	u32	rt_sa_flags;
> -	u32	rt_sa_restorer;
> -	k_rtsigset_t	rt_sa_mask;
> -} rt_sigaction_t_compat;
> +#if !defined(CONFIG_X86_64) && !defined(CONFIG_X86_32)
> +#define rt_sigaction_t_compat rt_sigaction_t
> +#endif
>
>  struct parasite_dump_sa_args_compat {
>  	rt_sigaction_t_compat sas[SIGMAX];
> diff --git a/criu/parasite-syscall.c b/criu/parasite-syscall.c
> index f658dfd37c33..47ac71280953 100644
> --- a/criu/parasite-syscall.c
> +++ b/criu/parasite-syscall.c
> @@ -693,8 +693,9 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_
>  	int ret, sig;
>  	struct cr_img *img;
>  	SaEntry se = SA_ENTRY__INIT;
> +	bool native_task = seized_native(ctl);
>
> -	if (seized_native(ctl))
> +	if (native_task)
>  		args = parasite_args(ctl, struct parasite_dump_sa_args);
>  	else
>  		args_c = parasite_args(ctl, struct parasite_dump_sa_args_compat);
> @@ -711,10 +712,12 @@ int parasite_dump_sigacts_seized(struct parasite_ctl *ctl, struct cr_imgset *cr_
>  		if (sig == SIGSTOP || sig == SIGKILL)
>  			continue;
>
> -		if (seized_native(ctl))
> +		if (native_task)
>  			ASSIGN_SAS(se, args);
>  		else
>  			ASSIGN_SAS(se, args_c);
> +		se.has_compat_sigaction = true;
> +		se.compat_sigaction = !native_task;
>
>  		if (pb_write_one(img, &se, PB_SIGACT) < 0)
>  			return -1;
> diff --git a/criu/pie/Makefile b/criu/pie/Makefile
> index fee5d3c6f911..e30293692c5e 100644
> --- a/criu/pie/Makefile
> +++ b/criu/pie/Makefile
> @@ -15,6 +15,7 @@ restorer-obj-y		+= ./$(ARCH_DIR)/restorer.o
>  ifeq ($(ARCH),x86)
>          restorer-obj-e		+= ./$(ARCH_DIR)/syscalls-64.built-in.o
>          restorer-obj-y		+= ./$(ARCH_DIR)/call32.o
> +        restorer-obj-y		+= ./$(ARCH_DIR)/sigaction_compat_pie.o
>
>          native-obj-y		+= ./$(ARCH_DIR)/parasite-head-64.o
>          native-obj-e		+= ./$(ARCH_DIR)/syscalls-64.built-in.o
> @@ -68,6 +69,7 @@ define obj-export-compat-flags
>          LDFLAGS_$(notdir $(1))	:= $(COMPAT_LDFLAGS)
>  endef
>
> +$(eval $(call map,obj-export-native-flags,$(restorer-obj-y)))
>  $(eval $(call map,obj-export-native-flags,$(native-obj-y) native))
>  $(eval $(call map,obj-export-compat-flags,$(compat-obj-y) compat))
>
> diff --git a/criu/pie/restorer.c b/criu/pie/restorer.c
> index 9e0f4e5d1641..a4a9f5e57520 100644
> --- a/criu/pie/restorer.c
> +++ b/criu/pie/restorer.c
> @@ -1460,7 +1460,20 @@ long __export_restore_task(struct task_restore_args *args)
>  		goto core_restore_end;
>  	}
>
> -	sys_sigaction(SIGCHLD, &args->sigchld_act, NULL, sizeof(k_rtsigset_t));
> +	if (!args->compatible_mode) {
> +		sys_sigaction(SIGCHLD, &args->sigchld_act,
> +				NULL, sizeof(k_rtsigset_t));
> +	} else {
> +		void *stack = alloc_compat_syscall_stack();
> +
> +		if (!stack) {
> +			pr_err("Failed to allocate 32-bit stack for sigaction\n");
> +			goto core_restore_end;
> +		}
> +		arch_compat_rt_sigaction(stack, SIGCHLD,
> +				(void*)&args->sigchld_act);
> +		free_compat_syscall_stack(stack);
> +	}
>
>  	ret = restore_signals(args->siginfo, args->siginfo_n, true);
>  	if (ret)
> diff --git a/images/sa.proto b/images/sa.proto
> index e5099100b8b1..fdfc6713975d 100644
> --- a/images/sa.proto
> +++ b/images/sa.proto
> @@ -5,4 +5,5 @@ message sa_entry {
>  	required uint64	flags		= 2 [(criu).hex = true];
>  	required uint64	restorer	= 3 [(criu).hex = true];
>  	required uint64	mask		= 4 [(criu).hex = true];
> +	optional bool compat_sigaction	= 5;
>  }
>


-- 
Regards,
Dmitry Safonov


More information about the CRIU mailing list