diff --git a/criu/cr-dump.c b/criu/cr-dump.c index 81be59824..3a64990aa 100644 --- a/criu/cr-dump.c +++ b/criu/cr-dump.c @@ -871,7 +871,16 @@ static int dump_task_thread(struct parasite_ctl *parasite_ctl, pr_err("Can't dump thread for pid %d\n", pid); goto err; } - tid->ns[0].virt = parasite_tid; + + if (tid->ns[0].virt == -1) + tid->ns[0].virt = parasite_tid; + else { + /* It was collected in parse_pid_status() */ + if (last_level_pid(tid) != parasite_tid) { + pr_err("Parasite and /proc/[pid]/status gave different tids\n"); + goto err; + } + } pstree_insert_pid(tid, item->ids->pid_ns_id); @@ -1341,9 +1350,20 @@ static int dump_one_task(struct pstree_item *item) goto err_cure_imgset; } - vpid(item) = misc.pid; - vsid(item) = misc.sid; - vpgid(item) = misc.pgid; + if (vpid(item) == -1) { + vpid(item) = misc.pid; + vsid(item) = misc.sid; + vpgid(item) = misc.pgid; + } else { + /* They were collected in parse_pid_status() */ + if (last_level_pid(item->pid) != misc.pid || + last_level_pid(item->sid) != misc.sid || + last_level_pid(item->pgid) != misc.pgid) { + pr_err("Parasite and /proc/[pid]/status gave different pids\n"); + goto err; + } + } + pstree_insert_pid(item->pid, item->ids->pid_ns_id); pr_info("sid=%d pgid=%d pid=%d\n", vsid(item), vpgid(item), vpid(item)); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 691ea9a11..5150396db 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -1037,6 +1037,44 @@ static int cap_parse(char *str, unsigned int *res) return 0; } +static int get_ns_pid(char *str, struct pid **pid_ptr) +{ + pid_t pid[MAX_NS_NESTING]; + int level, size, skip; + pid_t val; + + skip = pid_ns_root_off(); + + level = 0; + while (sscanf(str, "%d%n", &val, &size) == 1) { + if (level == MAX_NS_NESTING) { + pr_err("Too nested hierarchy\n"); + return -1; + } + str += size; + if (skip > 0) { + skip--; + continue; + } + pid[level++] = val; + } + + if (level == 0) { + pr_err("Line can't be collected\n"); + return -1; + } + + (*pid_ptr) = xrealloc(*pid_ptr, PID_SIZE(level)); + if (!*pid_ptr) + return -1; + + (*pid_ptr)->level = level; + while (level-- > 0) + (*pid_ptr)->ns[level].virt = pid[level]; + + return 0; +} + int parse_pid_status(pid_t pid, struct seize_task_status *ss, struct pstree_item *item, struct pid **thread) { @@ -1046,6 +1084,7 @@ int parse_pid_status(pid_t pid, struct seize_task_status *ss, int ret = -1; char *str; bool parsed_seccomp = false; + int expected_done; f.fd = open_proc(pid, "status"); if (f.fd < 0) @@ -1057,7 +1096,7 @@ int parse_pid_status(pid_t pid, struct seize_task_status *ss, if (bfdopenr(&f)) return -1; - while (done < 12) { + while (done < 14) { str = breadline(&f); if (str == NULL) break; @@ -1157,10 +1196,43 @@ int parse_pid_status(pid_t pid, struct seize_task_status *ss, done++; continue; } + if (!strncmp(str, "NSpid:", 6)) { + if (get_ns_pid(str + 6, thread ? : &item->pid) < 0) { + pr_err("Can't get NSpid\n"); + goto err_parse; + } + done++; + continue; + } + if (!strncmp(str, "NSpgid:", 7) && !thread) { + if (get_ns_pid(str + 7, &item->pgid) < 0) { + pr_err("Can't get NSpgid\n"); + goto err_parse; + } + done++; + continue; + } + if (!strncmp(str, "NSsid:", 6) && !thread) { + if (get_ns_pid(str + 6, &item->sid) < 0) { + pr_err("Can't get NSsid\n"); + goto err_parse; + } + done++; + continue; + } } - /* seccomp is optional */ - if (done >= 11 || (done == 10 && !parsed_seccomp)) + if (!thread && (item->pid->level != item->sid->level || + item->pid->level != item->pgid->level)) { + pr_err("Level mismatch\n"); + goto err_parse; + } + + /* seccomp and nspids are optional */ + expected_done = (parsed_seccomp ? 11 : 10); + if (kdat.has_nspid) + expected_done += (thread ? 1 : 3); + if (done == expected_done) ret = 0; err_parse: