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; }
int compel_infect(struct parasite_ctl *ctl, unsigned long nr_threads, unsigned long args_size) { int ret; unsigned long p, map_exchange_size, parasite_size = 0; if (ctl->pblob.parasite_type != COMPEL_BLOB_CHEADER) goto err; if (ctl->ictx.log_fd < 0) goto err; if (!arch_can_dump_task(ctl)) goto err; /* * Inject a parasite engine. Ie allocate memory inside alien * space and copy engine code there. Then re-map the engine * locally, so we will get an easy way to access engine memory * without using ptrace at all. */ parasite_size = total_pie_size(ctl->pblob.hdr.bsize); ctl->args_size = round_up(args_size, PAGE_SIZE); parasite_size += ctl->args_size; map_exchange_size = parasite_size; map_exchange_size += RESTORE_STACK_SIGFRAME + PARASITE_STACK_SIZE; if (nr_threads > 1) map_exchange_size += PARASITE_STACK_SIZE; ret = compel_map_exchange(ctl, map_exchange_size); if (ret) goto err; pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); ctl->parasite_ip = (unsigned long)(ctl->remote_map + ctl->pblob.hdr.parasite_ip_off); ctl->addr_cmd = ctl->local_map + ctl->pblob.hdr.addr_cmd_off; ctl->addr_args = ctl->local_map + ctl->pblob.hdr.addr_arg_off; memcpy(ctl->local_map, ctl->pblob.hdr.mem, ctl->pblob.hdr.bsize); if (ctl->pblob.hdr.nr_relocs) compel_relocs_apply(ctl->local_map, ctl->remote_map, ctl->pblob.hdr.bsize, ctl->pblob.hdr.relocs, ctl->pblob.hdr.nr_relocs); p = parasite_size; ctl->rsigframe = ctl->remote_map + p; ctl->sigframe = ctl->local_map + p; p += RESTORE_STACK_SIGFRAME; p += PARASITE_STACK_SIZE; ctl->rstack = ctl->remote_map + p; if (nr_threads > 1) { p += PARASITE_STACK_SIZE; ctl->r_thread_stack = ctl->remote_map + p; } ret = arch_fetch_sas(ctl, ctl->rsigframe); if (ret) { pr_err("Can't fetch sigaltstack for task %d (ret %d)\n", ctl->rpid, ret); goto err; } if (parasite_start_daemon(ctl)) goto err; return 0; err: return -1; }