cf68a0
From 8a4a164f3e33be9b2d28d54fe430e92f40626054 Mon Sep 17 00:00:00 2001
cf68a0
From: Cyrill Gorcunov <gorcunov@openvz.org>
cf68a0
Date: Mon, 26 Jun 2017 23:55:28 +0300
cf68a0
Subject: [PATCH 1/2] kerndat: Detect if we have guard page mangle in procfs
cf68a0
 output
cf68a0
cf68a0
In vanilla kernel commit 1be7107fbe18eed3e319a6c3e83c78254b693acb
cf68a0
show_map_vma() no longer report PAGE_SIZE. Detect it with
cf68a0
simple test and remember in kdat settings.
cf68a0
cf68a0
Suggested-by: Oleg Nesterov <oleg@redhat.com>
cf68a0
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
cf68a0
Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
cf68a0
---
cf68a0
 criu/include/kerndat.h |  1 +
cf68a0
 criu/kerndat.c         | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
cf68a0
 2 files changed, 77 insertions(+)
cf68a0
cf68a0
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
cf68a0
index ba8c10da7..891cbdd41 100644
cf68a0
--- a/criu/include/kerndat.h
cf68a0
+++ b/criu/include/kerndat.h
cf68a0
@@ -44,6 +44,7 @@ struct kerndat_s {
cf68a0
 	unsigned int has_xtlocks;
cf68a0
 	unsigned long mmap_min_addr;
cf68a0
 	bool has_tcp_half_closed;
cf68a0
+	bool stack_guard_gap_hidden;
cf68a0
 };
cf68a0
 
cf68a0
 extern struct kerndat_s kdat;
cf68a0
diff --git a/criu/kerndat.c b/criu/kerndat.c
cf68a0
index 354fb672b..80ec58bcf 100644
cf68a0
--- a/criu/kerndat.c
cf68a0
+++ b/criu/kerndat.c
cf68a0
@@ -563,6 +563,80 @@ int kerndat_tcp_repair(void)
cf68a0
 	return exit_code;
cf68a0
 }
cf68a0
 
cf68a0
+static int kerndat_detect_stack_guard_gap(void)
cf68a0
+{
cf68a0
+	int num, ret = -1, detected = 0;
cf68a0
+	unsigned long start, end;
cf68a0
+	char r, w, x, s;
cf68a0
+	char buf[1024];
cf68a0
+	FILE *maps;
cf68a0
+	void *mem;
cf68a0
+
cf68a0
+	mem = mmap(NULL, (3ul << 20), PROT_READ | PROT_WRITE,
cf68a0
+		   MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
cf68a0
+	if (mem == MAP_FAILED) {
cf68a0
+		pr_perror("Can't mmap stack area");
cf68a0
+		return -1;
cf68a0
+	}
cf68a0
+	munmap(mem, (3ul << 20));
cf68a0
+
cf68a0
+	mem = mmap(mem + (2ul << 20), (1ul << 20), PROT_READ | PROT_WRITE,
cf68a0
+		   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0);
cf68a0
+	if (mem == MAP_FAILED) {
cf68a0
+		pr_perror("Can't mmap stack area");
cf68a0
+		return -1;
cf68a0
+	}
cf68a0
+
cf68a0
+	maps = fopen("/proc/self/maps", "r");
cf68a0
+	if (maps == NULL) {
cf68a0
+		munmap(mem, 4096);
cf68a0
+		return -1;
cf68a0
+	}
cf68a0
+
cf68a0
+	while (fgets(buf, sizeof(buf), maps)) {
cf68a0
+		num = sscanf(buf, "%lx-%lx %c%c%c%c",
cf68a0
+			     &start, &end, &r, &w, &x, &s);
cf68a0
+		if (num < 6) {
cf68a0
+			pr_err("Can't parse: %s\n", buf);
cf68a0
+			goto err;
cf68a0
+		}
cf68a0
+
cf68a0
+		/*
cf68a0
+		 * When reading /proc/$pid/[s]maps the
cf68a0
+		 * start/end addresses migh be cutted off
cf68a0
+		 * with PAGE_SIZE on kernels prior 4.12
cf68a0
+		 * (see kernel commit 1be7107fbe18ee).
cf68a0
+		 *
cf68a0
+		 * Same time there was semi-complete
cf68a0
+		 * patch released which hitted a number
cf68a0
+		 * of repos (Ubuntu, Fedora) where instead
cf68a0
+		 * of PAGE_SIZE the 1M gap is cutted off.
cf68a0
+		 */
cf68a0
+		if (start == (unsigned long)mem) {
cf68a0
+			kdat.stack_guard_gap_hidden = false;
cf68a0
+			detected = 1;
cf68a0
+			break;
cf68a0
+		} else if (start == ((unsigned long)mem + (1ul << 20))) {
cf68a0
+			pr_warn("Unsupported stack guard detected, confused but continue\n");
cf68a0
+			kdat.stack_guard_gap_hidden = true;
cf68a0
+			detected = 1;
cf68a0
+			break;
cf68a0
+		} else if (start == ((unsigned long)mem + PAGE_SIZE)) {
cf68a0
+			kdat.stack_guard_gap_hidden = true;
cf68a0
+			detected = 1;
cf68a0
+			break;
cf68a0
+		}
cf68a0
+	}
cf68a0
+
cf68a0
+	if (detected)
cf68a0
+		ret = 0;
cf68a0
+
cf68a0
+err:
cf68a0
+	munmap(mem, (1ul << 20));
cf68a0
+	fclose(maps);
cf68a0
+	return ret;
cf68a0
+}
cf68a0
+
cf68a0
 int kerndat_init(void)
cf68a0
 {
cf68a0
 	int ret;
cf68a0
@@ -676,6 +750,8 @@ int kerndat_init(void)
cf68a0
 		ret = kerndat_iptables_has_xtlocks();
cf68a0
 	if (!ret)
cf68a0
 		ret = kerndat_tcp_repair();
cf68a0
+	if (!ret)
cf68a0
+		ret = kerndat_detect_stack_guard_gap();
cf68a0
 
cf68a0
 	kerndat_lsm();
cf68a0
 	kerndat_mmap_min_addr();
cf68a0
-- 
cf68a0
2.13.0
cf68a0