lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1242968132-1044-19-git-send-email-adobriyan@gmail.com>
Date:	Fri, 22 May 2009 08:55:13 +0400
From:	Alexey Dobriyan <adobriyan@...il.com>
To:	akpm@...ux-foundation.org
Cc:	linux-kernel@...r.kernel.org,
	containers@...ts.linux-foundation.org,
	torvalds@...ux-foundation.org, xemul@...allels.com,
	orenl@...columbia.edu, serue@...ibm.com, dave@...ux.vnet.ibm.com,
	mingo@...e.hu, Alexey Dobriyan <adobriyan@...il.com>
Subject: [PATCH 19/38] C/R: multiple tasks

Restore task hierarchy wrt ->real_parent.

First thing soon-to-be-restored task does after birth is to find
->real_parent and glue itself to parent lists.

For this parent is dumped first and restored first, so that at the time
child starts restoration, parent is already up and running as task_struct,
and we get cheap loop-prevention check.

Signed-off-by: Alexey Dobriyan <adobriyan@...il.com>
---
 include/linux/kstate-image.h  |    2 +
 kernel/kstate/kstate-object.c |    3 +-
 kernel/kstate/kstate-task.c   |   53 +++++++++++++++++++++++++++++++++++-----
 3 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/include/linux/kstate-image.h b/include/linux/kstate-image.h
index ac3c81d..348f59f 100644
--- a/include/linux/kstate-image.h
+++ b/include/linux/kstate-image.h
@@ -60,6 +60,8 @@ struct kstate_object_header {
 struct kstate_image_task_struct {
 	struct kstate_object_header hdr;
 
+	kstate_ref_t	ref_real_parent;
+
 	kstate_ref_t	ref_mm;
 
 	__u8		comm[16];
diff --git a/kernel/kstate/kstate-object.c b/kernel/kstate/kstate-object.c
index f9f2f33..60ba70d 100644
--- a/kernel/kstate/kstate-object.c
+++ b/kernel/kstate/kstate-object.c
@@ -25,7 +25,8 @@ int kstate_collect_object(struct kstate_context *ctx, void *p, enum kstate_conte
 	obj->o_ref.pos = 0;	/* not yet dumped */
 	obj->o_ref.id = 0;	/* not yet assigned */
 	obj->o_obj = p;
-	list_add(&obj->o_list, &ctx->obj[type]);
+	/* task_struct collecting relies on "_tail" part. */
+	list_add_tail(&obj->o_list, &ctx->obj[type]);
 
 	switch (type) {
 	case KSTATE_CTX_FILE:
diff --git a/kernel/kstate/kstate-task.c b/kernel/kstate/kstate-task.c
index aec97c2..4f48c32 100644
--- a/kernel/kstate/kstate-task.c
+++ b/kernel/kstate/kstate-task.c
@@ -11,11 +11,6 @@
 static int check_task_struct(struct task_struct *tsk)
 {
 	read_lock_irq(&tasklist_lock);
-	if (!list_empty(&tsk->children)) {
-		read_unlock_irq(&tasklist_lock);
-		WARN_ON(1);
-		return -EINVAL;
-	}
 	if (!list_empty(&tsk->thread_group)) {
 		read_unlock_irq(&tasklist_lock);
 		WARN_ON(1);
@@ -74,8 +69,32 @@ static int collect_task_struct(struct kstate_context *ctx, struct task_struct *t
 
 int kstate_collect_all_task_struct(struct kstate_context *ctx)
 {
+	struct kstate_object *obj;
+	int rv;
+
 	/* Seed task list. */
-	return collect_task_struct(ctx, ctx->init_tsk);
+	rv = collect_task_struct(ctx, ctx->init_tsk);
+	if (rv < 0)
+		return rv;
+	/*
+	 * Children are added after parent as iteration goes on:
+	 * - parent is dumped before child, child knows position of parent's
+	 *   image and can reference it,
+	 * - task_struct restore is done in the same order: parent first.
+	 *   This is cheap loop prevention wrt "->real_parent": if real_parent
+	 *   reference can't be resolved at the time ->real_parent rewrite is
+	 *   done, image is malformed.
+	 */
+	for_each_kstate_object(ctx, obj, KSTATE_CTX_TASK_STRUCT) {
+		struct task_struct *tsk = obj->o_obj, *child;
+
+		list_for_each_entry(child, &tsk->children, sibling) {
+			rv = collect_task_struct(ctx, child);
+			if (rv < 0)
+				return rv;
+		}
+	}
+	return 0;
 }
 
 static int dump_task_struct(struct kstate_context *ctx, struct kstate_object *obj)
@@ -91,6 +110,13 @@ static int dump_task_struct(struct kstate_context *ctx, struct kstate_object *ob
 	if (!i)
 		return -ENOMEM;
 
+	tmp = find_kstate_obj_by_ptr(ctx, tsk->real_parent, KSTATE_CTX_TASK_STRUCT);
+	if (tmp)
+		i->ref_real_parent = tmp->o_ref;
+	else
+		/* Root of hierarchy to be checkpointed. */
+		i->ref_real_parent = KSTATE_REF_UNDEF;
+
 	tmp = find_kstate_obj_by_ptr(ctx, tsk->mm, KSTATE_CTX_MM_STRUCT);
 	i->ref_mm = tmp->o_ref;
 
@@ -206,7 +232,20 @@ static int task_struct_restorer(void *_tsk_ctx)
 	pr_debug("%s: ENTER tsk %p/%s\n", __func__, tsk, tsk->comm);
 
 	write_lock_irq(&tasklist_lock);
-	real_parent = ctx->init_tsk->nsproxy->pid_ns->child_reaper;
+	if (kstate_ref_undefined(&i->ref_real_parent))
+		real_parent = ctx->init_tsk->nsproxy->pid_ns->child_reaper;
+	else {
+		struct kstate_object *tmp;
+
+		/* Parent as task_struct should be restored already. */
+		tmp = find_kstate_obj_by_ref(ctx, &i->ref_real_parent, KSTATE_CTX_TASK_STRUCT);
+		if (!tmp) {
+			write_unlock_irq(&tasklist_lock);
+			rv = -EINVAL;
+			goto out;
+		}
+		real_parent = tmp->o_obj;
+	}
 	tsk->real_parent = tsk->parent = real_parent;
 	list_move_tail(&tsk->sibling, &tsk->real_parent->sibling);
 	write_unlock_irq(&tasklist_lock);
-- 
1.5.6.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ