int compel_execute_syscall(struct parasite_ctl *ctl, user_regs_struct_t *regs, const char *code_syscall) { pid_t pid = ctl->rpid; int err; uint8_t code_orig[BUILTIN_SYSCALL_SIZE]; /* * Inject syscall instruction and remember original code, * we will need it to restore original program content. */ memcpy(code_orig, code_syscall, sizeof(code_orig)); if (ptrace_swap_area(pid, (void *)ctl->ictx.syscall_ip, (void *)code_orig, sizeof(code_orig))) { pr_err("Can't inject syscall blob (pid: %d)\n", pid); return -1; } err = parasite_run(pid, PTRACE_CONT, ctl->ictx.syscall_ip, 0, regs, &ctl->orig); if (!err) err = parasite_trap(ctl, pid, regs, &ctl->orig); if (ptrace_poke_area(pid, (void *)code_orig, (void *)ctl->ictx.syscall_ip, sizeof(code_orig))) { pr_err("Can't restore syscall blob (pid: %d)\n", ctl->rpid); err = -1; } return err; }
struct parasite_ctl *parasite_prep_ctl(pid_t pid, struct vm_area_list *vma_area_list) { struct parasite_ctl *ctl = NULL; struct vma_area *vma_area; if (!arch_can_dump_task(pid)) goto err; /* * Control block early setup. */ ctl = xzalloc(sizeof(*ctl)); if (!ctl) { pr_err("Parasite control block allocation failed (pid: %d)\n", pid); goto err; } ctl->tsock = -1; if (ptrace(PTRACE_GETREGS, pid, NULL, &ctl->regs_orig)) { pr_err("Can't obtain registers (pid: %d)\n", pid); goto err; } vma_area = get_vma_by_ip(&vma_area_list->h, REG_IP(ctl->regs_orig)); if (!vma_area) { pr_err("No suitable VMA found to run parasite " "bootstrap code (pid: %d)\n", pid); goto err; } ctl->pid.real = pid; ctl->pid.virt = 0; ctl->syscall_ip = vma_area->vma.start; /* * Inject syscall instruction and remember original code, * we will need it to restore original program content. */ memcpy(ctl->code_orig, code_syscall, sizeof(ctl->code_orig)); if (ptrace_swap_area(pid, (void *)ctl->syscall_ip, (void *)ctl->code_orig, sizeof(ctl->code_orig))) { pr_err("Can't inject syscall blob (pid: %d)\n", pid); goto err; } return ctl; err: xfree(ctl); return NULL; }
static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size) { void *where = (void *)ctl->ictx.syscall_ip + BUILTIN_SYSCALL_SIZE; uint8_t orig_code[MEMFD_FNAME_SZ] = MEMFD_FNAME; pid_t pid = ctl->rpid; long sret = -ENOSYS; int ret, fd, lfd; bool __maybe_unused compat_task = !compel_mode_native(ctl); if (ctl->ictx.flags & INFECT_NO_MEMFD) return 1; BUILD_BUG_ON(sizeof(orig_code) < sizeof(long)); if (ptrace_swap_area(pid, where, (void *)orig_code, sizeof(orig_code))) { pr_err("Can't inject memfd args (pid: %d)\n", pid); return -1; } ret = compel_syscall(ctl, __NR(memfd_create, compat_task), &sret, (unsigned long)where, 0, 0, 0, 0, 0); if (ptrace_poke_area(pid, orig_code, where, sizeof(orig_code))) { fd = (int)(long)sret; if (fd >= 0) compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); pr_err("Can't restore memfd args (pid: %d)\n", pid); return -1; } if (ret < 0) return ret; fd = (int)(long)sret; if (fd == -ENOSYS) return 1; if (fd < 0) { errno = -fd; pr_perror("Can't create memfd in victim"); return fd; } ctl->map_length = round_up(size, page_size()); lfd = ctl->ictx.open_proc(ctl->rpid, O_RDWR, "fd/%d", fd); if (lfd < 0) goto err_cure; if (ftruncate(lfd, ctl->map_length) < 0) { pr_perror("Fail to truncate memfd for parasite"); goto err_cure; } ctl->remote_map = remote_mmap(ctl, NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FILE | MAP_SHARED, fd, 0); if (!ctl->remote_map) { pr_err("Can't rmap memfd for parasite blob\n"); goto err_curef; } ctl->local_map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, lfd, 0); if (ctl->local_map == MAP_FAILED) { ctl->local_map = NULL; pr_perror("Can't lmap memfd for parasite blob"); goto err_curef; } compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); close(lfd); pr_info("Set up parasite blob using memfd\n"); return 0; err_curef: close(lfd); err_cure: compel_syscall(ctl, __NR(close, compat_task), &sret, fd, 0, 0, 0, 0, 0); return -1; }