[lxc-devel] [lxc/master] confile: add maskedpaths and readonlypaths to protect unsafe places
tanyifeng on Github
lxc-bot at linuxcontainers.org
Wed Dec 13 08:17:00 UTC 2017
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 350 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171213/fccfdce3/attachment.bin>
-------------- next part --------------
From 00d48b0c230480aad999f2fb64a5290d126c430c Mon Sep 17 00:00:00 2001
From: Yifeng Tan <tanyifeng1 at huawei.com>
Date: Tue, 12 Dec 2017 02:29:36 +0800
Subject: [PATCH] confile: add maskedpaths and readonlypaths to protect unsafe
places
Signed-off-by: Yifeng Tan <tanyifeng1 at huawei.com>
---
doc/lxc.container.conf.sgml.in | 24 ++++++++
src/lxc/conf.c | 127 +++++++++++++++++++++++++++++++++++++++++
src/lxc/conf.h | 6 ++
src/lxc/confile.c | 104 +++++++++++++++++++++++++++++++++
src/tests/parse_config_file.c | 18 +++++-
5 files changed, 277 insertions(+), 2 deletions(-)
diff --git a/doc/lxc.container.conf.sgml.in b/doc/lxc.container.conf.sgml.in
index 7a6dd4841..eebd15c66 100644
--- a/doc/lxc.container.conf.sgml.in
+++ b/doc/lxc.container.conf.sgml.in
@@ -1200,6 +1200,30 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>
+ <option>lxc.rootfs.ropath</option>
+ </term>
+ <listitem>
+ <para>
+ Specifies paths within the container's rootfs to remount as read-only
+ so that these files prevent any writes.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <option>lxc.rootfs.maskedpath</option>
+ </term>
+ <listitem>
+ <para>
+ specifies paths within the container's rootfs to mask over with a bind
+ mount pointing to /dev/null as to prevent reads of the file.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect2>
diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 6a452064b..f1c628a3b 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2339,6 +2339,68 @@ static int parse_resource(const char *res) {
return -1;
}
+// 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, savederrno;
+
+ if (!path)
+ return true;
+
+ ret = mount("/dev/null", path, "", MS_BIND, "");
+ if (ret < 0 && errno != ENOENT) {
+ savederrno = errno;
+ if (savederrno == ENOTDIR) {
+ ret = mount("tmpfs", path, "tmpfs", MS_RDONLY, "");
+ if (ret < 0) {
+ savederrno = errno;
+ goto error;
+ }
+ return true;
+ }
+ goto error;
+ }
+
+ return true;
+
+error:
+ SYSERROR("Failed to mask path \"%s\": %s", path, strerror(savederrno));
+ return false;
+}
+
+// readonly_path will make a path read only.
+static bool readonly_path(const char *path)
+{
+
+ int ret, savederrno;
+
+ if (!path)
+ return true;
+
+ ret = mount(path, path, "", MS_BIND | MS_REC, "");
+ if (ret < 0) {
+ savederrno = errno;
+ if (savederrno == ENOENT)
+ return true;
+
+ goto error;
+ }
+
+ ret = mount(path, path, "", MS_BIND | MS_REMOUNT | MS_RDONLY | MS_REC, "");
+ if (ret < 0) {
+ savederrno = errno;
+ goto error;
+ }
+
+ return true;
+
+error:
+ SYSERROR("unable to mount \"%s\" to readonly: %s", path, strerror(savederrno));
+ return false;
+}
+
int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
struct lxc_list *it;
struct lxc_limit *lim;
@@ -2453,6 +2515,8 @@ struct lxc_conf *lxc_conf_init(void)
lxc_list_init(&new->hooks[i]);
lxc_list_init(&new->groups);
lxc_list_init(&new->state_clients);
+ lxc_list_init(&new->rootfs.maskedpaths);
+ lxc_list_init(&new->rootfs.ropaths);
new->lsm_aa_profile = NULL;
new->lsm_se_context = NULL;
new->tmp_umount_proc = 0;
@@ -3012,6 +3076,30 @@ void lxc_execute_bind_init(struct lxc_conf *conf)
INFO("lxc.init.static bound into container at %s", path);
}
+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;
+}
+
+static int setup_rootfs_ropaths(struct lxc_list *ropaths)
+{
+ struct lxc_list *it;
+
+ lxc_list_for_each(it, ropaths) {
+ if (!readonly_path((char *)it->elem))
+ return -1;
+ }
+
+ return 0;
+}
+
/*
* This does the work of remounting / if it is shared, calling the
* container pre-mount hooks, and mounting the rootfs.
@@ -3192,6 +3280,18 @@ int lxc_setup(struct lxc_handler *handler)
if (ret < 0)
return -1;
+ if (!lxc_list_empty(&lxc_conf->rootfs.ropaths)) {
+ ret = setup_rootfs_ropaths(&lxc_conf->rootfs.ropaths);
+ if (ret < 0)
+ return -1;
+ }
+
+ if (!lxc_list_empty(&lxc_conf->rootfs.maskedpaths)) {
+ ret = setup_rootfs_maskedpaths(&lxc_conf->rootfs.maskedpaths);
+ if (ret < 0)
+ return -1;
+ }
+
if (setup_personality(lxc_conf->personality)) {
ERROR("failed to setup personality");
return -1;
@@ -3408,6 +3508,31 @@ int lxc_clear_environment(struct lxc_conf *c)
return 0;
}
+
+int lxc_clear_rootfs_maskedpaths(struct lxc_conf *c)
+{
+ struct lxc_list *it,*next;
+
+ lxc_list_for_each_safe(it, &c->rootfs.maskedpaths, next) {
+ lxc_list_del(it);
+ free(it->elem);
+ free(it);
+ }
+ return 0;
+}
+
+int lxc_clear_rootfs_ropaths(struct lxc_conf *c)
+{
+ struct lxc_list *it,*next;
+
+ lxc_list_for_each_safe(it, &c->rootfs.ropaths, next) {
+ lxc_list_del(it);
+ free(it->elem);
+ free(it);
+ }
+ return 0;
+}
+
int lxc_clear_mount_entries(struct lxc_conf *c)
{
struct lxc_list *it,*next;
@@ -3522,6 +3647,8 @@ void lxc_conf_free(struct lxc_conf *conf)
lxc_clear_includes(conf);
lxc_clear_aliens(conf);
lxc_clear_environment(conf);
+ lxc_clear_rootfs_maskedpaths(conf);
+ lxc_clear_rootfs_ropaths(conf);
lxc_clear_limits(conf, "lxc.prlimit");
lxc_clear_sysctls(conf, "lxc.sysctl");
free(conf->cgroup_meta.dir);
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index e60a6151f..38126e633 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -185,12 +185,16 @@ struct lxc_console {
* @mount : where it is mounted
* @options : mount options
* @bev_type : optional backing store type
+ * @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;
char *mount;
char *options;
char *bdev_type;
+ struct lxc_list maskedpaths;
+ struct lxc_list ropaths;
};
/*
@@ -415,6 +419,8 @@ extern int lxc_clear_environment(struct lxc_conf *c);
extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
extern int lxc_delete_autodev(struct lxc_handler *handler);
extern void lxc_clear_includes(struct lxc_conf *conf);
+extern int lxc_clear_rootfs_maskedpaths(struct lxc_conf *c);
+extern int lxc_clear_rootfs_ropaths(struct lxc_conf *c);
extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
const char *lxcpath);
extern int lxc_setup(struct lxc_handler *handler);
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 584f93630..3caa52d80 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -132,6 +132,8 @@ lxc_config_define(rootfs_backend);
lxc_config_define(rootfs_mount);
lxc_config_define(rootfs_options);
lxc_config_define(rootfs_path);
+lxc_config_define(rootfs_maskedpath);
+lxc_config_define(rootfs_ropath);
lxc_config_define(seccomp_profile);
lxc_config_define(selinux_context);
lxc_config_define(signal_halt);
@@ -231,6 +233,8 @@ static struct lxc_config_t config[] = {
{ "lxc.rootfs.mount", false, set_config_rootfs_mount, get_config_rootfs_mount, clr_config_rootfs_mount, },
{ "lxc.rootfs.options", false, set_config_rootfs_options, get_config_rootfs_options, clr_config_rootfs_options, },
{ "lxc.rootfs.path", false, set_config_rootfs_path, get_config_rootfs_path, clr_config_rootfs_path, },
+ { "lxc.rootfs.maskedpath", false, set_config_rootfs_maskedpath, get_config_rootfs_maskedpath, clr_config_rootfs_maskedpath, },
+ { "lxc.rootfs.ropath", false, set_config_rootfs_ropath, get_config_rootfs_ropath, clr_config_rootfs_ropath, },
{ "lxc.seccomp.profile", false, set_config_seccomp_profile, get_config_seccomp_profile, clr_config_seccomp_profile, },
{ "lxc.selinux.context", false, set_config_selinux_context, get_config_selinux_context, clr_config_selinux_context, },
{ "lxc.signal.halt", false, set_config_signal_halt, get_config_signal_halt, clr_config_signal_halt, },
@@ -1125,6 +1129,58 @@ static int set_config_environment(const char *key, const char *value,
return -1;
}
+static int set_config_rootfs_maskedpath(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 clr_config_rootfs_maskedpath(key, lxc_conf, data);
+
+ list_item = malloc(sizeof(*list_item));
+ if (!list_item)
+ goto on_error;
+
+ list_item->elem = strdup(value);
+
+ if (!list_item->elem)
+ goto on_error;
+
+ lxc_list_add_tail(&lxc_conf->rootfs.maskedpaths, list_item);
+
+ return 0;
+
+on_error:
+ free(list_item);
+ return -1;
+}
+
+static int set_config_rootfs_ropath(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 clr_config_rootfs_ropath(key, lxc_conf, data);
+
+ list_item = malloc(sizeof(*list_item));
+ if (!list_item)
+ goto on_error;
+
+ list_item->elem = strdup(value);
+
+ if (!list_item->elem)
+ goto on_error;
+
+ lxc_list_add_tail(&lxc_conf->rootfs.ropaths, list_item);
+
+ return 0;
+
+on_error:
+ free(list_item);
+ return -1;
+}
+
static int set_config_tty_max(const char *key, const char *value,
struct lxc_conf *lxc_conf, void *data)
{
@@ -3278,6 +3334,42 @@ static int get_config_environment(const char *key, char *retv, int inlen,
return fulllen;
}
+static int get_config_rootfs_maskedpath(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
+{
+ int len, fulllen = 0;
+ struct lxc_list *it;
+
+ 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;
+}
+
+static int get_config_rootfs_ropath(const char *key, char *retv, int inlen,
+ struct lxc_conf *c, void *data)
+{
+ int len, fulllen = 0;
+ struct lxc_list *it;
+
+ 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;
+}
+
static int get_config_execute_cmd(const char *key, char *retv, int inlen,
struct lxc_conf *c, void *data)
{
@@ -3584,6 +3676,18 @@ static inline int clr_config_rootfs_backend(const char *key, struct lxc_conf *c,
return 0;
}
+static inline int clr_config_rootfs_maskedpath(const char *key, struct lxc_conf *c,
+ void *data)
+{
+ return lxc_clear_rootfs_maskedpaths(c);
+}
+
+static inline int clr_config_rootfs_ropath(const char *key, struct lxc_conf *c,
+ void *data)
+{
+ return lxc_clear_rootfs_ropaths(c);
+}
+
static inline int clr_config_uts_name(const char *key, struct lxc_conf *c,
void *data)
{
diff --git a/src/tests/parse_config_file.c b/src/tests/parse_config_file.c
index 556d6d034..6ca97986b 100644
--- a/src/tests/parse_config_file.c
+++ b/src/tests/parse_config_file.c
@@ -478,7 +478,7 @@ int main(int argc, char *argv[])
}
if (!c->get_config_item(c, "lxc.id_map", retval, sizeof(retval))) {
- lxc_error("%s\n", "failed to get config item \"lxc.cgroup\"");
+ lxc_error("%s\n", "failed to get config item \"lxc.id_map\"");
return -1;
}
@@ -506,7 +506,7 @@ int main(int argc, char *argv[])
}
if (!c->get_config_item(c, "lxc.idmap", retval, sizeof(retval))) {
- lxc_error("%s\n", "failed to get config item \"lxc.cgroup\"");
+ lxc_error("%s\n", "failed to get config item \"lxc.idmap\"");
return -1;
}
@@ -615,6 +615,20 @@ int main(int argc, char *argv[])
goto non_test_error;
}
+ /* lxc.rootfs.ropath */
+ if (set_get_compare_clear_save_load(c, "lxc.rootfs.ropath",
+ "/proc/fs", tmpf, false) < 0) {
+ lxc_error("%s\n", "lxc.rootfs.ropath");
+ goto non_test_error;
+ }
+
+ /* lxc.rootfs.mskedpath */
+ if (set_get_compare_clear_save_load(c, "lxc.rootfs.maskedpath",
+ "/proc/kcore", tmpf, false) < 0) {
+ lxc_error("%s\n", "lxc.rootfs.maskedpath");
+ goto non_test_error;
+ }
+
/* REMOVE IN LXC 3.0
legacy lxc.utsname key
*/
More information about the lxc-devel
mailing list