[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, ®_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, ®_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