mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-07-29 21:12:29 +00:00
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: Jamie Liu <jamieliu@google.com> Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
This commit is contained in:
parent
288cf51741
commit
efe594f8f4
4 changed files with 27 additions and 5 deletions
|
|
@ -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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
14
proc_parse.c
14
proc_parse.c
|
|
@ -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)
|
||||||
#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)
|
||||||
|
|
||||||
#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 {
|
||||||
|
|
||||||
/* madvise flags bitmap */
|
/* madvise flags bitmap */
|
||||||
optional uint64 madv = 9;
|
optional uint64 madv = 9;
|
||||||
|
|
||||||
|
/* file status flags */
|
||||||
|
optional uint32 fdflags = 10;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue