[CRIU] [PATCH] dump: unprotect vmas for dumping content

Andrey Vagin avagin at openvz.org
Fri Mar 29 11:52:51 EDT 2013


VMA-s may be protected against read, so rights for such VMA-s should be
changed for dumping and protected back after dumping.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-dump.c                  |  4 +---
 include/parasite-syscall.h |  3 +++
 include/parasite.h         | 14 +++++++++++
 parasite-syscall.c         | 60 +++++++++++++++++++++++++++++++++++++++++++++-
 pie/parasite.c             | 20 ++++++++++++++++
 5 files changed, 97 insertions(+), 4 deletions(-)

diff --git a/cr-dump.c b/cr-dump.c
index 8089331..c8e2779 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -1431,10 +1431,8 @@ static int dump_one_task(struct pstree_item *item)
 	}
 
 	ret = parasite_dump_pages_seized(parasite_ctl, item->pid.virt, &vmas, cr_fdset);
-	if (ret) {
-		pr_err("Can't dump pages (pid: %d) with parasite\n", pid);
+	if (ret)
 		goto err_cure;
-	}
 
 	ret = parasite_dump_sigacts_seized(parasite_ctl, cr_fdset);
 	if (ret) {
diff --git a/include/parasite-syscall.h b/include/parasite-syscall.h
index 6965470..bc75984 100644
--- a/include/parasite-syscall.h
+++ b/include/parasite-syscall.h
@@ -37,6 +37,9 @@ extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce)
 extern int parasite_dump_pages_seized(struct parasite_ctl *ctl, int vpid,
 				      struct vm_area_list *vma_area_list,
 				      struct cr_fdset *cr_fdset);
+extern int parasite_mprotect_seized(struct parasite_ctl *ctl,
+				    struct vm_area_list *vma_area_list,
+				    bool unprotect);
 struct parasite_dump_thread;
 struct pid;
 struct _CoreEntry;
diff --git a/include/parasite.h b/include/parasite.h
index 62c4179..5e4143c 100644
--- a/include/parasite.h
+++ b/include/parasite.h
@@ -24,6 +24,7 @@ enum {
 	PARASITE_CMD_FINI,
 	PARASITE_CMD_FINI_THREAD,
 
+	PARASITE_CMD_MPROTECT_VMAS,
 	PARASITE_CMD_DUMPPAGES,
 
 	PARASITE_CMD_DUMP_SIGACTS,
@@ -52,6 +53,19 @@ struct parasite_log_args {
 	int log_level;
 };
 
+struct parasite_vma_entry
+{
+	unsigned long	start;
+	unsigned long	len;
+	int		prot;
+};
+
+struct parasite_mprotect_args
+{
+	unsigned int		  nr;
+	struct parasite_vma_entry vmas[0];
+};
+
 struct parasite_dump_pages_args {
 	unsigned int	off;
 	unsigned int	nr;
diff --git a/parasite-syscall.c b/parasite-syscall.c
index c723bc8..d82995e 100644
--- a/parasite-syscall.c
+++ b/parasite-syscall.c
@@ -485,6 +485,12 @@ int parasite_dump_creds(struct parasite_ctl *ctl, CredsEntry *ce)
 	return 0;
 }
 
+static unsigned int vmas_mprotect_size(struct vm_area_list *vmas)
+{
+	return sizeof(struct parasite_mprotect_args) +
+		(vmas->nr * sizeof(struct parasite_vma_entry));
+}
+
 static unsigned int vmas_pagemap_size(struct vm_area_list *vmas)
 {
 	/*
@@ -545,7 +551,35 @@ static int generate_iovs(struct vma_area *vma, int pagemap, struct page_pipe *pp
 	return 0;
 }
 
-int parasite_dump_pages_seized(struct parasite_ctl *ctl, int vpid,
+int parasite_mprotect_seized(struct parasite_ctl *ctl, struct vm_area_list *vma_area_list, bool unprotect)
+{
+	struct parasite_mprotect_args *args;
+	struct parasite_vma_entry *p_vma;
+	struct vma_area *vma;
+
+	args = parasite_args_s(ctl, vmas_pagemap_size(vma_area_list));
+
+	p_vma = args->vmas;
+	args->nr = 0;
+
+	list_for_each_entry(vma, &vma_area_list->h, list) {
+		if (!privately_dump_vma(vma))
+			continue;
+		if (vma->vma.prot & PROT_READ)
+			continue;
+		p_vma->start = vma->vma.start;
+		p_vma->len = vma_area_len(vma);
+		p_vma->prot = vma->vma.prot;
+		if (unprotect)
+			p_vma->prot |= PROT_READ;
+		args->nr++;
+		p_vma++;
+	}
+
+	return parasite_execute(PARASITE_CMD_MPROTECT_VMAS, ctl);
+}
+
+static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, int vpid,
 		struct vm_area_list *vma_area_list, struct cr_fdset *cr_fdset)
 {
 	struct parasite_dump_pages_args *args;
@@ -624,6 +658,29 @@ out:
 	return ret;
 }
 
+int parasite_dump_pages_seized(struct parasite_ctl *ctl, int vpid,
+		struct vm_area_list *vma_area_list, struct cr_fdset *cr_fdset)
+{
+	int ret;
+
+	ret = parasite_mprotect_seized(ctl, vma_area_list, true);
+	if (ret) {
+		pr_err("Can't dump unprotect vmas with parasite\n");
+		return ret;
+	}
+
+	ret = __parasite_dump_pages_seized(ctl, vpid, vma_area_list, cr_fdset);
+	if (ret)
+		pr_err("Can't dump page with parasite\n");
+
+	if (parasite_mprotect_seized(ctl, vma_area_list, false)) {
+		pr_err("Can't rollback unprotected vmas with parasite\n");
+		ret = -1;
+	}
+
+	return ret;
+}
+
 int parasite_drain_fds_seized(struct parasite_ctl *ctl,
 		struct parasite_drain_fd *dfds, int *lfds, struct fd_opts *opts)
 {
@@ -852,6 +909,7 @@ static unsigned long parasite_args_size(struct vm_area_list *vmas, struct parasi
 
 	size = max(size, (unsigned long)drain_fds_size(dfds));
 	size = max(size, (unsigned long)vmas_pagemap_size(vmas));
+	size = max(size, (unsigned long)vmas_mprotect_size(vmas));
 
 	return size;
 }
diff --git a/pie/parasite.c b/pie/parasite.c
index bfda754..9acb138 100644
--- a/pie/parasite.c
+++ b/pie/parasite.c
@@ -34,6 +34,24 @@ static unsigned int next_tid_state;
 #define SPLICE_F_GIFT	0x08
 #endif
 
+static int mprotect_vmas(struct parasite_mprotect_args *args)
+{
+	struct parasite_vma_entry *vma;
+	int ret = 0, i;
+
+	for (i = 0; i < args->nr; i++) {
+		vma = args->vmas + i;
+		ret = sys_mprotect((void *)vma->start, vma->len, vma->prot);
+		if (ret) {
+			pr_err("mprotect(%08lx, %lu) failed with code %d\n",
+						vma->start, vma->len, ret);
+			break;
+		}
+	}
+
+	return ret;
+}
+
 static int dump_pages(struct parasite_dump_pages_args *args)
 {
 	int p, ret;
@@ -425,6 +443,8 @@ int __used parasite_service(unsigned int cmd, void *args)
 		return parasite_cfg_log(args);
 	case PARASITE_CMD_DUMPPAGES:
 		return dump_pages(args);
+	case PARASITE_CMD_MPROTECT_VMAS:
+		return mprotect_vmas(args);
 	case PARASITE_CMD_DUMP_SIGACTS:
 		return dump_sigact(args);
 	case PARASITE_CMD_DUMP_ITIMERS:
-- 
1.7.11.7



More information about the CRIU mailing list