[CRIU] [PATCH 1/4] kerndat: Read anon shmem dev via maps

Pavel Emelyanov xemul at parallels.com
Thu Sep 24 15:02:26 PDT 2015


Kernel doesn't allow to read /proc/pid/map_files. This file
is used to get pseudo device for anon shmem mappings, but
this info can be get by scanning /proc/self/maps file.

This works slower, but still.

Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
---
 kerndat.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 62 insertions(+), 6 deletions(-)

diff --git a/kerndat.c b/kerndat.c
index e57c6fd..8eebe88 100644
--- a/kerndat.c
+++ b/kerndat.c
@@ -46,11 +46,51 @@ struct kerndat_s kdat = {
  * from real tmpfs files maps.
  */
 
+static int parse_self_maps(unsigned long vm_start, dev_t *device)
+{
+	FILE *maps;
+	char buf[1024];
+
+	maps = fopen_proc(PROC_SELF, "maps");
+	if (maps == NULL) {
+		pr_perror("Can't open self maps");
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), maps) != NULL) {
+		char *end, *aux;
+		unsigned long start;
+		int maj, min;
+
+		start = strtoul(buf, &end, 16);
+		if (vm_start > start)
+			continue;
+		if (vm_start < start)
+			break;
+
+		/* It's ours */
+		aux = strchr(end + 1, ' '); /* end prot */
+		aux = strchr(aux + 1, ' '); /* prot pgoff */
+		aux = strchr(aux + 1, ' '); /* pgoff dev */
+
+		maj = strtoul(aux + 1, &end, 16);
+		min = strtoul(end + 1, NULL, 16);
+
+		*device = makedev(maj, min);
+		fclose(maps);
+		return 0;
+	}
+
+	fclose(maps);
+	return -1;
+}
+
 static int kerndat_get_shmemdev(void)
 {
 	void *map;
 	char maps[128];
 	struct stat buf;
+	dev_t dev;
 
 	map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
 			MAP_SHARED | MAP_ANONYMOUS, 0, 0);
@@ -62,16 +102,32 @@ static int kerndat_get_shmemdev(void)
 	sprintf(maps, "/proc/self/map_files/%lx-%lx",
 			(unsigned long)map, (unsigned long)map + page_size());
 	if (stat(maps, &buf) < 0) {
-		munmap(map, PAGE_SIZE);
-		pr_perror("Can't stat self map_files");
-		return -1;
-	}
+		int e = errno;
+		if (errno == EPERM) {
+			/*
+			 * Kernel disables messing with map_files.
+			 * OK, let's go the slower route.
+			 */
+
+			if (parse_self_maps((unsigned long)map, &dev) < 0) {
+				pr_err("Can't read self maps\n");
+				goto err;
+			}
+		} else {
+			pr_perror("Can't stat self map_files %d", e);
+			goto err;
+		}
+	} else
+		dev = buf.st_dev;
 
 	munmap(map, PAGE_SIZE);
-
-	kdat.shmem_dev = buf.st_dev;
+	kdat.shmem_dev = dev;
 	pr_info("Found anon-shmem device at %"PRIx64"\n", kdat.shmem_dev);
 	return 0;
+
+err:
+	munmap(map, PAGE_SIZE);
+	return -1;
 }
 
 static dev_t get_host_dev(unsigned int which)
-- 
1.9.3




More information about the CRIU mailing list