[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