2011-09-23 12:00:45 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/vfs.h>
|
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#include <sys/user.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
|
|
#include <sched.h>
|
|
|
|
|
|
|
|
#include <sys/sendfile.h>
|
|
|
|
|
|
|
|
#include "compiler.h"
|
|
|
|
#include "types.h"
|
|
|
|
|
|
|
|
#include "image.h"
|
|
|
|
#include "util.h"
|
2011-10-26 17:35:50 +04:00
|
|
|
#include "syscall.h"
|
2011-10-24 22:23:06 +04:00
|
|
|
#include "restorer.h"
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
#include "crtools.h"
|
|
|
|
|
|
|
|
struct fmap_fd {
|
|
|
|
struct fmap_fd *next;
|
|
|
|
unsigned long start;
|
2011-09-28 13:19:30 +04:00
|
|
|
int pid;
|
2011-09-23 12:00:45 +04:00
|
|
|
int fd;
|
|
|
|
};
|
|
|
|
|
2011-10-13 17:31:52 +04:00
|
|
|
/*
|
2011-10-13 18:15:09 +04:00
|
|
|
* real_pid member formerly served cases when
|
|
|
|
* no fork-with-pid functionality were in kernel,
|
|
|
|
* so now it is being kept here just in case if
|
|
|
|
* we need it again.
|
2011-10-13 17:31:52 +04:00
|
|
|
*/
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
struct shmem_info {
|
|
|
|
unsigned long start;
|
|
|
|
unsigned long end;
|
2011-09-28 15:55:12 +04:00
|
|
|
unsigned long shmid;
|
2011-09-23 12:00:45 +04:00
|
|
|
int pid;
|
|
|
|
int real_pid;
|
|
|
|
};
|
|
|
|
|
2011-09-30 09:00:45 +04:00
|
|
|
#define PIPE_NONE (0 << 0)
|
|
|
|
#define PIPE_RDONLY (1 << 1)
|
|
|
|
#define PIPE_WRONLY (1 << 2)
|
|
|
|
#define PIPE_RDWR (PIPE_RDONLY | PIPE_WRONLY)
|
|
|
|
#define PIPE_MODE_MASK (0x7)
|
|
|
|
#define PIPE_CREATED (1 << 3)
|
|
|
|
|
|
|
|
#define pipe_is_rw(p) (((p)->status & PIPE_MODE_MASK) == PIPE_RDWR)
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
struct pipe_info {
|
2011-09-29 00:50:09 +04:00
|
|
|
unsigned int pipeid;
|
2011-09-23 12:00:45 +04:00
|
|
|
int pid;
|
|
|
|
int real_pid;
|
|
|
|
int read_fd;
|
|
|
|
int write_fd;
|
2011-09-30 09:00:45 +04:00
|
|
|
int status;
|
2011-09-23 12:00:45 +04:00
|
|
|
int users;
|
|
|
|
};
|
|
|
|
|
2011-09-28 14:45:30 +04:00
|
|
|
struct shmem_id {
|
|
|
|
struct shmem_id *next;
|
|
|
|
unsigned long addr;
|
|
|
|
unsigned long end;
|
2011-09-28 15:55:12 +04:00
|
|
|
unsigned long shmid;
|
2011-09-28 14:45:30 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct shmem_id *shmem_ids;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
static struct fmap_fd *fmap_fds;
|
|
|
|
|
|
|
|
static struct shmem_info *shmems;
|
|
|
|
static int nr_shmems;
|
|
|
|
|
|
|
|
static struct pipe_info *pipes;
|
|
|
|
static int nr_pipes;
|
|
|
|
|
|
|
|
static int restore_task_with_children(int my_pid, char *pstree_path);
|
|
|
|
|
|
|
|
static void show_saved_shmems(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
pr_info("\tSaved shmems:\n");
|
|
|
|
|
|
|
|
for (i = 0; i < nr_shmems; i++)
|
2011-09-28 15:55:12 +04:00
|
|
|
pr_info("\t\tstart: %016lx shmid: %lx pid: %d\n",
|
2011-09-23 12:00:45 +04:00
|
|
|
shmems[i].start,
|
2011-09-28 15:55:12 +04:00
|
|
|
shmems[i].shmid,
|
2011-09-23 12:00:45 +04:00
|
|
|
shmems[i].pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void show_saved_pipes(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
pr_info("\tSaved pipes:\n");
|
|
|
|
for (i = 0; i < nr_pipes; i++)
|
2011-09-30 09:00:45 +04:00
|
|
|
pr_info("\t\tpipeid %x pid %d users %d status %d\n",
|
|
|
|
pipes[i].pipeid, pipes[i].pid,
|
|
|
|
pipes[i].users, pipes[i].status);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2011-09-28 15:55:12 +04:00
|
|
|
static struct shmem_info *find_shmem(unsigned long addr, unsigned long shmid)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct shmem_info *si;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_shmems; i++) {
|
|
|
|
si = shmems + i;
|
2011-09-28 15:55:12 +04:00
|
|
|
if (si->start <= addr && si->end >= addr && si->shmid == shmid)
|
2011-09-23 12:00:45 +04:00
|
|
|
return si;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-09-28 14:45:30 +04:00
|
|
|
static struct pipe_info *find_pipe(unsigned int pipeid)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct pipe_info *pi;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_pipes; i++) {
|
|
|
|
pi = pipes + i;
|
2011-09-29 00:50:09 +04:00
|
|
|
if (pi->pipeid == pipeid)
|
2011-09-23 12:00:45 +04:00
|
|
|
return pi;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void shmem_update_real_pid(int vpid, int rpid)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_shmems; i++)
|
|
|
|
if (shmems[i].pid == vpid)
|
|
|
|
shmems[i].real_pid = rpid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int shmem_wait_and_open(struct shmem_info *si)
|
|
|
|
{
|
|
|
|
/* FIXME - not good */
|
|
|
|
char path[128];
|
|
|
|
unsigned long time = 1000;
|
|
|
|
|
|
|
|
sleep(1);
|
|
|
|
|
|
|
|
while (si->real_pid == 0)
|
|
|
|
usleep(time);
|
|
|
|
|
|
|
|
sprintf(path, "/proc/%d/map_files/%lx-%lx",
|
|
|
|
si->real_pid, si->start, si->end);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int ret = open(path, O_RDWR);
|
|
|
|
if (ret > 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (ret < 0 && errno != ENOENT) {
|
|
|
|
perror(" Can't stat shmem");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Waiting for [%s] to appear\n", path);
|
|
|
|
if (time < 20000000)
|
|
|
|
time <<= 1;
|
|
|
|
usleep(time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
static int collect_shmem(int pid, struct shmem_entry *e)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_shmems; i++) {
|
|
|
|
if (shmems[i].start != e->start ||
|
2011-09-28 15:55:12 +04:00
|
|
|
shmems[i].shmid != e->shmid)
|
2011-09-23 12:00:45 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (shmems[i].end != e->end) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Bogus shmem\n");
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 15:55:12 +04:00
|
|
|
/*
|
|
|
|
* Only the shared mapping with highest
|
|
|
|
* pid will be created in real, other processes
|
|
|
|
* will wait until the kernel propagate this mapping
|
|
|
|
* into /proc
|
|
|
|
*/
|
2011-09-23 12:00:45 +04:00
|
|
|
if (shmems[i].pid > pid)
|
|
|
|
shmems[i].pid = pid;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((nr_shmems + 1) * sizeof(struct shmem_info) >= 4096) {
|
|
|
|
pr_panic("OOM storing shmems\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-30 01:13:16 +04:00
|
|
|
memset(&shmems[nr_shmems], 0, sizeof(shmems[nr_shmems]));
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
shmems[nr_shmems].start = e->start;
|
|
|
|
shmems[nr_shmems].end = e->end;
|
2011-09-28 15:55:12 +04:00
|
|
|
shmems[nr_shmems].shmid = e->shmid;
|
2011-09-23 12:00:45 +04:00
|
|
|
shmems[nr_shmems].pid = pid;
|
|
|
|
shmems[nr_shmems].real_pid = 0;
|
|
|
|
|
|
|
|
nr_shmems++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
static int collect_pipe(int pid, struct pipe_entry *e, int p_fd)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
/*
|
|
|
|
* All pipes get collected into the one array,
|
|
|
|
* note the highest PID is the sign of which
|
|
|
|
* process pipe should be really created, all other
|
|
|
|
* processes (if they have pipes with pipeid matched)
|
|
|
|
* will be attached.
|
|
|
|
*/
|
2011-09-23 12:00:45 +04:00
|
|
|
for (i = 0; i < nr_pipes; i++) {
|
2011-09-29 00:50:09 +04:00
|
|
|
if (pipes[i].pipeid != e->pipeid)
|
2011-09-23 12:00:45 +04:00
|
|
|
continue;
|
|
|
|
|
2011-09-30 09:00:45 +04:00
|
|
|
if (pipes[i].pid > pid && !pipe_is_rw(&pipes[i])) {
|
2011-09-23 12:00:45 +04:00
|
|
|
pipes[i].pid = pid;
|
2011-09-30 09:00:45 +04:00
|
|
|
} else if (pipes[i].pid == pid) {
|
|
|
|
switch (e->flags) {
|
|
|
|
case O_RDONLY:
|
|
|
|
pipes[i].status |= PIPE_RDONLY;
|
|
|
|
break;
|
|
|
|
case O_WRONLY:
|
|
|
|
pipes[i].status |= PIPE_WRONLY;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-09-27 12:55:05 +04:00
|
|
|
|
|
|
|
pipes[i].users++;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((nr_pipes + 1) * sizeof(struct pipe_info) >= 4096) {
|
2011-09-28 01:09:34 +04:00
|
|
|
pr_panic("OOM storing pipes\n");
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&pipes[nr_pipes], 0, sizeof(pipes[nr_pipes]));
|
|
|
|
|
2011-09-29 00:50:09 +04:00
|
|
|
pipes[nr_pipes].pipeid = e->pipeid;
|
2011-09-28 01:09:34 +04:00
|
|
|
pipes[nr_pipes].pid = pid;
|
|
|
|
pipes[nr_pipes].users = 1;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-09-30 09:00:45 +04:00
|
|
|
switch (e->flags) {
|
|
|
|
case O_RDONLY:
|
|
|
|
pipes[nr_pipes].status = PIPE_RDONLY;
|
|
|
|
break;
|
|
|
|
case O_WRONLY:
|
|
|
|
pipes[nr_pipes].status = PIPE_WRONLY;
|
|
|
|
break;
|
|
|
|
default:
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("%d: Unknown pipe status pipeid %d\n",
|
|
|
|
pid, e->pipeid);
|
2011-09-30 09:00:45 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
nr_pipes++;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_shmem_pid(int pid)
|
|
|
|
{
|
|
|
|
int sh_fd;
|
|
|
|
u32 type = 0;
|
|
|
|
|
2011-10-24 13:56:21 +04:00
|
|
|
sh_fd = open_fmt_ro("shmem-%d.img", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (sh_fd < 0) {
|
|
|
|
perror("Can't open shmem info");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
read(sh_fd, &type, sizeof(type));
|
|
|
|
if (type != SHMEM_MAGIC) {
|
|
|
|
perror("Bad shmem magic");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct shmem_entry e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(sh_fd, &e, sizeof(e));
|
|
|
|
if (ret == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ret != sizeof(e)) {
|
|
|
|
perror("Can't read shmem entry");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
if (collect_shmem(pid, &e))
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(sh_fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_pipes_pid(int pid)
|
|
|
|
{
|
|
|
|
int p_fd;
|
|
|
|
u32 type = 0;
|
|
|
|
|
2011-10-24 13:56:21 +04:00
|
|
|
p_fd = open_fmt_ro("pipes-%d.img", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (p_fd < 0) {
|
|
|
|
perror("Can't open pipes image");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
read(p_fd, &type, sizeof(type));
|
|
|
|
if (type != PIPES_MAGIC) {
|
|
|
|
perror("Bad pipes magin");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct pipe_entry e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(p_fd, &e, sizeof(e));
|
|
|
|
if (ret == 0)
|
|
|
|
break;
|
|
|
|
if (ret != sizeof(e)) {
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_perror("Read pipes for %d failed %d of %li read\n",
|
|
|
|
pid, ret, sizeof(e));
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
if (collect_pipe(pid, &e, p_fd))
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (e.bytes)
|
|
|
|
lseek(p_fd, e.bytes, SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(p_fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_shared(int ps_fd)
|
|
|
|
{
|
|
|
|
pr_info("Preparing info about shared resources\n");
|
|
|
|
|
|
|
|
nr_shmems = 0;
|
|
|
|
shmems = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, 0, 0);
|
|
|
|
if (shmems == MAP_FAILED) {
|
|
|
|
perror("Can't map shmems");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pipes = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, 0, 0);
|
|
|
|
if (pipes == MAP_FAILED) {
|
|
|
|
perror("Can't map pipes");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct pstree_entry e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(ps_fd, &e, sizeof(e));
|
|
|
|
if (ret == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ret != sizeof(e)) {
|
|
|
|
perror("Can't read ps");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prepare_shmem_pid(e.pid))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (prepare_pipes_pid(e.pid))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
lseek(ps_fd, e.nr_children * sizeof(u32), SEEK_CUR);
|
|
|
|
}
|
|
|
|
|
|
|
|
lseek(ps_fd, sizeof(u32), SEEK_SET);
|
|
|
|
|
|
|
|
show_saved_shmems();
|
|
|
|
show_saved_pipes();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-28 13:19:30 +04:00
|
|
|
static struct fmap_fd *pop_fmap_fd(int pid, unsigned long start)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct fmap_fd **p, *r;
|
|
|
|
|
2011-09-28 13:19:30 +04:00
|
|
|
pr_info("%d: Looking for %lx : ", pid, start);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
for (p = &fmap_fds; *p != NULL; p = &(*p)->next) {
|
2011-09-28 13:19:30 +04:00
|
|
|
if ((*p)->start != start || (*p)->pid != pid)
|
2011-09-23 12:00:45 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
r = *p;
|
|
|
|
*p = r->next;
|
|
|
|
pr_info("found\n");
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("not found\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_fe_fd(struct fdinfo_entry *fe, int fd)
|
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
if (read(fd, path, fe->len) != fe->len) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Error reading path");
|
2011-09-23 12:00:45 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
path[fe->len] = '\0';
|
|
|
|
|
|
|
|
tmp = open(path, fe->flags);
|
|
|
|
if (tmp < 0) {
|
|
|
|
pr_perror("Can't open file %s", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lseek(tmp, fe->pos, SEEK_SET);
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_fd(int pid, struct fdinfo_entry *fe, int *cfd)
|
|
|
|
{
|
|
|
|
int fd, tmp;
|
|
|
|
|
|
|
|
if (*cfd == (int)fe->addr) {
|
|
|
|
tmp = dup(*cfd);
|
|
|
|
if (tmp < 0) {
|
|
|
|
perror("Can't dup file");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*cfd = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp = open_fe_fd(fe, *cfd);
|
|
|
|
if (tmp < 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
fd = reopen_fd_as((int)fe->addr, tmp);
|
2011-09-27 18:48:57 +04:00
|
|
|
if (fd < 0)
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_fmap(int pid, struct fdinfo_entry *fe, int fd)
|
|
|
|
{
|
|
|
|
int tmp;
|
|
|
|
struct fmap_fd *new;
|
|
|
|
|
|
|
|
tmp = open_fe_fd(fe, fd);
|
|
|
|
if (tmp < 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
pr_info("%d:\t\tWill map %lx to %d\n", pid, (unsigned long)fe->addr, tmp);
|
|
|
|
|
|
|
|
new = malloc(sizeof(*new));
|
|
|
|
new->start = fe->addr;
|
|
|
|
new->fd = tmp;
|
|
|
|
new->next = fmap_fds;
|
2011-09-28 13:19:30 +04:00
|
|
|
new->pid = pid;
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
fmap_fds = new;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_fds(int pid)
|
|
|
|
{
|
|
|
|
u32 mag;
|
|
|
|
int fdinfo_fd;
|
|
|
|
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_info("%d: Opening files img\n", pid);
|
2011-09-29 01:24:23 +04:00
|
|
|
|
2011-10-24 13:56:21 +04:00
|
|
|
fdinfo_fd = open_fmt_ro("fdinfo-%d.img", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (fdinfo_fd < 0) {
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_perror("Can't open %d fdinfo", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
read(fdinfo_fd, &mag, 4);
|
|
|
|
if (mag != FDINFO_MAGIC) {
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_err("Bad %d fdinfo magic number\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int ret;
|
|
|
|
struct fdinfo_entry fe;
|
|
|
|
|
|
|
|
ret = read(fdinfo_fd, &fe, sizeof(fe));
|
|
|
|
if (ret == 0) {
|
|
|
|
close(fdinfo_fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret < 0) {
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_perror("Error reading %d fdinfo\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
2011-09-29 01:24:23 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret != sizeof(fe)) {
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_err("Corrupted %d fdinfo\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("\t%d: Got fd for %lx type %d namelen %d\n", pid,
|
2011-09-27 01:14:38 +04:00
|
|
|
(unsigned long)fe.addr, fe.type, fe.len);
|
2011-09-23 12:00:45 +04:00
|
|
|
switch (fe.type) {
|
|
|
|
case FDINFO_FD:
|
|
|
|
if (open_fd(pid, &fe, &fdinfo_fd))
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
case FDINFO_MAP:
|
|
|
|
if (open_fmap(pid, &fe, fdinfo_fd))
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
default:
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_err("Unknown %d fdinfo file type\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long find_shmem_id(unsigned long addr)
|
|
|
|
{
|
2011-09-28 14:45:30 +04:00
|
|
|
struct shmem_id *si;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-09-28 14:45:30 +04:00
|
|
|
for (si = shmem_ids; si; si = si->next)
|
2011-09-23 12:00:45 +04:00
|
|
|
if (si->addr <= addr && si->end >= addr)
|
2011-09-28 15:55:12 +04:00
|
|
|
return si->shmid;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void save_shmem_id(struct shmem_entry *e)
|
|
|
|
{
|
2011-09-28 14:45:30 +04:00
|
|
|
struct shmem_id *si;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
si = malloc(sizeof(*si));
|
|
|
|
si->addr = e->start;
|
|
|
|
si->end = e->end;
|
2011-09-28 15:55:12 +04:00
|
|
|
si->shmid = e->shmid;
|
2011-09-28 14:45:30 +04:00
|
|
|
si->next = shmem_ids;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-09-28 14:45:30 +04:00
|
|
|
shmem_ids = si;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_shmem(int pid)
|
|
|
|
{
|
|
|
|
int sh_fd;
|
|
|
|
u32 type = 0;
|
|
|
|
|
2011-10-24 13:56:21 +04:00
|
|
|
sh_fd = open_fmt_ro("shmem-%d.img", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (sh_fd < 0) {
|
|
|
|
perror("Can't open shmem info");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
read(sh_fd, &type, sizeof(type));
|
|
|
|
if (type != SHMEM_MAGIC) {
|
|
|
|
perror("Bad shmem magic");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct shmem_entry e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(sh_fd, &e, sizeof(e));
|
|
|
|
if (ret == 0)
|
|
|
|
break;
|
|
|
|
if (ret != sizeof(e)) {
|
|
|
|
perror("Can't read shmem entry");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
save_shmem_id(&e);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(sh_fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-09-28 16:49:59 +04:00
|
|
|
static int try_fixup_file_map(int pid, struct vma_entry *vma_entry, int fd)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2011-09-28 16:49:59 +04:00
|
|
|
struct fmap_fd *fmap_fd = pop_fmap_fd(pid, vma_entry->start);
|
|
|
|
|
|
|
|
if (fmap_fd) {
|
|
|
|
pr_info("%d: Fixing %lx vma to %d fd\n",
|
|
|
|
pid, vma_entry->start, fmap_fd->fd);
|
|
|
|
|
|
|
|
lseek(fd, -sizeof(*vma_entry), SEEK_CUR);
|
|
|
|
vma_entry->fd = fmap_fd->fd;
|
|
|
|
|
2011-09-28 23:23:43 +04:00
|
|
|
write_ptr_safe(fd, vma_entry, err);
|
2011-09-28 16:49:59 +04:00
|
|
|
|
|
|
|
free(fmap_fd);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2011-09-28 16:49:59 +04:00
|
|
|
err:
|
|
|
|
pr_perror("%d: Can't fixup vma\n", pid);
|
|
|
|
return 1;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int try_fixup_shared_map(int pid, struct vma_entry *vi, int fd)
|
|
|
|
{
|
|
|
|
struct shmem_info *si;
|
2011-09-28 15:55:12 +04:00
|
|
|
unsigned long shmid;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-09-28 15:55:12 +04:00
|
|
|
shmid = find_shmem_id(vi->start);
|
|
|
|
if (!shmid)
|
2011-09-23 12:00:45 +04:00
|
|
|
return 0;
|
|
|
|
|
2011-09-28 15:55:12 +04:00
|
|
|
si = find_shmem(vi->start, shmid);
|
2011-09-23 12:00:45 +04:00
|
|
|
pr_info("%d: Search for %016lx shmem %p/%d\n", pid, vi->start, si, si ? si->pid : -1);
|
|
|
|
|
2011-09-28 15:55:12 +04:00
|
|
|
if (!si) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Can't find my shmem %016lx\n", vi->start);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (si->pid != pid) {
|
|
|
|
int sh_fd;
|
|
|
|
|
|
|
|
sh_fd = shmem_wait_and_open(si);
|
2011-09-27 01:14:38 +04:00
|
|
|
pr_info("%d: Fixing %lx vma to %lx/%d shmem -> %d\n",
|
2011-09-28 15:55:12 +04:00
|
|
|
pid, vi->start, si->shmid, si->pid, sh_fd);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (fd < 0) {
|
|
|
|
perror("Can't open shmem");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lseek(fd, -sizeof(*vi), SEEK_CUR);
|
|
|
|
vi->fd = sh_fd;
|
|
|
|
if (write(fd, vi, sizeof(*vi)) != sizeof(*vi)) {
|
|
|
|
perror("Can't write img");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int fixup_vma_fds(int pid, int fd)
|
|
|
|
{
|
2011-09-26 18:14:39 +04:00
|
|
|
int offset = GET_FILE_OFF_AFTER(struct core_entry);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
lseek(fd, offset, SEEK_SET);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct vma_entry vi;
|
|
|
|
|
|
|
|
if (read(fd, &vi, sizeof(vi)) != sizeof(vi)) {
|
|
|
|
perror("Can't read");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi.start == 0 && vi.end == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!(vi.status & VMA_AREA_REGULAR))
|
|
|
|
continue;
|
|
|
|
|
2011-09-27 01:14:38 +04:00
|
|
|
if ((vi.status & VMA_FILE_PRIVATE) ||
|
|
|
|
(vi.status & VMA_FILE_SHARED) ||
|
2011-09-26 18:14:39 +04:00
|
|
|
(vi.status & VMA_ANON_SHARED)) {
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-09-27 01:14:38 +04:00
|
|
|
pr_info("%d: Fixing %016lx-%016lx %016lx vma\n",
|
|
|
|
pid, vi.start, vi.end, vi.pgoff);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (try_fixup_file_map(pid, &vi, fd))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (try_fixup_shared_map(pid, &vi, fd))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-28 18:44:46 +04:00
|
|
|
static inline bool should_restore_page(int pid, unsigned long va)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
struct shmem_info *si;
|
2011-09-28 18:44:46 +04:00
|
|
|
unsigned long shmid;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-09-28 18:44:46 +04:00
|
|
|
/*
|
|
|
|
* If this is not a shmem virtual address
|
|
|
|
* we should restore such page.
|
|
|
|
*/
|
|
|
|
shmid = find_shmem_id(va);
|
|
|
|
if (!shmid)
|
|
|
|
return true;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-09-28 18:44:46 +04:00
|
|
|
si = find_shmem(va, shmid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return si->pid == pid;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char zpage[PAGE_SIZE];
|
|
|
|
|
|
|
|
static int fixup_pages_data(int pid, int fd)
|
|
|
|
{
|
|
|
|
int shfd;
|
2011-09-28 21:20:53 +04:00
|
|
|
u32 magic;
|
|
|
|
u64 va;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_info("%d: Reading shmem pages img\n", pid);
|
2011-09-29 01:24:23 +04:00
|
|
|
|
2011-10-24 13:56:21 +04:00
|
|
|
shfd = open_fmt_ro("pages-shmem-%d.img", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (shfd < 0) {
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_perror("Can't open %d shmem image %s", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:20:53 +04:00
|
|
|
read(shfd, &magic, sizeof(magic));
|
|
|
|
if (magic != PAGES_MAGIC) {
|
2011-10-12 18:34:15 +04:00
|
|
|
pr_err("Bad %d shmem file magic number\n", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:20:53 +04:00
|
|
|
/*
|
|
|
|
* Find out the last page, which must be a zero page.
|
|
|
|
*/
|
2011-09-23 12:00:45 +04:00
|
|
|
lseek(fd, -sizeof(struct page_entry), SEEK_END);
|
2011-09-28 21:20:53 +04:00
|
|
|
read(fd, &va, sizeof(va));
|
|
|
|
if (va) {
|
|
|
|
pr_panic("Zero-page expected but got %lx\n", (unsigned long)va);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
2011-09-28 21:20:53 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we're to update pages we suppress old zero-page
|
|
|
|
* and will write new one at the end.
|
|
|
|
*/
|
2011-09-23 12:00:45 +04:00
|
|
|
lseek(fd, -sizeof(struct page_entry), SEEK_END);
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int ret;
|
|
|
|
|
2011-09-28 21:20:53 +04:00
|
|
|
ret = read(shfd, &va, sizeof(va));
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret == 0)
|
|
|
|
break;
|
|
|
|
|
2011-09-28 21:20:53 +04:00
|
|
|
if (ret < 0 || ret != sizeof(va)) {
|
2011-09-29 01:24:23 +04:00
|
|
|
pr_perror("Can't read virtual address");
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:20:53 +04:00
|
|
|
if (va == 0)
|
2011-09-23 12:00:45 +04:00
|
|
|
break;
|
|
|
|
|
2011-09-28 21:20:53 +04:00
|
|
|
if (!should_restore_page(pid, va)) {
|
2011-09-23 12:00:45 +04:00
|
|
|
lseek(shfd, PAGE_SIZE, SEEK_CUR);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:20:53 +04:00
|
|
|
pr_info("%d: Restoring shared page: %16lx\n",
|
|
|
|
pid, va);
|
|
|
|
|
|
|
|
write(fd, &va, sizeof(va));
|
2011-09-23 12:00:45 +04:00
|
|
|
sendfile(fd, shfd, NULL, PAGE_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(shfd);
|
2011-09-28 21:20:53 +04:00
|
|
|
va = 0;
|
|
|
|
write(fd, &va, sizeof(va));
|
2011-09-23 12:00:45 +04:00
|
|
|
write(fd, zpage, sizeof(zpage));
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_image_maps(int fd, int pid)
|
|
|
|
{
|
|
|
|
pr_info("%d: Fixing maps before executing image\n", pid);
|
|
|
|
|
|
|
|
if (fixup_vma_fds(pid, fd))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (fixup_pages_data(pid, fd))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-13 15:46:04 +04:00
|
|
|
static int prepare_and_execute_image(int pid)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
|
|
|
char path[128], elf_path[128];
|
|
|
|
int fd, fd_new;
|
|
|
|
struct stat buf;
|
|
|
|
|
2011-10-24 13:56:21 +04:00
|
|
|
fd = open_fmt_ro("core-%d.img", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (fd < 0) {
|
|
|
|
perror("Can't open exec image");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fstat(fd, &buf)) {
|
|
|
|
perror("Can't stat");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(path, "core-%d.img.out", pid);
|
|
|
|
unlink(path);
|
|
|
|
|
|
|
|
fd_new = open(path, O_RDWR | O_CREAT | O_EXCL, 0700);
|
|
|
|
if (fd_new < 0) {
|
|
|
|
perror("Can't open new image");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(elf_path, "core-%d.elf", pid);
|
|
|
|
unlink(elf_path);
|
|
|
|
|
|
|
|
pr_info("%d: Preparing execution image %s (%li bytes)\n", pid, path, buf.st_size);
|
|
|
|
if (sendfile(fd_new, fd, NULL, buf.st_size) != buf.st_size) {
|
|
|
|
pr_perror("sendfile failed\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (fchmod(fd_new, 0700)) {
|
|
|
|
perror("Can't prepare exec image");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fstat(fd_new, &buf)) {
|
|
|
|
perror("Can't stat");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("fd_new: %li bytes\n", buf.st_size);
|
|
|
|
|
|
|
|
if (prepare_image_maps(fd_new, pid))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
sync();
|
|
|
|
|
|
|
|
if (convert_to_elf(elf_path, fd_new))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
sync();
|
|
|
|
close(fd_new);
|
|
|
|
|
|
|
|
pr_info("%d/%d EXEC ELF-IMAGE\n", pid, getpid());
|
|
|
|
return execl(elf_path, elf_path, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int create_pipe(int pid, struct pipe_entry *e, struct pipe_info *pi, int pipes_fd)
|
|
|
|
{
|
|
|
|
unsigned long time = 1000;
|
2011-09-27 20:23:26 +04:00
|
|
|
int pfd[2], tmp;
|
2011-09-30 09:00:45 +04:00
|
|
|
int minusers = 1;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
pr_info("\t%d: Creating pipe %x\n", pid, e->pipeid);
|
|
|
|
|
|
|
|
if (pipe(pfd) < 0) {
|
|
|
|
perror("Can't create pipe");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e->bytes) {
|
|
|
|
pr_info("\t%d: Splicing data to %d\n", pid, pfd[1]);
|
|
|
|
|
|
|
|
tmp = splice(pipes_fd, NULL, pfd[1], NULL, e->bytes, 0);
|
|
|
|
if (tmp != e->bytes) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("Wanted to restore %d bytes, but got %d\n",
|
|
|
|
e->bytes, tmp);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (tmp < 0)
|
|
|
|
perror("Error splicing data");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pi->read_fd = pfd[0];
|
|
|
|
pi->write_fd = pfd[1];
|
|
|
|
pi->real_pid = getpid();
|
|
|
|
|
2011-10-13 17:31:52 +04:00
|
|
|
/*
|
|
|
|
* FIXME: xemul@ reported that this actually
|
|
|
|
* would not work if a task keeps pipe many times
|
|
|
|
* not just two. Need to review and fix propery.
|
|
|
|
*/
|
2011-09-30 09:00:45 +04:00
|
|
|
if (pipe_is_rw(pi))
|
|
|
|
minusers = 2;
|
|
|
|
|
|
|
|
pi->status |= PIPE_CREATED;
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
pr_info("\t%d: Done, waiting for others (users %d) on %d pid with r:%d w:%d\n",
|
2011-09-30 09:00:45 +04:00
|
|
|
pid, pi->users - minusers, pi->real_pid, pi->read_fd, pi->write_fd);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
while (1) {
|
2011-09-30 09:00:45 +04:00
|
|
|
if (pi->users <= minusers) /* only I left here, no need to wait */
|
2011-09-23 12:00:45 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
pr_info("\t%d: Waiting for %x pipe to attach (%d users left)\n",
|
2011-09-30 09:00:45 +04:00
|
|
|
pid, e->pipeid, pi->users - minusers);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (time < 20000000)
|
|
|
|
time <<= 1;
|
|
|
|
usleep(time);
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("\t%d: All is ok - reopening pipe for %d\n", pid, e->fd);
|
|
|
|
if (e->flags & O_WRONLY) {
|
2011-09-30 09:00:45 +04:00
|
|
|
if (!pipe_is_rw(pi))
|
|
|
|
close_safe(&pi->read_fd);
|
2011-09-27 18:50:02 +04:00
|
|
|
tmp = reopen_fd_as(e->fd, pi->write_fd);
|
2011-09-23 12:00:45 +04:00
|
|
|
} else {
|
2011-09-30 09:00:45 +04:00
|
|
|
if (!pipe_is_rw(pi))
|
|
|
|
close_safe(&pi->write_fd);
|
2011-09-27 18:50:02 +04:00
|
|
|
tmp = reopen_fd_as(e->fd, pi->read_fd);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
2011-09-27 18:48:57 +04:00
|
|
|
if (tmp < 0)
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int attach_pipe(int pid, struct pipe_entry *e, struct pipe_info *pi)
|
|
|
|
{
|
|
|
|
char path[128];
|
|
|
|
int tmp, fd;
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
pr_info("\t%d: Wating for pipe %x to appear\n",
|
|
|
|
pid, e->pipeid);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
while (pi->real_pid == 0)
|
|
|
|
usleep(1000);
|
|
|
|
|
|
|
|
if (e->flags & O_WRONLY)
|
|
|
|
tmp = pi->write_fd;
|
|
|
|
else
|
|
|
|
tmp = pi->read_fd;
|
|
|
|
|
2011-09-27 20:23:26 +04:00
|
|
|
if (tmp == -1) {
|
|
|
|
pr_panic("Attaching closed pipe\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
sprintf(path, "/proc/%d/fd/%d", pi->real_pid, tmp);
|
2011-09-28 01:09:34 +04:00
|
|
|
pr_info("\t%d: Attaching pipe %s (%d users left)\n",
|
|
|
|
pid, path, pi->users - 1);
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
fd = open(path, e->flags);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("Can't attach pipe");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("\t%d: Done, reopening for %d\n", pid, e->fd);
|
|
|
|
tmp = reopen_fd_as(e->fd, fd);
|
2011-09-27 18:48:57 +04:00
|
|
|
if (tmp < 0)
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
2011-09-28 01:09:34 +04:00
|
|
|
pi->users--;
|
2011-09-23 12:00:45 +04:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_pipe(int pid, struct pipe_entry *e, int *pipes_fd)
|
|
|
|
{
|
|
|
|
struct pipe_info *pi;
|
|
|
|
|
|
|
|
pr_info("\t%d: Opening pipe %x on fd %d\n", pid, e->pipeid, e->fd);
|
|
|
|
if (e->fd == *pipes_fd) {
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
tmp = dup(*pipes_fd);
|
|
|
|
if (tmp < 0) {
|
|
|
|
perror("Can't dup file");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pipes_fd = tmp;
|
|
|
|
}
|
|
|
|
|
2011-09-28 14:45:30 +04:00
|
|
|
pi = find_pipe(e->pipeid);
|
2011-09-28 01:09:34 +04:00
|
|
|
if (!pi) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("BUG: can't find my pipe %x\n", e->pipeid);
|
2011-09-23 12:00:45 +04:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2011-09-28 01:09:34 +04:00
|
|
|
/*
|
2011-09-30 09:00:45 +04:00
|
|
|
* This is somewhat tricky -- in case if a process uses
|
|
|
|
* both pipe ends the pipe should be created but only one
|
|
|
|
* pipe end get connected immediately in create_pipe the
|
|
|
|
* other pipe end should be connected via pipe attaching.
|
2011-09-28 01:09:34 +04:00
|
|
|
*/
|
2011-09-30 09:00:45 +04:00
|
|
|
if (pi->pid == pid && !(pi->status & PIPE_CREATED))
|
2011-09-23 12:00:45 +04:00
|
|
|
return create_pipe(pid, e, pi, *pipes_fd);
|
|
|
|
else
|
|
|
|
return attach_pipe(pid, e, pi);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int prepare_pipes(int pid)
|
|
|
|
{
|
|
|
|
int pipes_fd;
|
|
|
|
u32 type = 0;
|
|
|
|
|
|
|
|
pr_info("%d: Opening pipes\n", pid);
|
|
|
|
|
2011-10-24 13:56:21 +04:00
|
|
|
pipes_fd = open_fmt_ro("pipes-%d.img", pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (pipes_fd < 0) {
|
|
|
|
perror("Can't open pipes img");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
read(pipes_fd, &type, sizeof(type));
|
|
|
|
if (type != PIPES_MAGIC) {
|
|
|
|
perror("Bad pipes file");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
struct pipe_entry e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(pipes_fd, &e, sizeof(e));
|
|
|
|
if (ret == 0) {
|
|
|
|
close(pipes_fd);
|
2011-09-30 09:00:45 +04:00
|
|
|
break;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
2011-09-30 09:00:45 +04:00
|
|
|
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret != sizeof(e)) {
|
|
|
|
perror("Bad pipes entry");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (open_pipe(pid, &e, &pipes_fd))
|
|
|
|
return 1;
|
|
|
|
}
|
2011-09-30 09:00:45 +04:00
|
|
|
|
|
|
|
return 0;
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_one_task(int pid)
|
|
|
|
{
|
|
|
|
pr_info("%d: Restoring resources\n", pid);
|
|
|
|
|
|
|
|
if (prepare_pipes(pid))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (prepare_fds(pid))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (prepare_shmem(pid))
|
|
|
|
return 1;
|
|
|
|
|
2011-10-13 15:46:04 +04:00
|
|
|
return prepare_and_execute_image(pid);
|
2011-09-23 12:00:45 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int do_child(void *arg)
|
|
|
|
{
|
|
|
|
return restore_task_with_children(getpid(), arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int fork_with_pid(int pid, char *pstree_path)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
void *stack;
|
|
|
|
|
|
|
|
stack = mmap(0, 4 * 4096, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, 0, 0);
|
|
|
|
if (stack == MAP_FAILED) {
|
|
|
|
pr_perror("mmap failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
stack += 4 * 4096;
|
|
|
|
ret = clone(do_child, stack, SIGCHLD | CLONE_CHILD_USEPID, pstree_path, NULL, NULL, &pid);
|
|
|
|
if (ret < 0)
|
|
|
|
pr_perror("clone failed\n");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_task_with_children(int my_pid, char *pstree_path)
|
|
|
|
{
|
|
|
|
int *pids;
|
|
|
|
int fd, ret, i;
|
|
|
|
struct pstree_entry e;
|
|
|
|
|
|
|
|
pr_info("%d: Starting restore\n", my_pid);
|
|
|
|
|
|
|
|
fd = open(pstree_path, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
perror("Can't reopen pstree image");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
lseek(fd, sizeof(u32), SEEK_SET);
|
|
|
|
while (1) {
|
|
|
|
ret = read(fd, &e, sizeof(e));
|
|
|
|
if (ret != sizeof(e)) {
|
2011-09-30 14:37:12 +04:00
|
|
|
pr_err("%d: Read returned %d\n", my_pid, ret);
|
2011-09-23 12:00:45 +04:00
|
|
|
if (ret < 0)
|
|
|
|
perror("Can't read pstree");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.pid != my_pid) {
|
|
|
|
lseek(fd, e.nr_children * sizeof(u32), SEEK_CUR);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.nr_children > 0) {
|
|
|
|
i = e.nr_children * sizeof(int);
|
|
|
|
pids = malloc(i);
|
|
|
|
ret = read(fd, pids, i);
|
|
|
|
if (ret != i) {
|
|
|
|
perror("Can't read children pids");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
pr_info("%d: Restoring %d children:\n", my_pid, e.nr_children);
|
|
|
|
for (i = 0; i < e.nr_children; i++) {
|
|
|
|
pr_info("\tFork %d from %d\n", pids[i], my_pid);
|
|
|
|
ret = fork_with_pid(pids[i], pstree_path);
|
|
|
|
if (ret < 0)
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
shmem_update_real_pid(my_pid, getpid());
|
|
|
|
|
|
|
|
return restore_one_task(my_pid);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_root_task(char *pstree_path, int fd)
|
|
|
|
{
|
|
|
|
struct pstree_entry e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(fd, &e, sizeof(e));
|
|
|
|
if (ret != sizeof(e)) {
|
|
|
|
perror("Can't read root pstree entry");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
pr_info("Forking root with %d pid\n", e.pid);
|
|
|
|
ret = fork_with_pid(e.pid, pstree_path);
|
|
|
|
if (ret < 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
wait(NULL);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_all_tasks(pid_t pid)
|
|
|
|
{
|
|
|
|
char path[128];
|
|
|
|
int pstree_fd;
|
|
|
|
u32 type = 0;
|
|
|
|
|
|
|
|
sprintf(path, "pstree-%d.img", pid);
|
|
|
|
pstree_fd = open(path, O_RDONLY);
|
|
|
|
if (pstree_fd < 0) {
|
|
|
|
perror("Can't open pstree image");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
read(pstree_fd, &type, sizeof(type));
|
|
|
|
if (type != PSTREE_MAGIC) {
|
|
|
|
perror("Bad pstree magic");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prepare_shared(pstree_fd))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return restore_root_task(path, pstree_fd);
|
|
|
|
}
|
|
|
|
|
2011-10-25 21:25:42 +04:00
|
|
|
static void restorer_test(pid_t pid)
|
2011-10-24 22:23:06 +04:00
|
|
|
{
|
2011-10-26 18:13:06 +04:00
|
|
|
long code_len, vma_len, args_offset, new_sp;
|
2011-10-26 11:16:00 +04:00
|
|
|
void *args_rip, *exec_mem, *exec_start;
|
2011-10-25 21:25:42 +04:00
|
|
|
long ret;
|
2011-10-24 22:23:06 +04:00
|
|
|
|
2011-10-26 18:13:06 +04:00
|
|
|
struct restore_core_args *args;
|
2011-10-26 11:16:00 +04:00
|
|
|
restorer_fcall_t restorer_fcall;
|
|
|
|
char path[64];
|
|
|
|
|
|
|
|
restorer_fcall = restorer;
|
2011-10-26 18:13:06 +04:00
|
|
|
code_len = restorer_fcall(RESTORER_CMD__GET_SELF_LEN) - (long)restorer;
|
2011-10-26 11:16:00 +04:00
|
|
|
args_offset = restorer_fcall(RESTORER_CMD__GET_ARG_OFFSET) - (long)restorer;
|
2011-10-26 18:13:06 +04:00
|
|
|
code_len = round_up(code_len, 16);
|
|
|
|
vma_len = round_up(code_len + RESTORER_STACK_SIZE, PAGE_SIZE);
|
2011-10-26 11:16:00 +04:00
|
|
|
|
2011-10-26 00:30:41 +04:00
|
|
|
/* VMA we need to run restorer code */
|
2011-10-26 18:13:06 +04:00
|
|
|
exec_mem = mmap(0, vma_len,
|
2011-10-26 11:16:00 +04:00
|
|
|
PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
|
|
MAP_PRIVATE | MAP_ANON, 0, 0);
|
2011-10-24 22:23:06 +04:00
|
|
|
if (exec_mem == MAP_FAILED) {
|
2011-10-26 11:16:00 +04:00
|
|
|
pr_err("Can't mmap section for restore code\n");
|
2011-10-24 22:23:06 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-10-26 11:16:00 +04:00
|
|
|
/*
|
|
|
|
* Prepare a stack for the restorer. It's a bit
|
|
|
|
* tricky -- since compiler generates function
|
|
|
|
* prologue we need to manually tune up stack
|
|
|
|
* value.
|
|
|
|
*/
|
|
|
|
exec_start = exec_mem + RESTORER_STACK_SIZE;
|
|
|
|
memzero(exec_mem, RESTORER_STACK_SIZE);
|
|
|
|
|
2011-10-26 00:30:41 +04:00
|
|
|
/* Restorer content at the new location */
|
2011-10-26 18:13:06 +04:00
|
|
|
memcpy(exec_start, &restorer, code_len);
|
2011-10-26 11:16:00 +04:00
|
|
|
restorer_fcall = exec_start;
|
|
|
|
|
2011-10-26 17:35:50 +04:00
|
|
|
/*
|
|
|
|
* Stack pointer in a middle of allocated stack zone.
|
|
|
|
*/
|
|
|
|
new_sp = (long)exec_mem + RESTORER_STACK_MIDDLE;
|
2011-10-24 22:23:06 +04:00
|
|
|
|
2011-10-26 00:30:41 +04:00
|
|
|
/*
|
|
|
|
* Pass arguments and run a command.
|
|
|
|
*/
|
2011-10-25 21:25:42 +04:00
|
|
|
snprintf(path, sizeof(path), "core-%d.img", pid);
|
2011-10-26 11:16:00 +04:00
|
|
|
args = (struct restore_core_args *)(exec_start + args_offset);
|
2011-10-26 00:30:41 +04:00
|
|
|
args->self_entry = exec_mem;
|
2011-10-26 18:13:06 +04:00
|
|
|
args->self_size = vma_len;
|
2011-10-26 00:30:41 +04:00
|
|
|
strcpy(args->core_path, path);
|
2011-10-25 21:25:42 +04:00
|
|
|
|
2011-10-26 17:35:50 +04:00
|
|
|
/*
|
|
|
|
* An indirect call to restorer, note it never resturns
|
|
|
|
* and restoreing core is extremely destructive.
|
|
|
|
*/
|
2011-10-26 11:16:00 +04:00
|
|
|
asm volatile(
|
2011-10-26 17:35:50 +04:00
|
|
|
"movq %0, %%rbx \t\n"
|
|
|
|
"movq %1, %%rax \t\n"
|
|
|
|
"movl $"__stringify(RESTORER_CMD__RESTORE_CORE)", %%edi \t\n"
|
|
|
|
"movq %%rbx, %%rsp \t\n"
|
|
|
|
"callq *%%rax \t\n"
|
|
|
|
:
|
|
|
|
: "g"(new_sp), "g"(exec_start)
|
2011-10-26 11:16:00 +04:00
|
|
|
: "rsp", "rdi", "rbx", "rax", "memory");
|
|
|
|
|
2011-10-26 17:35:50 +04:00
|
|
|
/* Just to be sure */
|
|
|
|
sys_exit(0);
|
2011-10-24 22:23:06 +04:00
|
|
|
}
|
|
|
|
|
2011-10-04 01:50:19 +04:00
|
|
|
int cr_restore_tasks(pid_t pid, struct cr_options *opts)
|
2011-09-23 12:00:45 +04:00
|
|
|
{
|
2011-10-25 21:25:42 +04:00
|
|
|
restorer_test(pid);
|
2011-10-24 22:23:06 +04:00
|
|
|
|
2011-10-04 01:50:19 +04:00
|
|
|
if (opts->leader_only)
|
2011-09-23 12:00:45 +04:00
|
|
|
return restore_one_task(pid);
|
|
|
|
return restore_all_tasks(pid);
|
|
|
|
}
|