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; }
static void unseize_task_and_threads(const struct pstree_item *item, int st) { int i; if (item->state == TASK_DEAD) return; /* * The st is the state we want to switch tasks into, * the item->state is the state task was in when we seized one. */ unseize_task(item->pid.real, item->state, st); if (st == TASK_DEAD) return; for (i = 1; i < item->nr_threads; i++) if (ptrace(PTRACE_DETACH, item->threads[i].real, NULL, NULL)) pr_perror("Unable to detach from %d", item->threads[i].real); }