[CRIU] [PATCH] criu: correctly handle mixed-permission mapped files

Jamie Liu jamieliu at google.com
Tue Apr 1 13:25:03 PDT 2014


An mmaped file is opened O_RDONLY or O_RDWR depending on the permissions
on the first vma dump_task_mm() encounters mapping that file. This means
that if a file has multiple MAP_SHARED mappings, some of which are
read-only and some of which are read-write, and the first encountered
mapping happens to be read-only, the file will be opened with O_RDONLY
during restore, and mmap(PROT_WRITE) will fail with EACCES.

To fix this, allow multiple RegFileEntry messages with the same id;
later RegFileEntry messages update flags in existing file_descs.

Signed-off-by: Jamie Liu <jamieliu at google.com>
---
 cr-dump.c           |  5 ++++-
 files-reg.c         | 35 +++++++++++++++++++++++++++++++++--
 include/files-reg.h |  1 +
 3 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 0111115..a54bacd 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -352,8 +352,11 @@ static int dump_filemap(pid_t pid, struct vma_area *vma_area,
 	else
 		p.flags = O_RDONLY;
 
-	if (fd_id_generate_special(&p.stat, &id))
+	if (fd_id_generate_special(&p.stat, &id)) {
 		ret = dump_one_reg_file(vma_area->vm_file_fd, id, &p);
+	} else if (p.flags == O_RDWR) {
+		ret = update_one_reg_file(id, &p);
+	}
 
 	vma->shmid = id;
 	return ret;
diff --git a/files-reg.c b/files-reg.c
index eccd04e..c4ef13b 100644
--- a/files-reg.c
+++ b/files-reg.c
@@ -573,6 +573,21 @@ int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p)
 	return pb_write_one(rfd, &rfe, PB_REG_FILE);
 }
 
+int update_one_reg_file(u32 id, const struct fd_parms *p)
+{
+	RegFileEntry rfe = REG_FILE_ENTRY__INIT;
+	int rfd;
+
+	rfe.id		= id;
+	rfe.flags	= p->flags;
+	rfe.pos		= p->pos;
+	rfe.fown	= (FownEntry *)&p->fown;
+	rfe.name	= "";
+
+	rfd = fdset_fd(glob_fdset, CR_FD_REG_FILES);
+	return pb_write_one(rfd, &rfe, PB_REG_FILE);
+}
+
 const struct fdtype_ops regfile_dump_ops = {
 	.type		= FD_TYPES__REG,
 	.dump		= dump_one_reg_file,
@@ -775,13 +790,29 @@ struct file_desc *collect_special_file(u32 id)
 static int collect_one_regfile(void *o, ProtobufCMessage *base)
 {
 	struct reg_file_info *rfi = o;
+	struct file_desc *d;
 
 	rfi->rfe = pb_msg(base, RegFileEntry);
 	rfi->path = rfi->rfe->name;
 	rfi->remap = NULL;
 
-	pr_info("Collected [%s] ID %#x\n", rfi->path, rfi->rfe->id);
-	return file_desc_add(&rfi->d, rfi->rfe->id, &reg_desc_ops);
+	d = find_file_desc_raw(reg_desc_ops.type, rfi->rfe->id);
+	if (d) {
+		/* Message contains an update for existing reg_file_info */
+		struct reg_file_info *orig_rfi = container_of(d,
+				struct reg_file_info, d);
+		pr_debug("Updating [%s] ID %#x\n", orig_rfi->path,
+				rfi->rfe->id);
+		/* Open O_RDWR if *any* update requests O_RDWR */
+		if ((rfi->rfe->flags & O_ACCMODE) == O_RDWR) {
+			orig_rfi->rfe->flags &= ~O_ACCMODE;
+			orig_rfi->rfe->flags |= O_RDWR;
+		}
+		return 0;
+	} else {
+		pr_info("Collected [%s] ID %#x\n", rfi->path, rfi->rfe->id);
+		return file_desc_add(&rfi->d, rfi->rfe->id, &reg_desc_ops);
+	}
 }
 
 struct collect_image_info reg_file_cinfo = {
diff --git a/include/files-reg.h b/include/files-reg.h
index b8ffb04..fbf7f4d 100644
--- a/include/files-reg.h
+++ b/include/files-reg.h
@@ -31,6 +31,7 @@ extern int prepare_shared_reg_files(void);
 
 extern const struct fdtype_ops regfile_dump_ops;
 extern int dump_one_reg_file(int lfd, u32 id, const struct fd_parms *p);
+extern int update_one_reg_file(u32 id, const struct fd_parms *p);
 
 extern struct file_remap *lookup_ghost_remap(u32 dev, u32 ino);
 extern void remap_put(struct file_remap *remap);
-- 
1.9.1.423.g4596e3a



More information about the CRIU mailing list