Blob Blame History Raw
From 0a2d380e6b9110ec809101757c243ce316f4d1bb Mon Sep 17 00:00:00 2001
From: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
Date: Thu, 13 Feb 2020 18:28:15 +0300
Subject: [PATCH 057/120] ghost/mount: allocate remounted_rw in shmem to get
 info from other processes

Previousely remounted_rw was not shared between all processes on
restore, thus cleanup didn't got this info from rfi_remap and these
mounts were wrongly left writable after restore.

Cherry-picked from Virtuozzo criu:
https://src.openvz.org/projects/OVZ/repos/criu/commits/3a1a592e7

Fixes: fd0a3cd9efb9 ("mount: remount ro mounts writable before
ghost-file restore")
Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
---
 criu/include/mount.h |  4 ++--
 criu/mount.c         | 32 ++++++++++++++++++++++----------
 criu/proc_parse.c    |  2 +-
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/criu/include/mount.h b/criu/include/mount.h
index 833a75ca0..7705279e4 100644
--- a/criu/include/mount.h
+++ b/criu/include/mount.h
@@ -84,7 +84,7 @@ struct mount_info {
 	struct list_head postpone;
 
 	int is_overmounted;
-	int remounted_rw;
+	int *remounted_rw;
 
 	void *private; /* associated filesystem data */
 };
@@ -100,7 +100,7 @@ static inline int collect_binfmt_misc(void)
 }
 #endif
 
-extern struct mount_info *mnt_entry_alloc(void);
+extern struct mount_info *mnt_entry_alloc(bool rst);
 extern void mnt_entry_free(struct mount_info *mi);
 
 extern int __mntns_get_root_fd(pid_t pid);
diff --git a/criu/mount.c b/criu/mount.c
index 93725e526..d75ca5598 100644
--- a/criu/mount.c
+++ b/criu/mount.c
@@ -27,6 +27,7 @@
 #include "external.h"
 #include "clone-noasan.h"
 #include "fdstore.h"
+#include "rst-malloc.h"
 
 #include "images/mnt.pb-c.h"
 
@@ -1415,7 +1416,8 @@ err:
 	return -1;
 }
 
-static __maybe_unused int add_cr_time_mount(struct mount_info *root, char *fsname, const char *path, unsigned int s_dev)
+static __maybe_unused int add_cr_time_mount(struct mount_info *root, char *fsname, const char *path, unsigned int s_dev,
+					    bool rst)
 {
 	struct mount_info *mi, *t, *parent;
 	bool add_slash = false;
@@ -1434,7 +1436,7 @@ static __maybe_unused int add_cr_time_mount(struct mount_info *root, char *fsnam
 		}
 	}
 
-	mi = mnt_entry_alloc();
+	mi = mnt_entry_alloc(rst);
 	if (!mi)
 		return -1;
 
@@ -2723,7 +2725,7 @@ err_root:
 	return exit_code;
 }
 
-struct mount_info *mnt_entry_alloc()
+struct mount_info *mnt_entry_alloc(bool rst)
 {
 	struct mount_info *new;
 
@@ -2734,6 +2736,13 @@ struct mount_info *mnt_entry_alloc()
 
 	new = xzalloc(sizeof(struct mount_info));
 	if (new) {
+		if (rst) {
+			new->remounted_rw = shmalloc(sizeof(int));
+			if (!new->remounted_rw) {
+				xfree(new);
+				return NULL;
+			}
+		}
 		new->fd = -1;
 		new->is_overmounted = -1;
 		INIT_LIST_HEAD(&new->children);
@@ -2956,7 +2965,7 @@ static int collect_mnt_from_image(struct mount_info **head, struct mount_info **
 		if (ret <= 0)
 			break;
 
-		pm = mnt_entry_alloc();
+		pm = mnt_entry_alloc(true);
 		if (!pm)
 			goto err;
 
@@ -3234,7 +3243,7 @@ static int populate_mnt_ns(void)
 {
 	int ret;
 
-	root_yard_mp = mnt_entry_alloc();
+	root_yard_mp = mnt_entry_alloc(true);
 	if (!root_yard_mp)
 		return -1;
 
@@ -3247,7 +3256,7 @@ static int populate_mnt_ns(void)
 #ifdef CONFIG_BINFMT_MISC_VIRTUALIZED
 	if (!opts.has_binfmt_misc && !list_empty(&binfmt_misc_list)) {
 		/* Add to mount tree. Generic code will mount it later */
-		ret = add_cr_time_mount(root_yard_mp, "binfmt_misc", BINFMT_MISC_HOME, 0);
+		ret = add_cr_time_mount(root_yard_mp, "binfmt_misc", BINFMT_MISC_HOME, 0, true);
 		if (ret)
 			return -1;
 	}
@@ -3697,7 +3706,7 @@ int collect_mnt_namespaces(bool for_dump)
 				ret = -1;
 				goto err;
 			} else if (ret > 0 && add_cr_time_mount(ns->mnt.mntinfo_tree, "binfmt_misc", BINFMT_MISC_HOME,
-								s_dev) < 0) {
+								s_dev, false) < 0) {
 				ret = -1;
 				goto err;
 			}
@@ -3838,7 +3847,10 @@ int try_remount_writable(struct mount_info *mi, bool ns)
 	if (!ns)
 		remounted = REMOUNTED_RW_SERVICE;
 
-	if (mi->flags & MS_RDONLY && !(mi->remounted_rw & remounted)) {
+	/* All mounts in mntinfo list should have it on restore */
+	BUG_ON(mi->remounted_rw == NULL);
+
+	if (mi->flags & MS_RDONLY && !(*mi->remounted_rw & remounted)) {
 		if (mnt_is_overmounted(mi)) {
 			pr_err("The mount %d is overmounted so paths are invisible\n", mi->mnt_id);
 			return -1;
@@ -3861,7 +3873,7 @@ int try_remount_writable(struct mount_info *mi, bool ns)
 			if (call_helper_process(ns_remount_writable, mi))
 				return -1;
 		}
-		mi->remounted_rw |= remounted;
+		*mi->remounted_rw |= remounted;
 	}
 
 	return 0;
@@ -3876,7 +3888,7 @@ static int __remount_readonly_mounts(struct ns_id *ns)
 		if (ns && mi->nsid != ns)
 			continue;
 
-		if (!(mi->remounted_rw && REMOUNTED_RW))
+		if (!(*mi->remounted_rw && REMOUNTED_RW))
 			continue;
 
 		/*
diff --git a/criu/proc_parse.c b/criu/proc_parse.c
index 8a9ce3a37..094f9b84e 100644
--- a/criu/proc_parse.c
+++ b/criu/proc_parse.c
@@ -1541,7 +1541,7 @@ struct mount_info *parse_mountinfo(pid_t pid, struct ns_id *nsid, bool for_dump)
 		int ret = -1;
 		char *fsname = NULL;
 
-		new = mnt_entry_alloc();
+		new = mnt_entry_alloc(false);
 		if (!new)
 			goto end;
 
-- 
2.34.1