[CRIU] [PATCH 1/2] kerndat: Detect if we have guard page mangle in procfs output

Cyrill Gorcunov gorcunov at openvz.org
Mon Jun 26 23:55:28 MSK 2017


In vanilla kernel commit 1be7107fbe18eed3e319a6c3e83c78254b693acb
show_map_vma() no longer report PAGE_SIZE. Detect it with
simple test and remember in kdat settings.

Suggested-by: Oleg Nesterov <oleg at redhat.com>
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 criu/include/kerndat.h |  1 +
 criu/kerndat.c         | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 77 insertions(+)

diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 7946cb9ae712..2035f793298b 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -66,6 +66,7 @@ struct kerndat_s {
 	struct vdso_symtable	vdso_sym_compat;
 #endif
 #endif
+	bool stack_guard_gap_hidden;
 };
 
 extern struct kerndat_s kdat;
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 593be5a5ff47..cdbef1299f18 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -712,6 +712,80 @@ int kerndat_has_pid_for_children_ns(void)
 	return 0;
 }
 
+static int kerndat_detect_stack_guard_gap(void)
+{
+	int num, ret = -1, detected = 0;
+	unsigned long start, end;
+	char r, w, x, s;
+	char buf[1024];
+	FILE *maps;
+	void *mem;
+
+	mem = mmap(NULL, (3ul << 20), PROT_READ | PROT_WRITE,
+		   MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
+	if (mem == MAP_FAILED) {
+		pr_perror("Can't mmap stack area");
+		return -1;
+	}
+	munmap(mem, (3ul << 20));
+
+	mem = mmap(mem + (2ul << 20), (1ul << 20), PROT_READ | PROT_WRITE,
+		   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
+	if (mem == MAP_FAILED) {
+		pr_perror("Can't mmap stack area");
+		return -1;
+	}
+
+	maps = fopen("/proc/self/maps", "r");
+	if (maps == NULL) {
+		munmap(mem, 4096);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), maps)) {
+		num = sscanf(buf, "%lx-%lx %c%c%c%c",
+			     &start, &end, &r, &w, &x, &s);
+		if (num < 6) {
+			pr_err("Can't parse: %s\n", buf);
+			goto err;
+		}
+
+		/*
+		 * When reading /proc/$pid/[s]maps the
+		 * start/end addresses migh be cutted off
+		 * with PAGE_SIZE on kernels prior 4.12
+		 * (see kernel commit 1be7107fbe18ee).
+		 *
+		 * Same time there was semi-complete
+		 * patch released which hitted a number
+		 * of repos (Ubuntu, Fedora) where instead
+		 * of PAGE_SIZE the 1M gap is cutted off.
+		 */
+		if (start == (unsigned long)mem) {
+			kdat.stack_guard_gap_hidden = false;
+			detected = 1;
+			break;
+		} else if (start == ((unsigned long)mem + (1ul << 20))) {
+			pr_warn("Unsupported stack guard detected, confused but continue\n");
+			kdat.stack_guard_gap_hidden = true;
+			detected = 1;
+			break;
+		} else if (start == ((unsigned long)mem + PAGE_SIZE)) {
+			kdat.stack_guard_gap_hidden = true;
+			detected = 1;
+			break;
+		}
+	}
+
+	if (detected)
+		ret = 0;
+
+err:
+	munmap(mem, (1ul << 20));
+	fclose(maps);
+	return ret;
+}
+
 #define KERNDAT_CACHE_FILE	KDAT_RUNDIR"/criu.kdat"
 #define KERNDAT_CACHE_FILE_TMP	KDAT_RUNDIR"/.criu.kdat"
 
@@ -908,6 +982,8 @@ int kerndat_init(void)
 	/* Needs kdat.compat_cr filled before */
 	if (!ret)
 		ret = kerndat_vdso_fill_symtable();
+	if (!ret)
+		ret = kerndat_detect_stack_guard_gap();
 
 	kerndat_lsm();
 	kerndat_mmap_min_addr();
-- 
2.7.5



More information about the CRIU mailing list