static int parasite_init(struct parasite_ctl *ctl, pid_t pid, int nr_threads) { struct parasite_init_args *args; static int sock = -1; args = parasite_args(ctl, struct parasite_init_args); pr_info("Putting tsock into pid %d\n", pid); args->h_addr_len = gen_parasite_saddr(&args->h_addr, getpid()); args->p_addr_len = gen_parasite_saddr(&args->p_addr, pid); args->nr_threads = nr_threads; if (sock == -1) { int rst = -1; if (current_ns_mask & CLONE_NEWNET) { pr_info("Switching to %d's net for tsock creation\n", pid); if (switch_ns(pid, &net_ns_desc, &rst)) return -1; } sock = socket(PF_UNIX, SOCK_DGRAM, 0); if (sock < 0) pr_perror("Can't create socket"); if (rst > 0 && restore_ns(rst, &net_ns_desc) < 0) return -1; if (sock < 0) return -1; if (bind(sock, (struct sockaddr *)&args->h_addr, args->h_addr_len) < 0) { pr_perror("Can't bind socket"); goto err; } } else { struct sockaddr addr = { .sa_family = AF_UNSPEC, }; /* * When the peer of a dgram socket dies the original socket * remains in connected state, thus denying any connections * from "other" sources. Unconnect the socket by hands thus * allowing for parasite to connect back. */ if (connect(sock, &addr, sizeof(addr)) < 0) { pr_perror("Can't unconnect"); goto err; } } if (parasite_execute(PARASITE_CMD_INIT, ctl) < 0) { pr_err("Can't init parasite\n"); goto err; } if (connect(sock, (struct sockaddr *)&args->p_addr, args->p_addr_len) < 0) { pr_perror("Can't connect a transport socket"); goto err; } ctl->tsock = sock; return 0; err: close_safe(&sock); return -1; }
static ct_process_t __local_enter_cb(ct_handler_t h, ct_process_desc_t ph, int (*cb)(void *), void *arg, bool is_exec) { struct container *ct = cth2ct(h); struct process_desc *p = prh2pr(ph); struct process *pr; int aux = -1, pid; int wait_pipe[2]; if (ct->state != CT_RUNNING) return ERR_PTR(-LCTERR_BADCTSTATE); if (ct->nsmask & CLONE_NEWPID) { if (switch_ns(ct->p.pid, &pid_ns, &aux)) return ERR_PTR(-LCTERR_INVARG); } pr = xmalloc(sizeof(struct process)); if (pr == NULL) return ERR_PTR(-1); local_process_init(pr); if (pipe(wait_pipe)) { xfree(pr); return ERR_PTR(-1); } pid = fork(); if (pid == 0) { struct ns_desc *ns; close(wait_pipe[0]); if (p->fds) { p->fds[p->fdn] = wait_pipe[1]; if (setup_fds(p->fds, p->fdn + 1)) exit(-1); wait_pipe[1] = p->fdn; } for (aux = 0; namespaces[aux]; aux++) { ns = namespaces[aux]; if (ns->cflag == CLONE_NEWPID) continue; if (!(ns->cflag & ct->nsmask)) continue; if (switch_ns(ct->p.pid, ns, NULL)) exit(-1); } if (cgroups_attach(ct)) exit(-1); if (ct->root_path && !(ct->nsmask & CLONE_NEWNS)) { char nroot[128]; /* * Otherwise switched by setns() */ snprintf(nroot, sizeof(nroot), "/proc/%d/root", ct->p.pid); if (set_current_root(nroot)) exit(-1); } if (apply_creds(p)) exit(-1); if (is_exec) spawn_wake_and_cloexec(wait_pipe, 0); else spawn_wake_and_close(wait_pipe, 0); aux = cb(arg); if (is_exec) spawn_wake_and_close(wait_pipe, -1); exit(aux); } close(wait_pipe[1]); if (aux >= 0) restore_ns(aux, &pid_ns); if (spawn_wait(wait_pipe)) goto err; if (spawn_wait_and_close(wait_pipe) != INT_MIN) goto err; pr->pid = pid; return &pr->h; err: xfree(pr); close(wait_pipe[0]); waitpid(pid, NULL, 0); return ERR_PTR(-1); }