2
0
mirror of https://github.com/checkpoint-restore/criu synced 2025-08-22 18:07:57 +00:00
criu/proc_parse.c
Pavel Emelyanov 199e8d8248 dump: Check for pids reuse at suspend
While we try to seize task it can die and give its pid to
somebody else. This can break pstree consistency. Check for
parent being valid after task is seized.

Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
Signed-off-by: Cyrill Gorcunov <gorcunov@openvz.org>
2012-03-01 19:31:20 +04:00

387 lines
7.7 KiB
C

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include "types.h"
#include "list.h"
#include "util.h"
#include "crtools.h"
#include "proc_parse.h"
int parse_maps(pid_t pid, struct list_head *vma_area_list, bool use_map_files)
{
struct vma_area *vma_area = NULL;
u64 start, end, pgoff;
char big_buffer[1024];
unsigned long ino;
char r,w,x,s;
int dev_maj, dev_min;
int ret = -1;
DIR *map_files_dir = NULL;
FILE *maps = NULL;
maps = fopen_proc(pid, "maps");
if (!maps)
goto err;
if (use_map_files) {
map_files_dir = opendir_proc(pid, "map_files");
if (!map_files_dir) /* old kernel? */
goto err;
}
while (fgets(big_buffer, sizeof(big_buffer), maps)) {
struct stat st_buf;
int num;
char file_path[6];
memset(file_path, 0, 6);
num = sscanf(big_buffer, "%lx-%lx %c%c%c%c %lx %02x:%02x %lu %5s",
&start, &end, &r, &w, &x, &s, &pgoff, &dev_maj,
&dev_min, &ino, file_path);
if (num < 10) {
pr_err("Can't parse: %s", big_buffer);
goto err;
}
vma_area = alloc_vma_area();
if (!vma_area)
goto err;
if (map_files_dir) {
char path[32];
/* Figure out if it's file mapping */
snprintf(path, sizeof(path), "%lx-%lx", start, end);
/*
* Note that we "open" it in dumper process space
* so later we might refer to it via /proc/self/fd/vm_file_fd
* if needed.
*/
vma_area->vm_file_fd = openat(dirfd(map_files_dir), path, O_RDONLY);
if (vma_area->vm_file_fd < 0) {
if (errno != ENOENT) {
pr_perror("Can't open %d's map %lu", pid, start);
goto err;
}
}
}
vma_area->vma.start = start;
vma_area->vma.end = end;
vma_area->vma.pgoff = pgoff;
vma_area->vma.prot = PROT_NONE;
if (r == 'r')
vma_area->vma.prot |= PROT_READ;
if (w == 'w')
vma_area->vma.prot |= PROT_WRITE;
if (x == 'x')
vma_area->vma.prot |= PROT_EXEC;
if (s == 's')
vma_area->vma.flags = MAP_SHARED;
else if (s == 'p')
vma_area->vma.flags = MAP_PRIVATE;
if (strstr(big_buffer, "[stack]")) {
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_STACK;
vma_area->vma.flags |= MAP_GROWSDOWN;
} else if (strstr(big_buffer, "[vsyscall]")) {
vma_area->vma.status |= VMA_AREA_VSYSCALL;
} else if (strstr(big_buffer, "[vdso]")) {
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_VDSO;
} else if (strstr(big_buffer, "[heap]")) {
vma_area->vma.status |= VMA_AREA_REGULAR | VMA_AREA_HEAP;
} else {
vma_area->vma.status = VMA_AREA_REGULAR;
}
/*
* Some mapping hints for restore, we save this on
* disk and restore might need to analyze it.
*/
if (vma_area->vm_file_fd >= 0) {
if (fstat(vma_area->vm_file_fd, &st_buf) < 0) {
pr_perror("Failed fstat on %d's map %lu", pid, start);
goto err;
}
if (!S_ISREG(st_buf.st_mode)) {
pr_err("Can't handle non-regular mapping on %d's map %lu\n", pid, start);
goto err;
}
/*
* /dev/zero stands for anon-shared mapping
* otherwise it's some file mapping.
*/
if (MAJOR(st_buf.st_dev) == 0) {
if (!(vma_area->vma.flags & MAP_SHARED))
goto err_bogus_mapping;
vma_area->vma.flags |= MAP_ANONYMOUS;
vma_area->vma.status |= VMA_ANON_SHARED;
vma_area->shmid = st_buf.st_ino;
if (!strcmp(file_path, "/SYSV")) {
pr_perror("path: %s\n", file_path);
vma_area->vma.status |= VMA_AREA_SYSVIPC;
}
} else {
if (vma_area->vma.flags & MAP_PRIVATE)
vma_area->vma.status |= VMA_FILE_PRIVATE;
else
vma_area->vma.status |= VMA_FILE_SHARED;
}
} else {
/*
* No file but mapping -- anonymous one.
*/
if (vma_area->vma.flags & MAP_SHARED) {
vma_area->vma.status |= VMA_ANON_SHARED;
vma_area->shmid = ino;
} else {
vma_area->vma.status |= VMA_ANON_PRIVATE;
}
vma_area->vma.flags |= MAP_ANONYMOUS;
}
list_add_tail(&vma_area->list, vma_area_list);
}
vma_area = NULL;
ret = 0;
err:
if (maps)
fclose(maps);
if (map_files_dir)
closedir(map_files_dir);
xfree(vma_area);
return ret;
err_bogus_mapping:
pr_err("Bogus mapping %lx-%lx (flags: %x vm_file_fd: %d)\n",
vma_area->vma.start, vma_area->vma.end,
vma_area->vma.flags, vma_area->vm_file_fd);
goto err;
}
int parse_pid_stat_small(pid_t pid, struct proc_pid_stat_small *s)
{
FILE *f;
char *tok;
int n;
f = fopen_proc(pid, "stat");
if (f == NULL)
return -1;
memset(s, 0, sizeof(*s));
n = fscanf(f, "%d " PROC_TASK_COMM_LEN_FMT " %c %d",
&s->pid, s->comm, &s->state, &s->ppid);
if (n < 4) {
pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
return -1;
}
s->comm[PROC_TASK_COMM_LEN-1] = '\0';
tok = strchr(s->comm, ')');
if (tok)
*tok = '\0';
fclose(f);
return 0;
}
int parse_pid_stat(pid_t pid, struct proc_pid_stat *s)
{
FILE *f;
char *tok;
int n;
f = fopen_proc(pid, "stat");
if (f == NULL)
return -1;
memset(s, 0, sizeof(*s));
n = fscanf(f,
"%d " PROC_TASK_COMM_LEN_FMT " %c %d %d %d %d %d %u %lu %lu %lu %lu "
"%lu %lu %ld %ld %ld %ld %d %d %llu %lu %ld %lu %lu %lu %lu "
"%lu %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld "
"%lu %lu %lu %lu %lu %lu %lu %d",
&s->pid,
s->comm,
&s->state,
&s->ppid,
&s->pgid,
&s->sid,
&s->tty_nr,
&s->tty_pgrp,
&s->flags,
&s->min_flt,
&s->cmin_flt,
&s->maj_flt,
&s->cmaj_flt,
&s->utime,
&s->stime,
&s->cutime,
&s->cstime,
&s->priority,
&s->nice,
&s->num_threads,
&s->zero0,
&s->start_time,
&s->vsize,
&s->mm_rss,
&s->rsslim,
&s->start_code,
&s->end_code,
&s->start_stack,
&s->esp,
&s->eip,
&s->sig_pending,
&s->sig_blocked,
&s->sig_ignored,
&s->sig_handled,
&s->wchan,
&s->zero1,
&s->zero2,
&s->exit_signal,
&s->task_cpu,
&s->rt_priority,
&s->policy,
&s->delayacct_blkio_ticks,
&s->gtime,
&s->cgtime,
&s->start_data,
&s->end_data,
&s->start_brk,
&s->arg_start,
&s->arg_end,
&s->env_start,
&s->env_end,
&s->exit_code);
if (n < 52) {
pr_err("Parsing %d's stat failed (#fields do not match)\n", pid);
return -1;
}
s->comm[PROC_TASK_COMM_LEN-1] = '\0';
tok = strchr(s->comm, ')');
if (tok)
*tok = '\0';
fclose(f);
return 0;
}
static int ids_parse(char *str, unsigned int *arr)
{
char *end;
arr[0] = strtol(str, &end, 10);
arr[1] = strtol(end + 1, &end, 10);
arr[2] = strtol(end + 1, &end, 10);
arr[3] = strtol(end + 1, &end, 10);
if (*end != '\n')
return -1;
else
return 0;
}
static int cap_parse(char *str, unsigned int *res)
{
int i, ret;
for (i = 0; i < PROC_CAP_SIZE; i++) {
ret = sscanf(str, "%08x", &res[PROC_CAP_SIZE - 1 - i]);
if (ret != 1)
return -1;
str += 8;
}
return 0;
}
int parse_pid_status(pid_t pid, struct proc_status_creds *cr)
{
int done = 0;
FILE *f;
char str[64];
f = fopen_proc(pid, "status");
if (f == NULL) {
pr_perror("Can't open proc status");
return -1;
}
while (done < 6 && fgets(str, sizeof(str), f)) {
if (!strncmp(str, "Uid:", 4)) {
if (ids_parse(str + 5, cr->uids))
goto err_parse;
done++;
}
if (!strncmp(str, "Gid:", 4)) {
if (ids_parse(str + 5, cr->gids))
goto err_parse;
done++;
}
if (!strncmp(str, "CapInh:", 7)) {
if (cap_parse(str + 8, cr->cap_inh))
goto err_parse;
done++;
}
if (!strncmp(str, "CapEff:", 7)) {
if (cap_parse(str + 8, cr->cap_eff))
goto err_parse;
done++;
}
if (!strncmp(str, "CapPrm:", 7)) {
if (cap_parse(str + 8, cr->cap_prm))
goto err_parse;
done++;
}
if (!strncmp(str, "CapBnd:", 7)) {
if (cap_parse(str + 8, cr->cap_bnd))
goto err_parse;
done++;
}
}
if (done != 6) {
err_parse:
pr_err("Error parsing proc status file\n");
fclose(f);
return -1;
}
fclose(f);
return 0;
}