[CRIU] [PATCH 04/10] parasite: Load PIE blob via memfd
Cyrill Gorcunov
gorcunov at openvz.org
Mon Sep 28 12:01:36 PDT 2015
From: Pavel Emelyanov <xemul at parallels.com>
Currently parasite is loaded using the map_files dir. When
we're not allowed to do it, we can still try to go via the
new memfd (4.0 has one).
Signed-off-by: Pavel Emelyanov <xemul at parallels.com>
---
cr-dump.c | 4 +--
cr-exec.c | 2 +-
include/parasite-syscall.h | 8 +++--
parasite-syscall.c | 77 ++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/cr-dump.c b/cr-dump.c
index 3af077b0b1ef..c41abc1b4cd4 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1080,7 +1080,7 @@ static int pre_dump_one_task(struct pstree_item *item, struct list_head *ctls)
}
ret = -1;
- parasite_ctl = parasite_infect_seized(pid, item, &vmas);
+ parasite_ctl = parasite_infect_seized(pid, item, &vmas, NULL);
if (!parasite_ctl) {
pr_err("Can't infect (pid: %d) with parasite\n", pid);
goto err_free;
@@ -1187,7 +1187,7 @@ static int dump_one_task(struct pstree_item *item)
goto err;
}
- parasite_ctl = parasite_infect_seized(pid, item, &vmas);
+ parasite_ctl = parasite_infect_seized(pid, item, &vmas, &pps_buf);
if (!parasite_ctl) {
pr_err("Can't infect (pid: %d) with parasite\n", pid);
goto err;
diff --git a/cr-exec.c b/cr-exec.c
index 8beb80f88914..2deab7797b05 100644
--- a/cr-exec.c
+++ b/cr-exec.c
@@ -53,7 +53,7 @@ static int execute_syscall(struct parasite_ctl *ctl,
int len;
if (!r_mem) {
- err = parasite_map_exchange(ctl, PAGE_SIZE);
+ err = parasite_map_exchange(ctl, PAGE_SIZE, NULL);
if (err)
return err;
diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 64cec51b5017..bec66497640c 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -93,16 +93,20 @@ extern int parasite_drain_fds_seized(struct parasite_ctl *ctl,
int *lfds, struct fd_opts *flags);
extern int parasite_get_proc_fd_seized(struct parasite_ctl *ctl);
+struct proc_pid_stat;
+
extern int parasite_cure_remote(struct parasite_ctl *ctl);
extern int parasite_cure_local(struct parasite_ctl *ctl);
extern int parasite_cure_seized(struct parasite_ctl *ctl);
extern struct parasite_ctl *parasite_infect_seized(pid_t pid,
struct pstree_item *item,
- struct vm_area_list *vma_area_list);
+ struct vm_area_list *vma_area_list,
+ struct proc_pid_stat *pps);
extern void parasite_ensure_args_size(unsigned long sz);
extern struct parasite_ctl *parasite_prep_ctl(pid_t pid,
struct vm_area_list *vma_area_list);
-extern int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size);
+extern int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size,
+ struct proc_pid_stat *pps);
extern struct parasite_tty_args *parasite_dump_tty(struct parasite_ctl *ctl, int fd, int type);
diff --git a/parasite-syscall.c b/parasite-syscall.c
index ee339db5d344..9406f84ac544 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -1116,7 +1116,7 @@ err:
return NULL;
}
-int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size)
+static int parasite_mmap_exchange(struct parasite_ctl *ctl, unsigned long size)
{
int fd;
@@ -1148,6 +1148,77 @@ int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size)
return 0;
}
+static int parasite_memfd_exchange(struct parasite_ctl *ctl, unsigned long size,
+ struct proc_pid_stat *pps)
+{
+ unsigned long sret;
+ int ret, fd, lfd;
+
+ ret = syscall_seized(ctl, __NR_memfd_create, &sret,
+ pps->arg_start, 0, 0, 0, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ fd = (int)(long)sret;
+ if (fd == -ENOSYS)
+ return 1;
+ if (fd < 0)
+ return fd;
+
+ ctl->map_length = round_up(size, page_size());
+ lfd = open_proc_rw(ctl->pid.real, "fd/%d", fd);
+ if (lfd < 0)
+ goto err_cure;
+
+ if (ftruncate(lfd, ctl->map_length) < 0) {
+ pr_perror("Fail to truncate memfd for parasite");
+ goto err_cure;
+ }
+
+ ctl->remote_map = mmap_seized(ctl, NULL, size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_FILE | MAP_SHARED, fd, 0);
+ if (!ctl->remote_map) {
+ pr_err("Can't rmap memfd for parasite blob\n");
+ goto err_curef;
+ }
+
+ ctl->local_map = mmap(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FILE, lfd, 0);
+ if (ctl->local_map == MAP_FAILED) {
+ ctl->local_map = NULL;
+ pr_perror("Can't lmap memfd for parasite blob");
+ goto err_curef;
+ }
+
+ syscall_seized(ctl, __NR_close, &sret, fd, 0, 0, 0, 0, 0);
+ close(lfd);
+
+ pr_info("Set up parasite blob using memfd\n");
+ return 0;
+
+err_curef:
+ close(lfd);
+err_cure:
+ syscall_seized(ctl, __NR_close, &sret, fd, 0, 0, 0, 0, 0);
+ return -1;
+}
+
+int parasite_map_exchange(struct parasite_ctl *ctl, unsigned long size,
+ struct proc_pid_stat *pps)
+{
+ int ret = 1;
+
+ if (pps)
+ ret = parasite_memfd_exchange(ctl, size, pps);
+ if (ret == 1) {
+ pr_info("MemFD parasite doesn't work, goto legacy mmap\n");
+ ret = parasite_mmap_exchange(ctl, size);
+ }
+
+ return ret;
+}
+
static unsigned long parasite_args_size = PARASITE_ARG_SIZE_MIN;
void parasite_ensure_args_size(unsigned long sz)
{
@@ -1180,7 +1251,7 @@ static int parasite_start_daemon(struct parasite_ctl *ctl, struct pstree_item *i
}
struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
- struct vm_area_list *vma_area_list)
+ struct vm_area_list *vma_area_list, struct proc_pid_stat *pps)
{
int ret;
struct parasite_ctl *ctl;
@@ -1211,7 +1282,7 @@ struct parasite_ctl *parasite_infect_seized(pid_t pid, struct pstree_item *item,
memcpy(&item->core[0]->tc->blk_sigset, &ctl->orig.sigmask, sizeof(k_rtsigset_t));
- ret = parasite_map_exchange(ctl, map_exchange_size);
+ ret = parasite_map_exchange(ctl, map_exchange_size, pps);
if (ret)
goto err_restore;
--
2.4.3
More information about the CRIU
mailing list