From d7353b9bb7e57ab54875cb421ac21375fd588ef2 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 16 Jul 2020 23:14:35 +0000 Subject: [PATCH] compel: rewrite parasite cmd and args manipulation from assembly to C Previously, __export_parasite_cmd was located in parasite-head.S, and __export_parasite_args located exactly at the end of the parasite blob. This is not ideal for various reasons: 1) These two variables work together. It would be preferrable to have them in the same location 2) This prevent us from allocating another section betweeen the parasite blob and the args area. We'll need this to allocate a GOT table This commit changes the allocation of these symbols from assembly/linker script to a C file. Moreover, the assembly entry points that invoke parasite_service() prepares arguments with hand crafted assembly. This is unecessary. This commit rewrite this logic with regular C code. Note: if it wasn't for the x86 compat mode, we could remove all parasite-head.S files and directly jump to parasite_service() via ptrace. An int3 architecture specific equivalent could be called at the end of parasite_service() with an inline asm statement. Signed-off-by: Nicolas Viennot --- .../arch/aarch64/plugins/std/parasite-head.S | 13 -------- compel/arch/aarch64/scripts/compel-pack.lds.S | 4 --- compel/arch/arm/plugins/std/parasite-head.S | 14 -------- compel/arch/arm/scripts/compel-pack.lds.S | 4 --- compel/arch/mips/plugins/std/parasite-head.S | 5 --- compel/arch/mips/scripts/compel-pack.lds.S | 4 --- compel/arch/ppc64/plugins/std/parasite-head.S | 16 ---------- compel/arch/ppc64/scripts/compel-pack.lds.S | 4 --- compel/arch/s390/plugins/std/parasite-head.S | 18 ----------- compel/arch/s390/scripts/compel-pack.lds.S | 4 --- compel/arch/x86/plugins/std/parasite-head.S | 6 ---- .../arch/x86/scripts/compel-pack-compat.lds.S | 4 --- compel/arch/x86/scripts/compel-pack.lds.S | 4 --- compel/include/uapi/infect.h | 1 + compel/plugins/include/uapi/std/infect.h | 5 ++- compel/plugins/std/infect.c | 16 +++++++++- compel/src/lib/handle-elf.c | 7 ++-- compel/src/lib/infect.c | 32 ++++++++++++++++++- 18 files changed, 54 insertions(+), 107 deletions(-) diff --git a/compel/arch/aarch64/plugins/std/parasite-head.S b/compel/arch/aarch64/plugins/std/parasite-head.S index 5e7067f6b..456c2117d 100644 --- a/compel/arch/aarch64/plugins/std/parasite-head.S +++ b/compel/arch/aarch64/plugins/std/parasite-head.S @@ -2,19 +2,6 @@ .section .head.text, "ax" ENTRY(__export_parasite_head_start) - adr x2, __export_parasite_head_start // get the address of this instruction - - ldr x0, __export_parasite_cmd - - ldr x1, parasite_args_ptr - add x1, x1, x2 // fixup __export_parasite_args - bl parasite_service brk #0 // the instruction BRK #0 generates the signal SIGTRAP in Linux - -parasite_args_ptr: - .quad __export_parasite_args - -__export_parasite_cmd: - .quad 0 END(__export_parasite_head_start) diff --git a/compel/arch/aarch64/scripts/compel-pack.lds.S b/compel/arch/aarch64/scripts/compel-pack.lds.S index eba89cd5f..57895ec9b 100644 --- a/compel/arch/aarch64/scripts/compel-pack.lds.S +++ b/compel/arch/aarch64/scripts/compel-pack.lds.S @@ -29,8 +29,4 @@ SECTIONS *(.eh_frame*) *(*) } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; } diff --git a/compel/arch/arm/plugins/std/parasite-head.S b/compel/arch/arm/plugins/std/parasite-head.S index e72646b50..6e46bed1f 100644 --- a/compel/arch/arm/plugins/std/parasite-head.S +++ b/compel/arch/arm/plugins/std/parasite-head.S @@ -2,21 +2,7 @@ .section .head.text, "ax" ENTRY(__export_parasite_head_start) - sub r2, pc, #8 @ get the address of this instruction - - adr r0, __export_parasite_cmd - ldr r0, [r0] - - adr r1, parasite_args_ptr - ldr r1, [r1] - add r1, r1, r2 @ fixup __export_parasite_args - bl parasite_service .byte 0xf0, 0x01, 0xf0, 0xe7 @ the instruction UDF #32 generates the signal SIGTRAP in Linux -parasite_args_ptr: - .long __export_parasite_args - -__export_parasite_cmd: - .long 0 END(__export_parasite_head_start) diff --git a/compel/arch/arm/scripts/compel-pack.lds.S b/compel/arch/arm/scripts/compel-pack.lds.S index f8a4739f3..3d97bb139 100644 --- a/compel/arch/arm/scripts/compel-pack.lds.S +++ b/compel/arch/arm/scripts/compel-pack.lds.S @@ -29,8 +29,4 @@ SECTIONS *(.eh_frame*) *(*) } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; } diff --git a/compel/arch/mips/plugins/std/parasite-head.S b/compel/arch/mips/plugins/std/parasite-head.S index 38e87f823..978c0b58c 100755 --- a/compel/arch/mips/plugins/std/parasite-head.S +++ b/compel/arch/mips/plugins/std/parasite-head.S @@ -6,15 +6,10 @@ ENTRY(__export_parasite_head_start) .set push .set noreorder - lw a0, __export_parasite_cmd - dla a1, __export_parasite_args jal parasite_service nop .byte 0x0d, 0x00, 0x00, 0x00 //break .set pop // .byte 0x40,0x01,0x00,0x00 //pause - -__export_parasite_cmd: - .long 0 END(__export_parasite_head_start) diff --git a/compel/arch/mips/scripts/compel-pack.lds.S b/compel/arch/mips/scripts/compel-pack.lds.S index cadb19aef..24ee408e8 100755 --- a/compel/arch/mips/scripts/compel-pack.lds.S +++ b/compel/arch/mips/scripts/compel-pack.lds.S @@ -30,8 +30,4 @@ SECTIONS *(.MIPS.options) *(.gnu.attributes) } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(32); -__export_parasite_args = .; } diff --git a/compel/arch/ppc64/plugins/std/parasite-head.S b/compel/arch/ppc64/plugins/std/parasite-head.S index c870efdc2..c675ab508 100644 --- a/compel/arch/ppc64/plugins/std/parasite-head.S +++ b/compel/arch/ppc64/plugins/std/parasite-head.S @@ -4,10 +4,6 @@ .align 8 ENTRY(__export_parasite_head_start) - - // int __used parasite_service(unsigned int cmd, void *args) - // cmd = r3 = *__export_parasite_cmd (u32 ?) - // args = r4 = @parasite_args_ptr + @pc bl 0f 0: mflr r2 @@ -15,12 +11,6 @@ ENTRY(__export_parasite_head_start) addis reg,r2,(name - 0b)@ha; \ addi reg,r2,(name - 0b)@l; - LOAD_REG_ADDR(r3,__export_parasite_cmd) - lwz r3,0(r3) - - LOAD_REG_ADDR(r4,parasite_args_ptr) - ld r4,0(r4) - LOAD_REG_ADDR(r12,parasite_service_ptr) ld r12,0(r12) mtctr r12 @@ -28,9 +18,6 @@ ENTRY(__export_parasite_head_start) bctrl // call parasite_service twi 31,0,0 // Should generate SIGTRAP -parasite_args_ptr: - .quad __export_parasite_args - parasite_service_ptr: // We want to run the function prototype to set r2. // Since the relocation will prefer the local entry @@ -39,7 +26,4 @@ parasite_service_ptr: // FIXME: There should be a way to specify the global entry here. .quad parasite_service - 8 -__export_parasite_cmd: - .long 0 - END(__export_parasite_head_start) diff --git a/compel/arch/ppc64/scripts/compel-pack.lds.S b/compel/arch/ppc64/scripts/compel-pack.lds.S index e0f826d7d..572f1c42d 100644 --- a/compel/arch/ppc64/scripts/compel-pack.lds.S +++ b/compel/arch/ppc64/scripts/compel-pack.lds.S @@ -33,8 +33,4 @@ SECTIONS *(.group*) *(.eh_frame*) } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; } diff --git a/compel/arch/s390/plugins/std/parasite-head.S b/compel/arch/s390/plugins/std/parasite-head.S index f4cb37276..1e276a2f5 100644 --- a/compel/arch/s390/plugins/std/parasite-head.S +++ b/compel/arch/s390/plugins/std/parasite-head.S @@ -2,25 +2,7 @@ .section .head.text, "ax" -/* - * Entry point for parasite_service() - * - * Addresses of symbols are exported in auto-generated criu/pie/parasite-blob.h - * - * Function is called via parasite_run(). The command for parasite_service() - * is stored in global variable __export_parasite_cmd. - * - * Load parameters for parasite_service(unsigned int cmd, void *args): - * - * - Parameter 1 (cmd) : %r2 = *(uint32 *)(__export_parasite_cmd + pc) - * - Parameter 2 (args): %r3 = __export_parasite_args + pc - */ ENTRY(__export_parasite_head_start) - larl %r14,__export_parasite_cmd - llgf %r2,0(%r14) - larl %r3,__export_parasite_args brasl %r14,parasite_service .long 0x00010001 /* S390_BREAKPOINT_U16: Generates SIGTRAP */ -__export_parasite_cmd: - .long 0 END(__export_parasite_head_start) diff --git a/compel/arch/s390/scripts/compel-pack.lds.S b/compel/arch/s390/scripts/compel-pack.lds.S index 91ffbda3e..2571ac852 100644 --- a/compel/arch/s390/scripts/compel-pack.lds.S +++ b/compel/arch/s390/scripts/compel-pack.lds.S @@ -33,8 +33,4 @@ SECTIONS *(.group*) *(.eh_frame*) } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; } diff --git a/compel/arch/x86/plugins/std/parasite-head.S b/compel/arch/x86/plugins/std/parasite-head.S index 465cd887b..2225568b9 100644 --- a/compel/arch/x86/plugins/std/parasite-head.S +++ b/compel/arch/x86/plugins/std/parasite-head.S @@ -11,8 +11,6 @@ andq $~15, %rsp pushq $\num movq %rsp, %rbp - movl __export_parasite_cmd(%rip), %edi - leaq __export_parasite_args(%rip), %rsi call parasite_service .endm @@ -48,7 +46,3 @@ ENTRY(__export_parasite_head_start) PARASITE_ENTRY 0 int $0x03 END(__export_parasite_head_start) - -.align 8 -GLOBAL(__export_parasite_cmd) - .long 0 diff --git a/compel/arch/x86/scripts/compel-pack-compat.lds.S b/compel/arch/x86/scripts/compel-pack-compat.lds.S index ff9c2c6b2..2d907a4a7 100644 --- a/compel/arch/x86/scripts/compel-pack-compat.lds.S +++ b/compel/arch/x86/scripts/compel-pack-compat.lds.S @@ -34,8 +34,4 @@ SECTIONS *(.group*) *(.eh_frame*) } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; } diff --git a/compel/arch/x86/scripts/compel-pack.lds.S b/compel/arch/x86/scripts/compel-pack.lds.S index 0c936f84d..68ddb3622 100644 --- a/compel/arch/x86/scripts/compel-pack.lds.S +++ b/compel/arch/x86/scripts/compel-pack.lds.S @@ -34,8 +34,4 @@ SECTIONS *(.group*) *(.eh_frame*) } - -/* Parasite args should have 4 bytes align, as we have futex inside. */ -. = ALIGN(4); -__export_parasite_args = .; } diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index aebaa8f75..8f9de0e1c 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -153,6 +153,7 @@ struct parasite_blob_desc { size_t nr_gotpcrel; unsigned long parasite_ip_off; unsigned long cmd_off; + unsigned long args_ptr_off; unsigned long args_off; compel_reloc_t *relocs; unsigned int nr_relocs; diff --git a/compel/plugins/include/uapi/std/infect.h b/compel/plugins/include/uapi/std/infect.h index 1e784f8b4..78de781b2 100644 --- a/compel/plugins/include/uapi/std/infect.h +++ b/compel/plugins/include/uapi/std/infect.h @@ -4,7 +4,10 @@ #include "common/compiler.h" extern int parasite_get_rpc_sock(void); -extern int __must_check parasite_service(unsigned int cmd, void *args); + +extern unsigned int __export_parasite_service_cmd; +extern void * __export_parasite_service_args_ptr; +extern int __must_check parasite_service(void); /* * Must be supplied by user plugins. diff --git a/compel/plugins/std/infect.c b/compel/plugins/std/infect.c index d5e1b4354..9749db7b7 100644 --- a/compel/plugins/std/infect.c +++ b/compel/plugins/std/infect.c @@ -196,8 +196,22 @@ err: # define __parasite_entry #endif -int __used __parasite_entry parasite_service(unsigned int cmd, void *args) +/* + * __export_parasite_service_{cmd,args} serve as arguments to the + * parasite_service() function. We use these global variables to make it + * easier to pass arguments when invoking from ptrace. + * + * We need the linker to allocate these variables. Hence the dummy + * initialization. Otherwise, we end up with COMMON symbols. + */ +unsigned int __export_parasite_service_cmd = 0; +void * __export_parasite_service_args_ptr = NULL; + +int __used __parasite_entry parasite_service(void) { + unsigned int cmd = __export_parasite_service_cmd; + void *args = __export_parasite_service_args_ptr; + pr_info("Parasite cmd %d/%x process\n", cmd, cmd); if (cmd == PARASITE_CMD_INIT_DAEMON) diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 6fb0fb37f..8a79151b4 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -699,10 +699,9 @@ int __handle_elf(void *mem, size_t size) pr_out("\t\tpbd->hdr.parasite_ip_off = " "%s_sym__export_parasite_head_start_compat;\n", opts.prefix); pr_out("#endif /* CONFIG_COMPAT */\n"); - pr_out("\tpbd->hdr.cmd_off = " - "%s_sym__export_parasite_cmd;\n", opts.prefix); - pr_out("\tpbd->hdr.args_off = " - "%s_sym__export_parasite_args;\n", opts.prefix); + pr_out("\tpbd->hdr.cmd_off = %s_sym__export_parasite_service_cmd;\n", opts.prefix); + pr_out("\tpbd->hdr.args_ptr_off = %s_sym__export_parasite_service_args_ptr;\n", opts.prefix); + pr_out("\tpbd->hdr.args_off = round_up(pbd->hdr.bsize, 4);\n"); pr_out("\tpbd->hdr.relocs = %s_relocs;\n", opts.prefix); pr_out("\tpbd->hdr.nr_relocs = " "sizeof(%s_relocs) / sizeof(%s_relocs[0]);\n", diff --git a/compel/src/lib/infect.c b/compel/src/lib/infect.c index 887a22d2a..78fe1f1a6 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -822,6 +822,13 @@ void compel_relocs_apply(void *mem, void *vbase, struct parasite_blob_desc *pbd) size_t i, j; + /* + * parasite_service() reads the value of __export_parasite_service_args_ptr. + * The reason it is set here is that semantically, we are doing a symbol + * resolution on parasite_service_args, and it turns out to be relocatable. + */ + *(void **)(mem + pbd->hdr.args_ptr_off) = vbase + pbd->hdr.args_off; + #ifdef CONFIG_MIPS compel_relocs_apply_mips(mem, vbase, pbd); #else @@ -883,7 +890,30 @@ int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned l * without using ptrace at all. */ - parasite_size = ctl->pblob.hdr.bsize; + /* + * The parasite memory layout is the following: + * Low address start first. + * The number in parenthesis denotes the size of the section. + * The arrow on the right shows the different variables that + * corresponds to a given offset. + * +------------------------------------------------------+ <--- 0 + * | Parasite blob (sizeof(parasite_blob)) | + * +------------------------------------------------------+ <--- hdr.bsize + * align 4 + * +------------------------------------------------------+ <--- hdr.args_off + * | Args area (args_size) | + * +------------------------------------------------------+ + * align 64 + * +------------------------------------------------------+ <--- ctl->rsigframe + * | sigframe (RESTORE_STACK_SIGFRAME) | ctl->sigframe + * +------------------------------------------------------+ + * | main stack (PARASITE_STACK_SIZE) | + * +------------------------------------------------------+ <--- ctl->rstack + * | compel_run_in_thread stack (PARASITE_STACK_SIZE) | + * +------------------------------------------------------+ <--- ctl->r_thread_stack + * map_exchange_size + */ + parasite_size = ctl->pblob.hdr.args_off; ctl->args_size = args_size; parasite_size += ctl->args_size;