[CRIU] [PATCH 3/8] proc: Use smaps path for file

Cyrill Gorcunov gorcunov at openvz.org
Mon Oct 5 12:54:32 PDT 2015


From: Pavel Emelyanov <xemul at parallels.com>

Kernel doesn't allow to mess with map_files dir in proc. So,
when doing dump from user process, we should try to get
file path using path from smaps file. To be 100% sure the
path is correct we also get device and ino numbers and
check them agains the stat()-ed path ones.

With this scheme we miss

- mapped packet sockets, but users don't use them
- AIOs, but this can be detected via device, inode and name
- several nested mntns's, but users don't use them
- mapped and unlinked files, but this can be fixed by
  reading file via task's memory (slow, but still)

gorcunov@:

 - For special mappings such as heap, vsyscall, vdso and such
   the kernel provides names rounded by brackets so exit
   from vma_get_mapfile if we meet one and allow the caller
   to handle it.

Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
---
 proc_parse.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 91 insertions(+), 6 deletions(-)

diff --git a/proc_parse.c b/proc_parse.c
index 6fdd840aa8fa..04a1b8f5dcf8 100644
--- a/proc_parse.c
+++ b/proc_parse.c
@@ -241,8 +241,95 @@ static int vma_get_mapfile(char *fname, struct vma_area *vma, DIR *mfd,
 			}
 
 			pr_err("Unknown shit %o (%s)\n", buf.st_mode, fname);
+			return -1;
+		}
+
+		if (errno == EPERM && !opts.aufs) {
+			int fd;
+			dev_t vfi_dev;
+
+			/*
+			 * Kernel prohibits reading map_files for users. The
+			 * best we can do here is fill stat using the information
+			 * from smaps file and ... hope for the better :\
+			 *
+			 * Here we'll miss AIO-s and sockets :(
+			 */
+
+			if (fname[0] == '\0') {
+				/*
+				 * Another bad thing is that kernel first checks
+				 * for permission access to ANY map_files link,
+				 * then checks for its existance. So we have to
+				 * check for file path being empty to "emulate"
+				 * the ENOENT case.
+				 */
+
+				if (vfi->dev_maj != 0 || vfi->dev_min != 0 || vfi->ino != 0) {
+					pr_err("Strange file mapped at %lx [%s]:%d.%d.%ld\n",
+							vma->e->start, fname,
+							vfi->dev_maj, vfi->dev_min, vfi->ino);
+					return -1;
+				}
+
+				return 0;
+			} else if (fname[0] != '/') {
+				/*
+				 * This should be some kind of
+				 * special mapping like [heap], [vdso]
+				 * and such, the caller should take care
+				 * of the @fname and vma status.
+				 */
+				return 0;
+			}
+
+			vfi_dev = makedev(vfi->dev_maj, vfi->dev_min);
+			if (is_anon_shmem_map(vfi_dev)) {
+				if (!(vma->e->flags & MAP_SHARED))
+					return -1;
+
+				vma->e->flags  |= MAP_ANONYMOUS;
+				vma->e->status |= VMA_ANON_SHARED;
+				vma->e->shmid = vfi->ino;
+
+				if (!strncmp(fname, "/SYSV", 5))
+					vma->e->status |= VMA_AREA_SYSVIPC;
+
+				return 0;
+			}
+
+			pr_info("Failed to open map_files/%s, try to go via [%s] path\n", path, fname);
+			fd = open(fname, O_RDONLY);
+			if (fd < 0) {
+				pr_perror("Can't open mapped [%s]", fname);
+				return -1;
+			}
+
+			vma->vmst = xmalloc(sizeof(struct stat));
+			if (!vma->vmst) {
+				close(fd);
+				return -1;
+			}
+
+			if (fstat(fd, vma->vmst) < 0) {
+				pr_perror("Can't stat [%s]\n", fname);
+				close(fd);
+				return -1;
+			}
+
+			if (vma->vmst->st_dev != vfi_dev ||
+					vma->vmst->st_ino != vfi->ino) {
+				pr_err("Failed to resolve mapping %lx filename\n",
+						vma->e->start);
+				close(fd);
+				return -1;
+			}
+
+			vma->vm_file_fd = fd;
+			return 0;
 		}
 
+		pr_perror("Can't open map_files");
 		return -1;
 	}
 
@@ -520,8 +607,7 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list)
 		goto err;
 
 	while (1) {
-		int num;
-		char file_path[32];
+		int num, path_off;
 		bool eof;
 		char *str;
 
@@ -561,10 +647,9 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list)
 		if (!vma_area)
 			goto err;
 
-		memzero(file_path, sizeof(file_path));
-		num = sscanf(str, "%lx-%lx %c%c%c%c %lx %x:%x %lu %31s",
+		num = sscanf(str, "%lx-%lx %c%c%c%c %lx %x:%x %lu %n",
 			     &start, &end, &r, &w, &x, &s, &pgoff,
-			     &vfi.dev_maj, &vfi.dev_min, &vfi.ino, file_path);
+			     &vfi.dev_maj, &vfi.dev_min, &vfi.ino, &path_off);
 		if (num < 10) {
 			pr_err("Can't parse: %s\n", str);
 			goto err;
@@ -591,7 +676,7 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list)
 			goto err;
 		}
 
-		if (handle_vma(pid, vma_area, file_path, map_files_dir,
+		if (handle_vma(pid, vma_area, str + path_off, map_files_dir,
 					&vfi, &prev_vfi, vma_area_list))
 			goto err;
 	}
-- 
2.4.3



More information about the CRIU mailing list