[CRIU] [PATCH 4/4] parasite: Load PIE blob via memfd

Pavel Emelyanov xemul at parallels.com
Thu Sep 24 15:03:20 PDT 2015


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 3af077b..c41abc1 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 8beb80f..2deab77 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 64cec51..bec6649 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 ee339db..9406f84 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;
 
-- 
1.9.3




More information about the CRIU mailing list