diff --git a/cr-dump.c b/cr-dump.c index e32b597c2..ffca7bc08 100644 --- a/cr-dump.c +++ b/cr-dump.c @@ -848,7 +848,7 @@ static int seize_threads(struct pstree_item *item) continue; pr_info("\tSeizing %d's %d thread\n", item->pid, item->threads[i]); - ret = seize_task(item->threads[i]); + ret = seize_task(item->threads[i], item->ppid); if (ret < 0) goto err; @@ -887,7 +887,7 @@ static int collect_threads(struct pstree_item *item) return ret; } -static struct pstree_item *collect_task(pid_t pid, struct list_head *list) +static struct pstree_item *collect_task(pid_t pid, pid_t ppid, struct list_head *list) { int ret; struct pstree_item *item; @@ -896,12 +896,13 @@ static struct pstree_item *collect_task(pid_t pid, struct list_head *list) if (!item) goto err; - ret = seize_task(pid); + ret = seize_task(pid, ppid); if (ret < 0) goto err_free; pr_info("Seized task %d, state %d\n", pid, ret); item->pid = pid; + item->ppid = ppid; item->state = ret; ret = collect_threads(item); @@ -932,13 +933,14 @@ err: return NULL; } -static int collect_pstree(pid_t pid, struct list_head *pstree_list, int leader_only) +static int collect_subtree(pid_t pid, pid_t ppid, struct list_head *pstree_list, + int leader_only) { struct pstree_item *item; int i; pr_info("Collecting tasks starting from %d\n", pid); - item = collect_task(pid, pstree_list); + item = collect_task(pid, ppid, pstree_list); if (item == NULL) return -1; @@ -946,12 +948,17 @@ static int collect_pstree(pid_t pid, struct list_head *pstree_list, int leader_o return 0; for (i = 0; i < item->nr_children; i++) - if (collect_pstree(item->children[i], pstree_list, 0) < 0) + if (collect_subtree(item->children[i], item->pid, pstree_list, 0) < 0) return -1; return 0; } +static int collect_pstree(pid_t pid, struct list_head *pstree_list, int leader_only) +{ + return collect_subtree(pid, -1, pstree_list, leader_only); +} + static int dump_pstree(pid_t pid, struct list_head *pstree_list, struct cr_fdset *cr_fdset) { struct pstree_item *item; diff --git a/include/crtools.h b/include/crtools.h index 8ac10f2ec..ef3f0b30d 100644 --- a/include/crtools.h +++ b/include/crtools.h @@ -150,6 +150,7 @@ struct vma_area { struct pstree_item { struct list_head list; pid_t pid; /* leader pid */ + pid_t ppid; int state; /* TASK_XXX constants */ u32 nr_children; /* number of children */ u32 nr_threads; /* number of threads */ diff --git a/include/proc_parse.h b/include/proc_parse.h index 91714e5a1..383526d8c 100644 --- a/include/proc_parse.h +++ b/include/proc_parse.h @@ -8,6 +8,7 @@ struct proc_pid_stat_small { int pid; char comm[PROC_TASK_COMM_LEN]; char state; + int ppid; }; struct proc_pid_stat { diff --git a/include/ptrace.h b/include/ptrace.h index 2665e76b1..87f452871 100644 --- a/include/ptrace.h +++ b/include/ptrace.h @@ -32,7 +32,7 @@ #define PTRACE_O_TRACEVFORKDONE 0x00000020 #define PTRACE_O_TRACEEXIT 0x00000040 -extern int seize_task(pid_t pid); +extern int seize_task(pid_t pid, pid_t ppid); extern int unseize_task(pid_t pid, enum cr_task_state st); extern int ptrace_peek_area(pid_t pid, void *dst, void *addr, long bytes); extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes); diff --git a/proc_parse.c b/proc_parse.c index a443d6e03..d65a11d8a 100644 --- a/proc_parse.c +++ b/proc_parse.c @@ -190,10 +190,10 @@ int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s) return -1; memset(s, 0, sizeof(*s)); - n = fscanf(f, "%d " PROC_TASK_COMM_LEN_FMT " %c", - &s->pid, s->comm, &s->state); + n = fscanf(f, "%d " PROC_TASK_COMM_LEN_FMT " %c %d", + &s->pid, s->comm, &s->state, &s->ppid); - if (n < 3) { + if (n < 4) { pr_err("Parsing %d's stat failed (#fields do not match)\n", pid); return -1; } diff --git a/ptrace.c b/ptrace.c index 3abb5e572..f7850bd26 100644 --- a/ptrace.c +++ b/ptrace.c @@ -40,21 +40,20 @@ int unseize_task(pid_t pid, enum cr_task_state st) * up with someone else. */ -int seize_task(pid_t pid) +int seize_task(pid_t pid, pid_t ppid) { siginfo_t si; int status; - int ret; + int ret, ret2; + struct proc_pid_stat_small ps; ret = ptrace(PTRACE_SEIZE, pid, NULL, (void *)(unsigned long)PTRACE_SEIZE_DEVEL); + ret2 = parse_pid_stat_small(pid, &ps); + if (ret2 < 0) + return -1; + if (ret < 0) { - struct proc_pid_stat_small ps; - - ret = parse_pid_stat_small(pid, &ps); - if (ret < 0) - return -1; - if (ps.state != 'Z') { pr_err("Unseizeable non-zombie %d found, state %c\n", pid, ps.state); @@ -64,6 +63,12 @@ int seize_task(pid_t pid) return TASK_DEAD; } + if ((ppid != -1) && (ps.ppid != ppid)) { + pr_err("Task pid reused while suspending (%d: %d -> %d)\n", + pid, ppid, ps.ppid); + goto err; + } + ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL); if (ret < 0) { pr_perror("SEIZE %d: can't interrupt task", pid);