Commit 57a691f6 authored by Stanislav Kinsburskiy's avatar Stanislav Kinsburskiy Committed by Pavel Emelyanov

proc_parse: fix vma file open mode recognition

WIth current code we have smth like

1) If file was opened with O_WRONLY, this mode is simply lost.
2) If file was opened with O_RDWR, but mapping is private, resulting mode will be O_RDONLY

The correct place to get fd open flags for file mappings is
/proc/<pid>/map_files.
An attempt tp speculate on "shared" and "maywrite" bits doesn't garantee,
that file will be opened with correct permissions on restore.
Here is an example:

Process mapping (read/write):

# cat /proc/481943/maps | grep 7f7108077000-7f7108078000
7f7108077000-7f7108078000 rw-p 00001000 00:35 7 <snip>

1) Before suspend:

# ls -l /proc/481427/map_files/7f7108077000-7f7108078000
lrw------- <snip> /proc/481427/map_files/7f7108077000-7f7108078000 -> <snip>

2) After restore:

# ls -l /proc/481943/map_files/7f7108077000-7f7108078000
lr-------- <snip> /proc/481943/map_files/7f7108077000-7f7108078000 -> <snip>

Write bit is lost.

This patch set vma->e->fdflags as /proc/<pid>/map_files/<vma> open mode.
Signed-off-by: 's avatarStanislav Kinsburskiy <skinsbursky@virtuozzo.com>
Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 8112ad76
......@@ -96,8 +96,6 @@ static bool is_vma_range_fmt(char *line)
static int parse_vmflags(char *buf, struct vma_area *vma_area)
{
char *tok;
bool shared = false;
bool maywrite = false;
if (!buf[0])
return 0;
......@@ -109,12 +107,6 @@ static int parse_vmflags(char *buf, struct vma_area *vma_area)
#define _vmflag_match(_t, _s) (_t[0] == _s[0] && _t[1] == _s[1])
do {
/* open() block */
if (_vmflag_match(tok, "sh"))
shared = true;
else if (_vmflag_match(tok, "mw"))
maywrite = true;
/* mmap() block */
if (_vmflag_match(tok, "gd"))
vma_area->e->flags |= MAP_GROWSDOWN;
......@@ -158,12 +150,6 @@ static int parse_vmflags(char *buf, struct vma_area *vma_area)
#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)
vma_area->e->has_madv = true;
......@@ -189,6 +175,34 @@ static inline int vfi_equal(struct vma_file_info *a, struct vma_file_info *b)
(a->dev_min ^ b->dev_min)) == 0;
}
static int vma_get_mapfile_flags(struct vma_area *vma, DIR *mfd, char *path)
{
struct stat stat;
if (fstatat(dirfd(mfd), path, &stat, AT_SYMLINK_NOFOLLOW) < 0) {
if (errno == ENOENT) {
/* Just mapping w/o map_files link */
return 0;
}
pr_perror("Failed fstatat on map %"PRIx64"", vma->e->start);
return -1;
}
switch(stat.st_mode & 0600) {
case 0200:
vma->e->fdflags = O_WRONLY;
break;
case 0400:
vma->e->fdflags = O_RDONLY;
break;
case 0600:
vma->e->fdflags = O_RDWR;
break;
}
vma->e->has_fdflags = true;
return 0;
}
static int vma_get_mapfile(char *fname, struct vma_area *vma, DIR *mfd,
struct vma_file_info *vfi,
struct vma_file_info *prev_vfi,
......@@ -197,6 +211,12 @@ static int vma_get_mapfile(char *fname, struct vma_area *vma, DIR *mfd,
char path[32];
int flags;
/* Figure out if it's file mapping */
snprintf(path, sizeof(path), "%"PRIx64"-%"PRIx64, vma->e->start, vma->e->end);
if (vma_get_mapfile_flags(vma, mfd, path))
return -1;
if (prev_vfi->vma && vfi_equal(vfi, prev_vfi)) {
struct vma_area *prev = prev_vfi->vma;
......@@ -225,9 +245,6 @@ static int vma_get_mapfile(char *fname, struct vma_area *vma, DIR *mfd,
}
close_safe(vm_file_fd);
/* Figure out if it's file mapping */
snprintf(path, sizeof(path), "%"PRIx64"-%"PRIx64, vma->e->start, vma->e->end);
/*
* Note that we "open" it in dumper process space
* so later we might refer to it via /proc/self/fd/vm_file_fd
......
......@@ -161,12 +161,13 @@ void pr_vma(unsigned int loglevel, const struct vma_area *vma_area)
return;
vma_opt_str(vma_area, opt);
print_on_level(loglevel, "%#"PRIx64"-%#"PRIx64" (%"PRIi64"K) prot %#x flags %#x st %#x off %#"PRIx64" "
print_on_level(loglevel, "%#"PRIx64"-%#"PRIx64" (%"PRIi64"K) prot %#x flags %#x fdflags %#o st %#x off %#"PRIx64" "
"%s shmid: %#"PRIx64"\n",
vma_area->e->start, vma_area->e->end,
KBYTES(vma_area_len(vma_area)),
vma_area->e->prot,
vma_area->e->flags,
vma_area->e->fdflags,
vma_area->e->status,
vma_area->e->pgoff,
opt, vma_area->e->shmid);
......
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