int cr_exec(int pid, char **opt) { char *sys_name = opt[0]; struct syscall_exec_desc *si; struct parasite_ctl *ctl; struct vm_area_list vmas; int ret = -1, prev_state; struct proc_status_creds *creds; if (!sys_name) { pr_err("Syscall name required\n"); goto out; } si = find_syscall(sys_name); if (!si) { pr_err("Unknown syscall [%s]\n", sys_name); goto out; } if (seize_catch_task(pid)) goto out; prev_state = ret = seize_wait_task(pid, -1, &creds); if (ret < 0) { pr_err("Can't seize task %d\n", pid); goto out; } /* * We don't seize a task's threads here, and there is no reason to * compare threads' creds in this use case anyway, so let's just free * the creds. */ free(creds); ret = collect_mappings(pid, &vmas, NULL); if (ret) { pr_err("Can't collect vmas for %d\n", pid); goto out_unseize; } ctl = parasite_prep_ctl(pid, &vmas); if (!ctl) { pr_err("Can't prep ctl %d\n", pid); goto out_unseize; } ret = execute_syscall(ctl, si, opt + 1); if (ret < 0) pr_err("Can't execute syscall remotely\n"); parasite_cure_seized(ctl); out_unseize: unseize_task(pid, prev_state, prev_state); out: return ret; }
struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item, struct vm_area_list *vma_area_list, struct parasite_drain_fd *dfds) { int ret; struct parasite_ctl *ctl; ctl = parasite_prep_ctl(pid, vma_area_list); if (!ctl) return NULL; /* * 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. */ ctl->args_size = parasite_args_size(vma_area_list, dfds); ret = parasite_map_exchange(ctl, parasite_size + ctl->args_size); if (ret) goto err_restore; pr_info("Putting parasite blob into %p->%p\n", ctl->local_map, ctl->remote_map); memcpy(ctl->local_map, parasite_blob, sizeof(parasite_blob)); /* Setup the rest of a control block */ ctl->parasite_ip = (unsigned long)parasite_sym(ctl->remote_map, __export_parasite_head_start); ctl->addr_cmd = parasite_sym(ctl->local_map, __export_parasite_cmd); ctl->addr_args = parasite_sym(ctl->local_map, __export_parasite_args); ret = parasite_init(ctl, pid, item->nr_threads); if (ret) { pr_err("%d: Can't create a transport socket\n", pid); goto err_restore; } ctl->signals_blocked = 1; ret = parasite_set_logfd(ctl, pid); if (ret) { pr_err("%d: Can't set a logging descriptor\n", pid); goto err_restore; } ret = parasite_init_threads_seized(ctl, item); if (ret) goto err_restore; return ctl; err_restore: parasite_cure_seized(ctl, item); return NULL; }