[CRIU] [crtools-bot for Pavel Emelyanov ] dump: Check for pids reuse at suspend

Cyrill Gorcunov gorcunov at openvz.org
Thu Mar 1 10:31:20 EST 2012


The commit is pushed to "master" and will appear on git://github.com/cyrillos/crtools.git
------>
commit 199e8d824833d3d044eb6756ff25b4a36b51611b
Author: Pavel Emelyanov <xemul at parallels.com>
Date:   Thu Mar 1 19:04:31 2012 +0400

    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: Pavel Emelyanov <xemul at parallels.com>
    Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 cr-dump.c            |   19 +++++++++++++------
 include/crtools.h    |    1 +
 include/proc_parse.h |    1 +
 include/ptrace.h     |    2 +-
 proc_parse.c         |    6 +++---
 ptrace.c             |   21 +++++++++++++--------
 6 files changed, 32 insertions(+), 18 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index e32b597..ffca7bc 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 8ac10f2..ef3f0b3 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 91714e5..383526d 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 2665e76..87f4528 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 a443d6e..d65a11d 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 3abb5e5..f7850bd 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);
-	if (ret < 0) {
-		struct proc_pid_stat_small ps;
-
-		ret = parse_pid_stat_small(pid, &ps);
-		if (ret < 0)
-			return -1;
+	ret2 = parse_pid_stat_small(pid, &ps);
+	if (ret2 < 0)
+		return -1;
 
+	if (ret < 0) {
 		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);


More information about the CRIU mailing list