[CRIU] [PATCH 5/6] restorer: Workaround ASan false-positives after clone().

Andrey Ryabinin aryabinin at virtuozzo.com
Mon Feb 6 02:14:16 PST 2017


ASan doesn't play nicely with clone if we use current stack for
child task. ASan puts local variables on the fake stack
to catch use-after-return bug:
	https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn#algorithm

So it's become easy to overflow this fake stack frame in cloned child.
We need a real stack for clone().

To workaround this we add clone_noasan() not-instrumented wrapper for
clone(). Unfortunately we can't use __attrbute__((no_sanitize_addresss))
for this because of bug in GCC > 6:
	https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69863

So the only way is to put this wrapper in separate non-instrumented file.

Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
 criu/Makefile.crtools       |  2 ++
 criu/clone-noasan.c         | 33 +++++++++++++++++++++++++++++++++
 criu/cr-restore.c           | 12 +++---------
 criu/include/clone-noasan.h |  6 ++++++
 4 files changed, 44 insertions(+), 9 deletions(-)
 create mode 100644 criu/clone-noasan.c
 create mode 100644 criu/include/clone-noasan.h

diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools
index 8188129..e095d01 100644
--- a/criu/Makefile.crtools
+++ b/criu/Makefile.crtools
@@ -1,5 +1,6 @@
 ccflags-y		+= -iquote criu/$(ARCH)
 ccflags-y		+= $(COMPEL_UAPI_INCLUDES)
+CFLAGS_REMOVE_clone-noasan.o += $(CFLAGS-ASAN)
 
 obj-y			+= action-scripts.o
 obj-y			+= external.o
@@ -8,6 +9,7 @@ obj-y			+= bfd.o
 obj-y			+= bitmap.o
 obj-y			+= cgroup.o
 obj-y			+= cgroup-props.o
+obj-y			+= clone-noasan.o
 obj-y			+= cr-check.o
 obj-y			+= cr-dedup.o
 obj-y			+= cr-dump.o
diff --git a/criu/clone-noasan.c b/criu/clone-noasan.c
new file mode 100644
index 0000000..c5171b1
--- /dev/null
+++ b/criu/clone-noasan.c
@@ -0,0 +1,33 @@
+#include <sched.h>
+#include "common/compiler.h"
+
+/*
+ * ASan doesn't play nicely with clone if we use current stack for
+ * child task. ASan puts local variables on the fake stack
+ * to catch use-after-return bug:
+ *         https://github.com/google/sanitizers/wiki/AddressSanitizerUseAfterReturn#algorithm
+ *
+ * So it's become easy to overflow this fake stack frame in cloned child.
+ * We need a real stack for clone().
+ *
+ * To workaround this we add clone_noasan() not-instrumented wrapper for
+ * clone(). Unfortunately we can't use __attrbute__((no_sanitize_addresss))
+ * for this because of bug in GCC > 6:
+ *         https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69863
+ *
+ * So the only way is to put this wrapper in separate non-instrumented file
+ */
+int clone_noasan(int (*fn)(void *), int flags, void *arg)
+{
+	/*
+	 * Reserve some space for clone() to locate arguments
+	 * and retcode in this place
+	 */
+	char stack[128] __stack_aligned__;
+	char *stack_ptr = &stack[sizeof(stack)];
+	int ret;
+
+	ret = clone(fn, stack_ptr, flags, arg);
+	return ret;
+}
+
diff --git a/criu/cr-restore.c b/criu/cr-restore.c
index ee6b848..a5743fb 100644
--- a/criu/cr-restore.c
+++ b/criu/cr-restore.c
@@ -27,6 +27,7 @@
 #include <compel/ptrace.h>
 #include "common/compiler.h"
 
+#include "clone-noasan.h"
 #include "cr_options.h"
 #include "servicefd.h"
 #include "image.h"
@@ -914,12 +915,6 @@ static int restore_one_task(int pid, CoreEntry *core)
 
 /* All arguments should be above stack, because it grows down */
 struct cr_clone_arg {
-	/*
-	 * Reserve some space for clone() to locate arguments
-	 * and retcode in this place
-	 */
-	char stack[128] __stack_aligned__;
-	char stack_ptr[0];
 	struct pstree_item *item;
 	unsigned long clone_flags;
 	int fd;
@@ -1042,9 +1037,8 @@ static inline int fork_with_pid(struct pstree_item *item)
 	 * The cgroup namespace is also unshared explicitly in the
 	 * move_in_cgroup(), so drop this flag here as well.
 	 */
-	ret = clone(restore_task_with_children, ca.stack_ptr,
-		    (ca.clone_flags & ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, &ca);
-
+	ret = clone_noasan(restore_task_with_children,
+			(ca.clone_flags & ~(CLONE_NEWNET | CLONE_NEWCGROUP)) | SIGCHLD, &ca);
 	if (ret < 0) {
 		pr_perror("Can't fork for %d", pid);
 		goto err_unlock;
diff --git a/criu/include/clone-noasan.h b/criu/include/clone-noasan.h
new file mode 100644
index 0000000..8ef75fa
--- /dev/null
+++ b/criu/include/clone-noasan.h
@@ -0,0 +1,6 @@
+#ifndef __CR_CLONE_NOASAN_H__
+#define __CR_CLONE_NOASAN_H__
+
+int clone_noasan(int (*fn)(void *), int flags, void *arg);
+
+#endif /* __CR_CLONE_NOASAN_H__ */
-- 
2.10.2



More information about the CRIU mailing list