Commit 199e8d82 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Cyrill Gorcunov

dump: Check for pids reuse at suspend

While we try to seize task it can die and give its pid to
somebody else. This can break pstree consistency. Check for
parent being valid after task is seized.
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
Signed-off-by: 's avatarCyrill Gorcunov <gorcunov@openvz.org>
parent f8a18edd
...@@ -848,7 +848,7 @@ static int seize_threads(struct pstree_item *item) ...@@ -848,7 +848,7 @@ static int seize_threads(struct pstree_item *item)
continue; continue;
pr_info("\tSeizing %d's %d thread\n", item->pid, item->threads[i]); 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) if (ret < 0)
goto err; goto err;
...@@ -887,7 +887,7 @@ static int collect_threads(struct pstree_item *item) ...@@ -887,7 +887,7 @@ static int collect_threads(struct pstree_item *item)
return ret; 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; int ret;
struct pstree_item *item; struct pstree_item *item;
...@@ -896,12 +896,13 @@ static struct pstree_item *collect_task(pid_t pid, struct list_head *list) ...@@ -896,12 +896,13 @@ static struct pstree_item *collect_task(pid_t pid, struct list_head *list)
if (!item) if (!item)
goto err; goto err;
ret = seize_task(pid); ret = seize_task(pid, ppid);
if (ret < 0) if (ret < 0)
goto err_free; goto err_free;
pr_info("Seized task %d, state %d\n", pid, ret); pr_info("Seized task %d, state %d\n", pid, ret);
item->pid = pid; item->pid = pid;
item->ppid = ppid;
item->state = ret; item->state = ret;
ret = collect_threads(item); ret = collect_threads(item);
...@@ -932,13 +933,14 @@ err: ...@@ -932,13 +933,14 @@ err:
return NULL; 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; struct pstree_item *item;
int i; int i;
pr_info("Collecting tasks starting from %d\n", pid); 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) if (item == NULL)
return -1; return -1;
...@@ -946,12 +948,17 @@ static int collect_pstree(pid_t pid, struct list_head *pstree_list, int leader_o ...@@ -946,12 +948,17 @@ static int collect_pstree(pid_t pid, struct list_head *pstree_list, int leader_o
return 0; return 0;
for (i = 0; i < item->nr_children; i++) 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 -1;
return 0; 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) static int dump_pstree(pid_t pid, struct list_head *pstree_list, struct cr_fdset *cr_fdset)
{ {
struct pstree_item *item; struct pstree_item *item;
......
...@@ -150,6 +150,7 @@ struct vma_area { ...@@ -150,6 +150,7 @@ struct vma_area {
struct pstree_item { struct pstree_item {
struct list_head list; struct list_head list;
pid_t pid; /* leader pid */ pid_t pid; /* leader pid */
pid_t ppid;
int state; /* TASK_XXX constants */ int state; /* TASK_XXX constants */
u32 nr_children; /* number of children */ u32 nr_children; /* number of children */
u32 nr_threads; /* number of threads */ u32 nr_threads; /* number of threads */
......
...@@ -8,6 +8,7 @@ struct proc_pid_stat_small { ...@@ -8,6 +8,7 @@ struct proc_pid_stat_small {
int pid; int pid;
char comm[PROC_TASK_COMM_LEN]; char comm[PROC_TASK_COMM_LEN];
char state; char state;
int ppid;
}; };
struct proc_pid_stat { struct proc_pid_stat {
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#define PTRACE_O_TRACEVFORKDONE 0x00000020 #define PTRACE_O_TRACEVFORKDONE 0x00000020
#define PTRACE_O_TRACEEXIT 0x00000040 #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 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_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); extern int ptrace_poke_area(pid_t pid, void *src, void *addr, long bytes);
......
...@@ -190,10 +190,10 @@ int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s) ...@@ -190,10 +190,10 @@ int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s)
return -1; return -1;
memset(s, 0, sizeof(*s)); memset(s, 0, sizeof(*s));
n = fscanf(f, "%d " PROC_TASK_COMM_LEN_FMT " %c", n = fscanf(f, "%d " PROC_TASK_COMM_LEN_FMT " %c %d",
&s->pid, s->comm, &s->state); &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); pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
return -1; return -1;
} }
......
...@@ -40,21 +40,20 @@ int unseize_task(pid_t pid, enum cr_task_state st) ...@@ -40,21 +40,20 @@ int unseize_task(pid_t pid, enum cr_task_state st)
* up with someone else. * up with someone else.
*/ */
int seize_task(pid_t pid) int seize_task(pid_t pid, pid_t ppid)
{ {
siginfo_t si; siginfo_t si;
int status; int status;
int ret; int ret, ret2;
struct proc_pid_stat_small ps;
ret = ptrace(PTRACE_SEIZE, pid, NULL, ret = ptrace(PTRACE_SEIZE, pid, NULL,
(void *)(unsigned long)PTRACE_SEIZE_DEVEL); (void *)(unsigned long)PTRACE_SEIZE_DEVEL);
if (ret < 0) { ret2 = parse_pid_stat_small(pid, &ps);
struct proc_pid_stat_small ps; if (ret2 < 0)
return -1;
ret = parse_pid_stat_small(pid, &ps);
if (ret < 0)
return -1;
if (ret < 0) {
if (ps.state != 'Z') { if (ps.state != 'Z') {
pr_err("Unseizeable non-zombie %d found, state %c\n", pr_err("Unseizeable non-zombie %d found, state %c\n",
pid, ps.state); pid, ps.state);
...@@ -64,6 +63,12 @@ int seize_task(pid_t pid) ...@@ -64,6 +63,12 @@ int seize_task(pid_t pid)
return TASK_DEAD; 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); ret = ptrace(PTRACE_INTERRUPT, pid, NULL, NULL);
if (ret < 0) { if (ret < 0) {
pr_perror("SEIZE %d: can't interrupt task", pid); pr_perror("SEIZE %d: can't interrupt task", pid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment