[CRIU] [PATCH v2] criu: correctly handle mixed-permission mapped files
Andrew Vagin
avagin at parallels.com
Thu Apr 3 01:48:37 PDT 2014
On Wed, Apr 02, 2014 at 05:52:56PM -0700, Jamie Liu wrote:
> 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, defer filemap open flags selection until restore, since
> mapped files are opened per mapping.
Hi Jamie,
I have modified your test and it fails even with this patch.
The idea of my changes is simple, I call mprotect after suspend/resume:
open(xxx, O_RDWR)
mmap(0, size, PROT_READ, MAP_SHARED, fd, 0);
/* suspend/resume */
mprotect(addr, size, PROT_READ | PROT_WRITE))
Execute zdtm/live/static/maps_file_mixedprot
./maps_file_mixedprot --pidfile=maps_file_mixedprot.pid --outfile=maps_file_mixedprot.out --filename=maps_file_mixedprot.test
Dump 29705
Restore
Check results 29705
12:41:42.588: 29705: ERR: maps_file_mixedprot.c:39: mprotect failed (errno = 13 (Permission denied))
Test: zdtm/live/static/maps_file_mixedprot, Result: FAIL
==================================== ERROR ====================================
Test: zdtm/live/static/maps_file_mixedprot, Namespace:
Dump log : /root/git/crtools/test/dump/maps_file_mixedprot/29705/1/dump.log
--------------------------------- grep Error ---------------------------------
------------------------------------- END -------------------------------------
Restore log: /root/git/crtools/test/dump/maps_file_mixedprot/29705/1/restore.log
--------------------------------- grep Error ---------------------------------
------------------------------------- END -------------------------------------
Output file: /root/git/crtools/test/zdtm/live/static/maps_file_mixedprot.out
------------------------------------------------------------------------------
12:41:42.588: 29705: ERR: maps_file_mixedprot.c:39: mprotect failed (errno = 13 (Permission denied))
------------------------------------- END -------------------------------------
================================= ERROR OVER =================================
>
> Signed-off-by: Jamie Liu <jamieliu at google.com>
> ---
> cr-dump.c | 6 +-----
> files-reg.c | 8 ++++++++
> 2 files changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/cr-dump.c b/cr-dump.c
> index 0111115..f7945d9 100644
> --- a/cr-dump.c
> +++ b/cr-dump.c
> @@ -15,7 +15,6 @@
> #include <sys/vfs.h>
>
> #include <sys/sendfile.h>
> -#include <sys/mman.h>
>
> #include <sched.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);
> p.stat = *vma_area->st;
>
> - if ((vma->prot & PROT_WRITE) && vma_entry_is(vma, VMA_FILE_SHARED))
> - p.flags = O_RDWR;
> - else
> - p.flags = O_RDONLY;
> + /* Flags will be detected during restore in get_filemap_fd() */
>
> if (fd_id_generate_special(&p.stat, &id))
> ret = dump_one_reg_file(vma_area->vm_file_fd, id, &p);
> diff --git a/files-reg.c b/files-reg.c
> index eccd04e..743b035 100644
> --- a/files-reg.c
> +++ b/files-reg.c
> @@ -3,6 +3,7 @@
> #include <errno.h>
> #include <string.h>
> #include <sys/types.h>
> +#include <sys/mman.h>
> #include <sys/stat.h>
> #include <sys/vfs.h>
> #include <ctype.h>
> @@ -708,6 +709,8 @@ int open_reg_by_id(u32 id)
>
> int get_filemap_fd(struct vma_area *vma)
> {
> + struct reg_file_info *rfi;
> +
> /*
> * Thevma->fd should have been assigned in collect_filemap
> *
> @@ -715,6 +718,11 @@ int get_filemap_fd(struct vma_area *vma)
> */
>
> BUG_ON(vma->fd == NULL);
> + rfi = container_of(vma->fd, struct reg_file_info, d);
> + if ((vma->e->prot & PROT_WRITE) && vma_area_is(vma, VMA_FILE_SHARED))
> + rfi->rfe->flags = O_RDWR;
> + else
> + rfi->rfe->flags = O_RDONLY;
> return open_path(vma->fd, do_open_reg_noseek, NULL);
> }
>
> --
> 1.9.1.423.g4596e3a
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://lists.openvz.org/mailman/listinfo/criu
-------------- next part --------------
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <linux/limits.h>
#include "zdtmtst.h"
const char *test_doc = "Test mappings of same file with different prot";
const char *test_author = "Jamie Liu <jamieliu at google.com>";
char *filename;
TEST_OPTION(filename, string, "file name", 1);
#define die(fmt, arg...) do { err(fmt, ## arg); return 1; } while (0)
int main(int argc, char ** argv)
{
void *ro_map, *rw_map;
int fd;
test_init(argc, argv);
fd = open(filename, O_RDWR | O_CREAT, 0644);
if (fd < 0)
die("open failed");
ftruncate(fd, PAGE_SIZE * 2);
ro_map = mmap(NULL, 2 * PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
if (ro_map == MAP_FAILED)
die("ro_map mmap failed");
test_daemon();
test_waitsig();
rw_map = ro_map + PAGE_SIZE;
if (mprotect(rw_map, PAGE_SIZE, PROT_READ | PROT_WRITE))
die("mprotect failed");
close(fd);
/* Check that rw_map is still writeable */
*(volatile char *)rw_map = 1;
pass();
return 0;
}
More information about the CRIU
mailing list