diff --git a/compel/arch/ppc64/scripts/compel-pack.lds.S b/compel/arch/ppc64/scripts/compel-pack.lds.S index 572f1c42d..f197fb999 100644 --- a/compel/arch/ppc64/scripts/compel-pack.lds.S +++ b/compel/arch/ppc64/scripts/compel-pack.lds.S @@ -12,7 +12,7 @@ SECTIONS *(.compel.init) } - .data : { + .data : ALIGN(0x10000) { *(.data*) *(.bss*) } diff --git a/compel/arch/s390/scripts/compel-pack.lds.S b/compel/arch/s390/scripts/compel-pack.lds.S index 2571ac852..a82118983 100644 --- a/compel/arch/s390/scripts/compel-pack.lds.S +++ b/compel/arch/s390/scripts/compel-pack.lds.S @@ -12,7 +12,7 @@ SECTIONS *(.compel.init) } - .data : { + .data : ALIGN(0x1000) { *(.data*) *(.bss*) } diff --git a/compel/arch/x86/scripts/compel-pack.lds.S b/compel/arch/x86/scripts/compel-pack.lds.S index 68ddb3622..44e705e29 100644 --- a/compel/arch/x86/scripts/compel-pack.lds.S +++ b/compel/arch/x86/scripts/compel-pack.lds.S @@ -13,7 +13,7 @@ SECTIONS *(.compel.init) } - .data : { + .data : ALIGN(0x1000) { *(.data*) *(.bss*) } diff --git a/compel/include/uapi/infect.h b/compel/include/uapi/infect.h index 257658a70..fa326eafe 100644 --- a/compel/include/uapi/infect.h +++ b/compel/include/uapi/infect.h @@ -155,6 +155,7 @@ struct parasite_blob_desc { unsigned long args_ptr_off; unsigned long got_off; unsigned long args_off; + unsigned long data_off; compel_reloc_t *relocs; unsigned int nr_relocs; } hdr; diff --git a/compel/src/lib/handle-elf.c b/compel/src/lib/handle-elf.c index 2319170ae..e505f2c43 100644 --- a/compel/src/lib/handle-elf.c +++ b/compel/src/lib/handle-elf.c @@ -155,6 +155,7 @@ int __handle_elf(void *mem, size_t size) int64_t toc_offset = 0; #endif int ret = -EINVAL; + unsigned long data_off = 0; pr_debug("Header\n"); pr_debug("------------\n"); @@ -698,6 +699,9 @@ int __handle_elf(void *mem, size_t size) pr_out("\n\t"); pr_out("0x%02x,", shdata[j]); } + + if (!strcmp(&secstrings[sh->sh_name], ".data")) + data_off = sh->sh_addr; } pr_out("};\n"); pr_out("\n"); @@ -722,6 +726,7 @@ int __handle_elf(void *mem, size_t size) pr_out("\tpbd->hdr.args_ptr_off = %s_sym__export_parasite_service_args_ptr;\n", opts.prefix); pr_out("\tpbd->hdr.got_off = round_up(pbd->hdr.bsize, sizeof(long));\n"); pr_out("\tpbd->hdr.args_off = pbd->hdr.got_off + %zd*sizeof(long);\n", nr_gotpcrel); + pr_out("\tpbd->hdr.data_off = %#lx;\n", data_off); 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 38846c21f..5c4c1b18d 100644 --- a/compel/src/lib/infect.c +++ b/compel/src/lib/infect.c @@ -690,12 +690,11 @@ static int parasite_start_daemon(struct parasite_ctl *ctl) return 0; } -static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size) +static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size, int remote_prot) { int fd; - ctl->remote_map = remote_mmap(ctl, NULL, size, - PROT_READ | PROT_WRITE | PROT_EXEC, + ctl->remote_map = remote_mmap(ctl, NULL, size, remote_prot, MAP_ANONYMOUS | MAP_SHARED, -1, 0); if (!ctl->remote_map) { pr_err("Can't allocate memory for parasite blob (pid: %d)\n", ctl->rpid); @@ -733,7 +732,7 @@ static void parasite_memfd_close(struct parasite_ctl *ctl, int fd) pr_err("Can't close memfd\n"); } -static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) +static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size, int remote_prot) { void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; bool compat_task = !compel_mode_native(ctl); @@ -785,8 +784,7 @@ static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) goto err_cure; } - ctl->remote_map = remote_mmap(ctl, NULL, size, - PROT_READ | PROT_WRITE | PROT_EXEC, + ctl->remote_map = remote_mmap(ctl, NULL, size, remote_prot, MAP_FILE | MAP_SHARED, fd, 0); if (!ctl->remote_map) { pr_err("Can't rmap memfd for parasite blob\n"); @@ -856,15 +854,47 @@ void compel_relocs_apply(void *mem, void *vbase, struct parasite_blob_desc *pbd) #endif } +long remote_mprotect(struct parasite_ctl *ctl, void *addr, size_t len, int prot) +{ + long ret; + int err; + bool compat_task = !user_regs_native(&ctl->orig.regs); + + err = compel_syscall(ctl, __NR(mprotect, compat_task), &ret, + (unsigned long)addr, len, prot, 0, 0, 0); + if (err < 0) { + pr_err("compel_syscall for mprotect failed\n"); + return -1; + } + return ret; +} + static int compel_map_exchange(struct parasite_ctl *ctl, unsigned long size) { - int ret; + int ret, remote_prot; - ret = parasite_memfd_exchange(ctl, size); + if (ctl->pblob.hdr.data_off) + remote_prot = PROT_READ | PROT_EXEC; + else + remote_prot = PROT_READ | PROT_WRITE | PROT_EXEC; + + ret = parasite_memfd_exchange(ctl, size, remote_prot); if (ret == 1) { pr_info("MemFD parasite doesn't work, goto legacy mmap\n"); - ret = parasite_mmap_exchange(ctl, size); + ret = parasite_mmap_exchange(ctl, size, remote_prot); + if (ret) + return ret; } + + if (!ctl->pblob.hdr.data_off) + return 0; + + ret = remote_mprotect(ctl, ctl->remote_map + ctl->pblob.hdr.data_off, + size - ctl->pblob.hdr.data_off, + PROT_READ | PROT_WRITE); + if (ret) + pr_err("remote_mprotect failed\n"); + return ret; }