From c5ea37649d728630df34e1af22908b8e8124f772 Mon Sep 17 00:00:00 2001
From: wujing <wujing50@huawei.com>
Date: Mon, 13 Apr 2020 09:11:21 -0400
Subject: [PATCH 15/49] add masked paths and readonly paths

Signed-off-by: wujing <wujing50@huawei.com>
---
 src/lxc/conf.c    | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/lxc/conf.h    |  12 +++++
 src/lxc/confile.c | 106 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 256 insertions(+), 1 deletion(-)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a904348..fce241b 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -1275,6 +1275,96 @@ static int lxc_mount_rootfs(struct lxc_conf *conf)
 	return 0;
 }
 
+#ifdef HAVE_ISULAD
+// maskPath masks the top of the specified path inside a container to avoid
+// security issues from processes reading information from non-namespace aware
+// mounts ( proc/kcore ).
+static bool mask_path(const char *path)
+{
+	int ret;
+
+	if (!path)
+		return true;
+
+	ret = mount("/dev/null", path, "", MS_BIND, "");
+	if (ret < 0 && errno != ENOENT) {
+		if (errno == ENOTDIR) {
+			ret = mount("tmpfs", path, "tmpfs", MS_RDONLY, "");
+			if (ret < 0)
+				goto error;
+			return true;
+		}
+		goto error;
+	}
+	return true;
+
+error:
+	SYSERROR("Failed to mask path \"%s\": %s", path, strerror(errno));
+	return false;
+}
+
+// remount_readonly will bind over the top of an existing path and ensure that it is read-only.
+static bool remount_readonly(const char *path)
+{
+	int ret, i;
+
+	if (!path)
+		return true;
+
+	for (i = 0; i < 5; i++) {
+		ret = mount("", path, "", MS_REMOUNT | MS_RDONLY, "");
+		if (ret < 0 && errno != ENOENT) {
+			if (errno == EINVAL) {
+				// Probably not a mountpoint, use bind-mount
+				ret = mount(path, path, "", MS_BIND, "");
+				if (ret < 0)
+					goto on_error;
+				ret = mount(path, path, "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC | \
+				            MS_NOEXEC | MS_NOSUID | MS_NODEV, "");
+				if (ret < 0)
+					goto on_error;
+			} else if (errno == EBUSY) {
+				DEBUG("Try to mount \"%s\" to readonly after 100ms.", path);
+				usleep(100 * 1000);
+				continue;
+			} else {
+				goto on_error;
+			}
+		}
+		return true;
+	}
+
+on_error:
+	SYSERROR("Unable to mount \"%s\" to readonly", path);
+	return false;
+}
+
+// isulad: setup rootfs masked paths
+static int setup_rootfs_maskedpaths(struct lxc_list *maskedpaths)
+{
+	struct lxc_list *it;
+
+	lxc_list_for_each(it, maskedpaths) {
+		if (!mask_path((char *)it->elem))
+			return -1;
+	}
+
+	return 0;
+}
+// isulad: setup rootfs ro paths
+static int setup_rootfs_ropaths(struct lxc_list *ropaths)
+{
+	struct lxc_list *it;
+
+	lxc_list_for_each(it, ropaths) {
+		if (!remount_readonly((char *)it->elem))
+			return -1;
+	}
+
+	return 0;
+}
+#endif
+
 int lxc_chroot(const struct lxc_rootfs *rootfs)
 {
 	__do_free char *nroot = NULL;
@@ -2666,8 +2756,9 @@ struct lxc_conf *lxc_conf_init(void)
 	seccomp_conf_init(new);
 
 #ifdef HAVE_ISULAD
-	/* isulad add begin */
 	lxc_list_init(&new->populate_devs);
+	lxc_list_init(&new->rootfs.maskedpaths);
+	lxc_list_init(&new->rootfs.ropaths);
 	new->exit_fd = -1;
 	new->umask = 0027; /*default umask 0027*/
 	new->console.init_fifo[0] = NULL;
@@ -3690,6 +3781,22 @@ int lxc_setup(struct lxc_handler *handler)
 			return log_error(-1, "Failed to setup sysctl parameters");
 	}
 
+#ifdef HAVE_ISULAD
+	// isulad: setup rootfs masked paths
+	if (!lxc_list_empty(&lxc_conf->rootfs.maskedpaths)) {
+		if (setup_rootfs_maskedpaths(&lxc_conf->rootfs.maskedpaths)) {
+			return log_error(-1, "failed to setup maskedpaths");
+		}
+	}
+
+	// isulad: setup rootfs ro paths
+	if (!lxc_list_empty(&lxc_conf->rootfs.ropaths)) {
+		if (setup_rootfs_ropaths(&lxc_conf->rootfs.ropaths)) {
+			return log_error(-1, "failed to setup readonlypaths");
+		}
+	}
+#endif
+
 	if (!lxc_list_empty(&lxc_conf->keepcaps)) {
 		if (!lxc_list_empty(&lxc_conf->caps))
 			return log_error(-1, "Container requests lxc.cap.drop and lxc.cap.keep: either use lxc.cap.drop or lxc.cap.keep, not both");
@@ -4103,6 +4210,8 @@ void lxc_conf_free(struct lxc_conf *conf)
 	}
 	lxc_clear_init_args(conf);
 	lxc_clear_populate_devices(conf);
+	lxc_clear_rootfs_masked_paths(conf);
+	lxc_clear_rootfs_ro_paths(conf);
 #endif
 	free(conf);
 }
@@ -4945,4 +5054,32 @@ int lxc_clear_populate_devices(struct lxc_conf *c)
 	return 0;
 }
 
+/*isulad: clear rootfs masked paths*/
+int lxc_clear_rootfs_masked_paths(struct lxc_conf *c)
+{
+	struct lxc_list *it = NULL;
+	struct lxc_list *next = NULL;
+
+	lxc_list_for_each_safe(it, &c->rootfs.maskedpaths, next) {
+		lxc_list_del(it);
+		free(it->elem);
+		free(it);
+	}
+	return 0;
+}
+
+/*isulad: clear rootfs ro paths*/
+int lxc_clear_rootfs_ro_paths(struct lxc_conf *c)
+{
+	struct lxc_list *it = NULL;
+	struct lxc_list *next = NULL;
+
+	lxc_list_for_each_safe(it, &c->rootfs.ropaths, next) {
+		lxc_list_del(it);
+		free(it->elem);
+		free(it);
+	}
+	return 0;
+}
+
 #endif
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 52460a3..482fe0d 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -143,6 +143,8 @@ struct lxc_tty_info {
  * @mountflags : the portion of @options that are flags
  * @data       : the portion of @options that are not flags
  * @managed    : whether it is managed by LXC
+ * @maskedpaths: A list of paths to be msked over inside the container
+ * @ropaths    : A list of paths to be remounted with readonly inside the container
  */
 struct lxc_rootfs {
 	char *path;
@@ -152,6 +154,14 @@ struct lxc_rootfs {
 	unsigned long mountflags;
 	char *data;
 	bool managed;
+
+#ifdef HAVE_ISULAD
+    /* isulad: maskedpaths */
+    struct lxc_list maskedpaths;
+    /* isulad: ropaths */
+    struct lxc_list ropaths;
+#endif
+
 };
 
 /*
@@ -511,5 +521,7 @@ extern int userns_exec_minimal(const struct lxc_conf *conf,
 #ifdef HAVE_ISULAD
 int lxc_clear_init_args(struct lxc_conf *lxc_conf);
 int lxc_clear_populate_devices(struct lxc_conf *c);
+int lxc_clear_rootfs_masked_paths(struct lxc_conf *c);
+int lxc_clear_rootfs_ro_paths(struct lxc_conf *c);
 #endif
 #endif /* __LXC_CONF_H */
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 2df269a..bf0fdf0 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -151,6 +151,8 @@ lxc_config_define(proc);
 lxc_config_define(init_args);
 lxc_config_define(populate_device);
 lxc_config_define(umask);
+lxc_config_define(rootfs_masked_paths);
+lxc_config_define(rootfs_ro_paths);
 #endif
 
 /*
@@ -268,6 +270,8 @@ static struct lxc_config_t config_jump_table[] = {
 	{ "lxc.isulad.init.args",          set_config_init_args,                   get_config_init_args,                   clr_config_init_args,                 },
 	{ "lxc.isulad.populate.device",    set_config_populate_device,             get_config_populate_device,             clr_config_populate_device,           },
 	{ "lxc.isulad.umask",              set_config_umask,                       get_config_umask,                       clr_config_umask,                     },
+	{ "lxc.isulad.rootfs.maskedpaths", set_config_rootfs_masked_paths,         get_config_rootfs_masked_paths,         clr_config_rootfs_masked_paths,       },
+	{ "lxc.isulad.rootfs.ropaths",     set_config_rootfs_ro_paths,             get_config_rootfs_ro_paths,             clr_config_rootfs_ro_paths,           },
 #endif
 };
 
@@ -6311,4 +6315,106 @@ static inline int clr_config_umask(const char *key, struct lxc_conf *c,
 	return 0;
 }
 
+/* isulad: set config for rootfs masked paths */
+static int set_config_rootfs_masked_paths(const char *key, const char *value,
+                struct lxc_conf *lxc_conf, void *data)
+{
+	struct lxc_list *list_item = NULL;
+
+	if (lxc_config_value_empty(value))
+		return lxc_clear_rootfs_masked_paths(lxc_conf);
+
+	list_item = malloc(sizeof(*list_item));
+	if (list_item == NULL)
+		goto on_error;
+
+	list_item->elem = safe_strdup(value);
+
+	lxc_list_add_tail(&lxc_conf->rootfs.maskedpaths, list_item);
+
+	return 0;
+
+on_error:
+	free(list_item);
+
+	return -1;
+}
+
+// isulad: get config rootfs masked paths
+static int get_config_rootfs_masked_paths(const char *key, char *retv, int inlen,
+                struct lxc_conf *c, void *data)
+{
+	int len, fulllen = 0;
+	struct lxc_list *it = NULL;
+
+	if (!retv)
+		inlen = 0;
+	else
+		memset(retv, 0, inlen);
+
+	lxc_list_for_each(it, &c->rootfs.maskedpaths) {
+		strprint(retv, inlen, "%s\n", (char *)it->elem);
+	}
+
+	return fulllen;
+}
+
+/* isulad: set config for rootfs ro paths */
+static int set_config_rootfs_ro_paths(const char *key, const char *value,
+                                      struct lxc_conf *lxc_conf, void *data)
+{
+	struct lxc_list *list_item = NULL;
+
+	if (lxc_config_value_empty(value))
+		return lxc_clear_rootfs_ro_paths(lxc_conf);
+
+	list_item = malloc(sizeof(*list_item));
+	if (list_item == NULL)
+		goto on_error;
+
+	list_item->elem = safe_strdup(value);
+
+	lxc_list_add_tail(&lxc_conf->rootfs.ropaths, list_item);
+
+	return 0;
+
+on_error:
+	free(list_item);
+
+	return -1;
+}
+
+// isulad: get config rootfs ro paths
+static int get_config_rootfs_ro_paths(const char *key, char *retv, int inlen,
+                                      struct lxc_conf *c, void *data)
+{
+	int len, fulllen = 0;
+	struct lxc_list *it = NULL;
+
+	if (!retv)
+		inlen = 0;
+	else
+		memset(retv, 0, inlen);
+
+	lxc_list_for_each(it, &c->rootfs.ropaths) {
+		strprint(retv, inlen, "%s\n", (char *)it->elem);
+	}
+
+	return fulllen;
+}
+
+/* isulad: clr config rootfs masked paths */
+static inline int clr_config_rootfs_masked_paths(const char *key, struct lxc_conf *c,
+                void *data)
+{
+	return lxc_clear_rootfs_masked_paths(c);
+}
+
+/* isulad: clr config rootfs ro paths */
+static inline int clr_config_rootfs_ro_paths(const char *key, struct lxc_conf *c,
+                void *data)
+{
+	return lxc_clear_rootfs_ro_paths(c);
+}
+
 #endif
-- 
1.8.3.1

