Commit efe594f8 authored by Jamie Liu's avatar Jamie Liu Committed by Pavel Emelyanov

criu: fix filemap open permissions

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
causes two problems:

1. 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 O_RDONLY
   during restore, and mmap(PROT_WRITE) will fail with EACCES, causing
   the restore to fail.

2. If a file is opened read-write and mapped read-only, it will be
   opened O_RDONLY during restore, so restore will succeed, but
   mprotect(PROT_WRITE) on the read-only mapping after restore will
   fail.

To fix both of these, record open flags per-vma based on the presence of
VM_MAYWRITE in smaps.
Signed-off-by: 's avatarJamie Liu <jamieliu@google.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 288cf517
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
#include <sys/vfs.h> #include <sys/vfs.h>
#include <sys/sendfile.h> #include <sys/sendfile.h>
#include <sys/mman.h>
#include <sched.h> #include <sched.h>
#include <sys/resource.h> #include <sys/resource.h>
...@@ -347,10 +346,7 @@ static int dump_filemap(pid_t pid, struct vma_area *vma_area, ...@@ -347,10 +346,7 @@ static int dump_filemap(pid_t pid, struct vma_area *vma_area,
BUG_ON(!vma_area->st); BUG_ON(!vma_area->st);
p.stat = *vma_area->st; p.stat = *vma_area->st;
if ((vma->prot & PROT_WRITE) && vma_entry_is(vma, VMA_FILE_SHARED)) /* Flags will be set during restore in get_filemap_fd() */
p.flags = O_RDWR;
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); ret = dump_one_reg_file(vma_area->vm_file_fd, id, &p);
......
...@@ -708,6 +708,8 @@ int open_reg_by_id(u32 id) ...@@ -708,6 +708,8 @@ int open_reg_by_id(u32 id)
int get_filemap_fd(struct vma_area *vma) int get_filemap_fd(struct vma_area *vma)
{ {
struct reg_file_info *rfi;
/* /*
* Thevma->fd should have been assigned in collect_filemap * Thevma->fd should have been assigned in collect_filemap
* *
...@@ -715,6 +717,13 @@ int get_filemap_fd(struct vma_area *vma) ...@@ -715,6 +717,13 @@ int get_filemap_fd(struct vma_area *vma)
*/ */
BUG_ON(vma->fd == NULL); BUG_ON(vma->fd == NULL);
rfi = container_of(vma->fd, struct reg_file_info, d);
if (vma->e->has_fdflags)
rfi->rfe->flags = vma->e->fdflags;
else {
pr_err("vma %#lx missing fdflags", vma->e->start);
return -1;
}
return open_path(vma->fd, do_open_reg_noseek, NULL); return open_path(vma->fd, do_open_reg_noseek, NULL);
} }
......
...@@ -92,6 +92,8 @@ static bool is_vma_range_fmt(char *line) ...@@ -92,6 +92,8 @@ static bool is_vma_range_fmt(char *line)
static int parse_vmflags(char *buf, struct vma_area *vma_area) static int parse_vmflags(char *buf, struct vma_area *vma_area)
{ {
char *tok; char *tok;
bool shared = false;
bool maywrite = false;
if (!buf[0]) if (!buf[0])
return 0; return 0;
...@@ -103,6 +105,12 @@ static int parse_vmflags(char *buf, struct vma_area *vma_area) ...@@ -103,6 +105,12 @@ static int parse_vmflags(char *buf, struct vma_area *vma_area)
#define _vmflag_match(_t, _s) (_t[0] == _s[0] && _t[1] == _s[1]) #define _vmflag_match(_t, _s) (_t[0] == _s[0] && _t[1] == _s[1])
do { do {
/* open() block */
if (_vmflag_match(tok, "sh"))
shared = true;
else if (_vmflag_match(tok, "mw"))
maywrite = true;
/* mmap() block */ /* mmap() block */
if (_vmflag_match(tok, "gd")) if (_vmflag_match(tok, "gd"))
vma_area->e->flags |= MAP_GROWSDOWN; vma_area->e->flags |= MAP_GROWSDOWN;
...@@ -136,6 +144,12 @@ static int parse_vmflags(char *buf, struct vma_area *vma_area) ...@@ -136,6 +144,12 @@ static int parse_vmflags(char *buf, struct vma_area *vma_area)
#undef _vmflag_match #undef _vmflag_match
if (shared && maywrite)
vma_area->e->fdflags = O_RDWR;
else
vma_area->e->fdflags = O_RDONLY;
vma_area->e->has_fdflags = true;
if (vma_area->e->madv) if (vma_area->e->madv)
vma_area->e->has_madv = true; vma_area->e->has_madv = true;
......
...@@ -15,4 +15,7 @@ message vma_entry { ...@@ -15,4 +15,7 @@ message vma_entry {
/* madvise flags bitmap */ /* madvise flags bitmap */
optional uint64 madv = 9; optional uint64 madv = 9;
/* file status flags */
optional uint32 fdflags = 10;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment