The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/2300

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
Hi there!
This is an initial step for moving the mount injection stuff from LXD to LXC. 
In this PR, the new `lxc_container` API method `mount` is introduced, alongside with the supporting config option `shmounts` for `lxc.mount.auto` (because in order to enable mount injection in the running container, a shared mount point is established between on a startup) and the necessary utils.
From 5f8aabfc231000249d2d11fd0f3b49aee6826570 Mon Sep 17 00:00:00 2001
From: Liza Tretyakova <[email protected]>
Date: Wed, 2 May 2018 10:09:34 +0300
Subject: [PATCH 1/6] conf, confile: introduce basic structs for shared mount
 point

Signed-off-by: Liza Tretyakova <[email protected]>
---
 src/lxc/conf.c    |  4 ++++
 src/lxc/conf.h    | 10 ++++++++++
 src/lxc/confile.c |  1 +
 3 files changed, 15 insertions(+)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index 48c4b4ecc..a52331c86 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -2665,6 +2665,8 @@ struct lxc_conf *lxc_conf_init(void)
        new->lsm_aa_profile = NULL;
        new->lsm_se_context = NULL;
        new->tmp_umount_proc = 0;
+       new->lxc_shmount.path_host = NULL;
+       new->lxc_shmount.path_cont = NULL;
 
        /* if running in a new user namespace, init and COMMAND
         * default to running as UID/GID 0 when using lxc-execute */
@@ -3869,6 +3871,8 @@ void lxc_conf_free(struct lxc_conf *conf)
        lxc_clear_procs(conf, "lxc.proc");
        free(conf->cgroup_meta.dir);
        free(conf->cgroup_meta.controllers);
+       free(conf->lxc_shmount.path_host);
+       free(conf->lxc_shmount.path_cont);
        free(conf);
 }
 
diff --git a/src/lxc/conf.h b/src/lxc/conf.h
index 351059c94..542fdd61f 100644
--- a/src/lxc/conf.h
+++ b/src/lxc/conf.h
@@ -185,6 +185,9 @@ enum {
        LXC_AUTO_CGROUP_FULL_NOSPEC   = 0x0E0,   /* /sys/fs/cgroup (full mount, 
r/w or mixed, depending on caps) */
        LXC_AUTO_CGROUP_FORCE         = 0x100,   /* mount cgroups even when 
cgroup namespaces are supported */
        LXC_AUTO_CGROUP_MASK          = 0x1F0,   /* all known cgroup options, 
doe not contain LXC_AUTO_CGROUP_FORCE */
+
+       LXC_AUTO_SHMOUNTS             = 0x200,   /* shared mount point */
+       LXC_AUTO_SHMOUNTS_MASK        = 0x200,   /* shared mount point mask */
        LXC_AUTO_ALL_MASK             = 0x1FF,   /* all known settings */
 };
 
@@ -365,6 +368,13 @@ struct lxc_conf {
 
        /* procs */
        struct lxc_list procs;
+
+       struct lxc_shmount {
+               /* Absolute path to the shared mount point on the host */
+               char *path_host;
+               /* Absolute path (in the container) to the shared mount point */
+               char *path_cont;
+       } lxc_shmount;
 };
 
 extern int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index 9704bbbec..d0770542a 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1743,6 +1743,7 @@ static int set_config_mount_auto(const char *key, const 
char *value,
            { "cgroup-full:mixed:force", LXC_AUTO_CGROUP_MASK, 
LXC_AUTO_CGROUP_FULL_MIXED | LXC_AUTO_CGROUP_FORCE  },
            { "cgroup-full:ro:force",    LXC_AUTO_CGROUP_MASK, 
LXC_AUTO_CGROUP_FULL_RO | LXC_AUTO_CGROUP_FORCE     },
            { "cgroup-full:rw:force",    LXC_AUTO_CGROUP_MASK, 
LXC_AUTO_CGROUP_FULL_RW | LXC_AUTO_CGROUP_FORCE     },
+           { "shmounts:",               LXC_AUTO_SHMOUNTS_MASK, 
LXC_AUTO_SHMOUNTS                                 },
            /* For adding anything that is just a single on/off, but has no
            *  options: keep mask and flag identical and just define the enum
            *  value as an unused bit so far

From 17e460874cc28edec34cc3139151d14843af88cc Mon Sep 17 00:00:00 2001
From: Liza Tretyakova <[email protected]>
Date: Wed, 2 May 2018 10:28:39 +0300
Subject: [PATCH 2/6] conf, confile: add parsing of a shmounts config parameter

Signed-off-by: Liza Tretyakova <[email protected]>
---
 src/lxc/conf.c    | 42 ++++++++++++++++++++++++++++++++++++++++++
 src/lxc/confile.c | 20 ++++++++++++++++++++
 src/lxc/confile.h |  2 ++
 3 files changed, 64 insertions(+)

diff --git a/src/lxc/conf.c b/src/lxc/conf.c
index a52331c86..7819ac20c 100644
--- a/src/lxc/conf.c
+++ b/src/lxc/conf.c
@@ -23,6 +23,7 @@
 
 #define _GNU_SOURCE
 #include "config.h"
+#include "confile.h"
 
 #include <arpa/inet.h>
 #include <dirent.h>
@@ -630,6 +631,39 @@ unsigned long add_required_remount_flags(const char *s, 
const char *d,
 #endif
 }
 
+static int add_shmount_to_list(struct lxc_conf *conf) {
+       char *new_mount;
+       size_t len_mount;
+       /* Offset for the leading '/' since the path_cont
+        * is absolute inside the container */
+       int ret = -1, offset = 1;
+
+       /* +1 for the separating whitespace */
+       len_mount = strlen(conf->lxc_shmount.path_host) + 1
+                       + strlen(conf->lxc_shmount.path_cont) - offset
+                       + sizeof(" none bind,create=dir 0 0") - 1;
+       /* +1 for the termintating '\0' */
+       new_mount = malloc(len_mount + 1);
+       if (!new_mount) {
+               SYSERROR("Not enough memory");
+               return -ENOMEM;
+       }
+
+       ret = snprintf(new_mount, len_mount + 1, "%s %s none bind,create=dir 0 
0",
+                                  conf->lxc_shmount.path_host, 
conf->lxc_shmount.path_cont + offset);
+       if (ret < 0 || ret >= len_mount + 1) {
+               free(new_mount);
+               return -1;
+       }
+
+       ret = add_elem_to_mount_list(new_mount, conf);
+       if (ret < 0)
+               ERROR("Failed to add new mount \"%s\" to the config", 
new_mount);
+
+       free(new_mount);
+       return ret;
+}
+
 static int lxc_mount_auto_mounts(struct lxc_conf *conf, int flags, struct 
lxc_handler *handler)
 {
        int i, r;
@@ -763,6 +797,14 @@ static int lxc_mount_auto_mounts(struct lxc_conf *conf, 
int flags, struct lxc_ha
                }
        }
 
+       if (flags & LXC_AUTO_SHMOUNTS_MASK) {
+               int ret = add_shmount_to_list(conf);
+               if (ret < 0) {
+                       ERROR("Failed to add shmount entry to container 
config");
+                       return ret;
+               }
+       }
+
        return 0;
 }
 
diff --git a/src/lxc/confile.c b/src/lxc/confile.c
index d0770542a..3ed219ebd 100644
--- a/src/lxc/confile.c
+++ b/src/lxc/confile.c
@@ -1761,6 +1761,8 @@ static int set_config_mount_auto(const char *key, const 
char *value,
                return -1;
 
        for (autoptr = autos;; autoptr = NULL) {
+               bool is_shmounts = false;
+
                token = strtok_r(autoptr, " \t", &sptr);
                if (!token) {
                        ret = 0;
@@ -1770,6 +1772,12 @@ static int set_config_mount_auto(const char *key, const 
char *value,
                for (i = 0; allowed_auto_mounts[i].token; i++) {
                        if (!strcmp(allowed_auto_mounts[i].token, token))
                                break;
+
+                       if (strcmp("shmounts:", allowed_auto_mounts[i].token) 
== 0
+                                       && strncmp("shmounts:", token, 
sizeof("shmounts:") - 1) == 0) {
+                               is_shmounts = true;
+                               break;
+                       }
                }
 
                if (!allowed_auto_mounts[i].token) {
@@ -1779,6 +1787,14 @@ static int set_config_mount_auto(const char *key, const 
char *value,
 
                lxc_conf->auto_mounts &= ~allowed_auto_mounts[i].mask;
                lxc_conf->auto_mounts |= allowed_auto_mounts[i].flag;
+               if (is_shmounts) {
+                       lxc_conf->lxc_shmount.path_host = strdup(token + 
(sizeof("shmounts:") - 1));
+                       if (strcmp(lxc_conf->lxc_shmount.path_host, "") == 0) {
+                               ERROR("Invalid shmounts path: empty");
+                               break;
+                       }
+                       lxc_conf->lxc_shmount.path_cont = 
strdup("/dev/.lxc-mounts");
+               }
        }
 
        free(autos);
@@ -1810,6 +1826,10 @@ static int set_config_mount(const char *key, const char 
*value,
        return 0;
 }
 
+int add_elem_to_mount_list(const char *value, struct lxc_conf *lxc_conf) {
+       return set_config_mount(NULL, value, lxc_conf, NULL);
+}
+
 static int set_config_cap_keep(const char *key, const char *value,
                               struct lxc_conf *lxc_conf, void *data)
 {
diff --git a/src/lxc/confile.h b/src/lxc/confile.h
index 0d877c898..894cb79bf 100644
--- a/src/lxc/confile.h
+++ b/src/lxc/confile.h
@@ -112,4 +112,6 @@ bool clone_update_unexp_ovl_paths(struct lxc_conf *conf, 
const char *oldpath,
 
 extern bool network_new_hwaddrs(struct lxc_conf *conf);
 
+extern int add_elem_to_mount_list(const char *value, struct lxc_conf 
*lxc_conf);
+
 #endif /* __LXC_CONFILE_H */

From abc0fbf7ce2606c3101378ff4a242dbedbb1d1d2 Mon Sep 17 00:00:00 2001
From: Liza Tretyakova <[email protected]>
Date: Wed, 2 May 2018 10:47:15 +0300
Subject: [PATCH 3/6] utils: add shared mount point detection

Signed-off-by: Liza Tretyakova <[email protected]>
---
 src/lxc/utils.c | 33 ++++++++++++++++++++-------------
 src/lxc/utils.h |  1 +
 2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index 3d0f8641c..f30bfc76a 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -1133,19 +1133,12 @@ uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t 
hval)
        return hval;
 }
 
-/*
- * Detect whether / is mounted MS_SHARED.  The only way I know of to
- * check that is through /proc/self/mountinfo.
- * I'm only checking for /.  If the container rootfs or mount location
- * is MS_SHARED, but not '/', then you're out of luck - figuring that
- * out would be too much work to be worth it.
- */
-int detect_shared_rootfs(void)
+bool is_shared_mountpoint(const char *path)
 {
-       char buf[LXC_LINELEN], *p;
+       char buf[LXC_LINELEN];
        FILE *f;
        int i;
-       char *p2;
+       char *p, *p2;
 
        f = fopen("/proc/self/mountinfo", "r");
        if (!f)
@@ -1159,16 +1152,30 @@ int detect_shared_rootfs(void)
                if (!p2)
                        continue;
                *p2 = '\0';
-               if (strcmp(p + 1, "/") == 0) {
-                       /* This is '/'. Is it shared? */
+               if (strcmp(p + 1, path) == 0) {
+                       /* This is the path. Is it shared? */
                        p = strchr(p2 + 1, ' ');
                        if (p && strstr(p, "shared:")) {
                                fclose(f);
-                               return 1;
+                               return true;
                        }
                }
        }
        fclose(f);
+       return false;
+}
+
+/*
+ * Detect whether / is mounted MS_SHARED.  The only way I know of to
+ * check that is through /proc/self/mountinfo.
+ * I'm only checking for /.  If the container rootfs or mount location
+ * is MS_SHARED, but not '/', then you're out of luck - figuring that
+ * out would be too much work to be worth it.
+ */
+int detect_shared_rootfs(void)
+{
+       if(is_shared_mountpoint("/"))
+               return 1;
        return 0;
 }
 
diff --git a/src/lxc/utils.h b/src/lxc/utils.h
index b15076cbd..dbab1e183 100644
--- a/src/lxc/utils.h
+++ b/src/lxc/utils.h
@@ -490,6 +490,7 @@ extern bool dir_exists(const char *path);
 #define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL)
 extern uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval);
 
+extern bool is_shared_mountpoint(const char *path);
 extern int detect_shared_rootfs(void);
 extern bool detect_ramfs_rootfs(void);
 extern char *on_path(const char *cmd, const char *rootfs);

From 0eb3a8d374b8a4cddf4816844f3c2d4fe9f8ea16 Mon Sep 17 00:00:00 2001
From: Liza Tretyakova <[email protected]>
Date: Wed, 2 May 2018 10:58:54 +0300
Subject: [PATCH 4/6] start: add shmount setup on container start

Signed-off-by: Liza Tretyakova <[email protected]>
---
 src/lxc/start.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 79 insertions(+)

diff --git a/src/lxc/start.c b/src/lxc/start.c
index d7f079979..6584ebd13 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1473,6 +1473,70 @@ static inline int do_share_ns(void *arg)
        return 0;
 }
 
+static int lxc_setup_shmount(struct lxc_conf *conf) {
+       size_t len_cont;
+       char *full_cont_path;
+       int ret = -1;
+
+       /* Construct the shmount path under the container root */
+       /* +1 for slash */
+       len_cont = strlen(conf->rootfs.mount) + 1 + 
strlen(conf->lxc_shmount.path_cont);
+       /* +1 for the terminating '\0' */
+       full_cont_path = malloc(len_cont + 1);
+       if(!full_cont_path) {
+               SYSERROR("Not enough memory");
+               return -ENOMEM;
+       }
+       ret = snprintf(full_cont_path, len_cont + 1, "%s/%s", 
conf->rootfs.mount, conf->lxc_shmount.path_cont);
+       if (ret < 0 || ret >= len_cont + 1) {
+               SYSERROR("Failed to create filename");
+               free(full_cont_path);
+               return -1;
+       }
+
+       /* Check if shmount point is already set up */
+       if (is_shared_mountpoint(conf->lxc_shmount.path_host)) {
+               INFO("Path \"%s\" is already MS_SHARED. Reusing", 
conf->lxc_shmount.path_host);
+               free(full_cont_path);
+               return 0;
+       }
+
+       /* Create host and cont mount paths */
+       ret = mkdir_p(conf->lxc_shmount.path_host, 0711);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", 
conf->lxc_shmount.path_host);
+               free(full_cont_path);
+               return ret;
+       }
+
+       ret = mkdir_p(full_cont_path, 0711);
+       if (ret < 0 && errno != EEXIST) {
+               SYSERROR("Failed to create directory \"%s\"", full_cont_path);
+               free(full_cont_path);
+               return ret;
+       }
+
+       /* Prepare host mountpoint */
+       ret = mount("tmpfs", conf->lxc_shmount.path_host, "tmpfs",
+                               0, "size=100k,mode=0711");
+       if (ret < 0) {
+               SYSERROR("Failed to mount \"%s\"", conf->lxc_shmount.path_host);
+               free(full_cont_path);
+               return ret;
+       }
+       ret = mount(conf->lxc_shmount.path_host, conf->lxc_shmount.path_host, 
"none",
+                               MS_REC | MS_SHARED, "");
+       if (ret < 0) {
+               SYSERROR("Failed to make shared \"%s\"", 
conf->lxc_shmount.path_host);
+               free(full_cont_path);
+               return ret;
+       }
+
+       INFO("Made shared mount point \"%s\"", conf->lxc_shmount.path_host);
+       free(full_cont_path);
+       return 0;
+}
+
 /* lxc_spawn() performs crucial setup tasks and clone()s the new process which
  * exec()s the requested container binary.
  * Note that lxc_spawn() runs in the parent namespaces. Any operations 
performed
@@ -1549,6 +1613,21 @@ static int lxc_spawn(struct lxc_handler *handler)
                }
        }
 
+       if (conf->lxc_shmount.path_host) {
+               if(!conf->lxc_shmount.path_cont) {
+                       ERROR("Missing the container side path to the shared 
mount point");
+                       lxc_sync_fini(handler);
+                       return -1;
+               }
+
+               ret = lxc_setup_shmount(conf);
+               if (ret < 0) {
+                       ERROR("Failed to setup shared mount point");
+                       lxc_sync_fini(handler);
+                       return -1;
+               }
+       }
+
        if (!cgroup_init(handler)) {
                ERROR("Failed initializing cgroup support");
                goto out_delete_net;

From 1b9fdb0bb4db5f3bbd4bc64a4daacb0346b1cfc3 Mon Sep 17 00:00:00 2001
From: Liza Tretyakova <[email protected]>
Date: Wed, 2 May 2018 11:07:58 +0300
Subject: [PATCH 5/6] lxccontainer: add container API function and structs for
 injecting a mount

Signed-off-by: Liza Tretyakova <[email protected]>
---
 src/lxc/lxccontainer.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/lxccontainer.h |  13 +++++
 2 files changed, 165 insertions(+)

diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 30efeaff8..803f74cea 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -30,9 +30,11 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <sys/file.h>
 #include <sys/mman.h>
 #include <sys/mount.h>
+#include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/sysmacros.h>
 #include <sys/types.h>
@@ -457,6 +459,25 @@ static rettype fnname(struct lxc_container *c, t1 a1, t2 
a2, t3 a3)        \
        return ret;                                                     \
 }
 
+#define WRAP_API_6(rettype, fnname, t1, t2, t3, t4, t5, t6)                    
        \
+static rettype fnname(struct lxc_container *c, t1 a1, t2 a2, t3 a3,    \
+                                               t4 a4, t5 a5, t6 a6)    \
+{                                                                      \
+       rettype ret;                                                    \
+       bool reset_config = false;                                      \
+                                                                       \
+       if (!current_config && c && c->lxc_conf) {                      \
+               current_config = c->lxc_conf;                           \
+               reset_config = true;                                    \
+       }                                                               \
+                                                                       \
+       ret = do_##fnname(c, a1, a2, a3, a4, a5, a6);                           
\
+       if (reset_config)                                               \
+               current_config = NULL;                                  \
+                                                                       \
+       return ret;                                                     \
+}
+
 WRAP_API(bool, lxcapi_is_defined)
 
 static const char *do_lxcapi_state(struct lxc_container *c)
@@ -4691,6 +4712,136 @@ static bool do_lxcapi_restore(struct lxc_container *c, 
char *directory, bool ver
 
 WRAP_API_2(bool, lxcapi_restore, char *, bool)
 
+static int do_lxcapi_mount(struct lxc_container *c,
+                       const char *source, const char *target,
+                       const char *filesystemtype, unsigned long mountflags,
+                       const void *data, struct lxc_mount *mnt) {
+       char *template, *suff, *path;
+       pid_t pid, init_pid;
+       size_t len;
+       int ret = -1, fd = -EBADF;
+
+       if (!c || !c->lxc_conf) {
+               ERROR("Container or configuration is NULL");
+               return -EINVAL;
+       }
+
+       len = strlen(c->lxc_conf->lxc_shmount.path_host) + 
sizeof("/lxcmountXXXXXX") - 1;
+       template = malloc(len + 1);
+       if (!template) {
+               SYSERROR("Not enough memory");
+               return -ENOMEM;
+       }
+       ret = snprintf(template, len + 1, "%s/lxcmountXXXXXX", 
c->lxc_conf->lxc_shmount.path_host);
+       if (ret < 0 || (size_t)ret >= len + 1) {
+               SYSERROR("Error writing shmounts tempdir name");
+               goto out_err_free;
+       }
+
+       /* Create a temporary dir under the shared mountpoint */
+       template = mkdtemp(template);
+       if (!template) {
+               SYSERROR("Could not create shmounts temporary dir");
+               goto out_err_free;
+       }
+
+       /* Do the fork */
+       pid = fork();
+       if (pid < 0) {
+               SYSERROR("Could not fork");
+               goto out_err_free;
+       }
+
+       if (pid == 0) {
+               int exit_status = EXIT_FAILURE;
+
+               /* Do the mount */
+               ret = mount(source, template, filesystemtype, mountflags, data);
+               if (ret < 0) {
+                       SYSERROR("Failed to mount \"%s\" onto \"%s\"", source, 
template);
+                       goto out_child_err_temp;
+               }
+
+               init_pid = do_lxcapi_init_pid(c);
+               if (init_pid < 0) {
+                       ERROR("Failed to obtain container's init pid");
+                       goto out_child_err_temp;
+               }
+
+               /* Enter the container namespaces */
+               if (am_guest_unpriv() && !lxc_list_empty(&c->lxc_conf->id_map)) 
{
+                       /* if fully unprivileged */
+                       if (!switch_to_ns(init_pid, "user")){
+                               ERROR("Failed to enter user namespace");
+                               goto out_child_err_temp;
+                       }
+               }
+               if (!switch_to_ns(init_pid, "mnt")) {
+                       ERROR("Failed to enter mount namespace");
+                       goto out_child_err_temp;
+               }
+
+               suff = strrchr(template, '/');
+               if (!suff)
+                       goto out_child_err_temp;
+
+               len = strlen(c->lxc_conf->lxc_shmount.path_cont) + 
sizeof("/lxcmountXXXXXX") - 1;
+               path = malloc(len + 1);
+               if (!path) {
+                       SYSERROR("Not enough memory");
+                       goto out_child_err_temp;
+               }
+               ret = snprintf(path, len + 1, "%s%s", 
c->lxc_conf->lxc_shmount.path_cont, suff);
+               if (ret < 0 || (size_t)ret >= len + 1) {
+                       SYSERROR("Error writing container mountpoint name");
+                       goto out_child_err_path;
+               }
+
+               ret = mkdir_p(target, 0700);
+               if (ret < 0) {
+                       ERROR("Failed to create container temp mountpoint");
+                       goto out_child_err_path;
+               }
+
+               ret = mount(path, target, NULL, MS_REC | MS_MOVE, NULL);
+               if (ret < 0) {
+                       SYSERROR("Failed to move the mount from \"%s\" to 
\"%s\"", path, target);
+                       goto out_child_err_path;
+               }
+
+               exit_status = EXIT_SUCCESS;
+
+out_child_err_path:
+               free(path);
+
+out_child_err_temp:
+               free(template);
+
+               _exit(exit_status);
+       }
+
+       ret = wait_for_pid(pid);
+       if (ret < 0) {
+               SYSERROR("Wait for the child with pid %ld failed", (long) pid);
+               goto out_err_free;
+       }
+
+       ret = 0;
+
+       (void)umount2(template, MNT_DETACH);
+       (void)unlink(template);
+
+out_err_free:
+       if (fd >= 0)
+               close(fd);
+       free(template);
+
+       return ret;
+}
+
+WRAP_API_6(int, lxcapi_mount, const char *, const char *, const char *,
+          unsigned long, const void *, struct lxc_mount*)
+
 static int lxcapi_attach_run_waitl(struct lxc_container *c, 
lxc_attach_options_t *options, const char *program, const char *arg, ...)
 {
        va_list ap;
@@ -4839,6 +4990,7 @@ struct lxc_container *lxc_container_new(const char *name, 
const char *configpath
        c->restore = lxcapi_restore;
        c->migrate = lxcapi_migrate;
        c->console_log = lxcapi_console_log;
+       c->mount = lxcapi_mount;
 
        return c;
 
diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
index 7bbac2f06..c61a1b840 100644
--- a/src/lxc/lxccontainer.h
+++ b/src/lxc/lxccontainer.h
@@ -42,6 +42,7 @@ extern "C" {
 #define LXC_CLONE_MAXFLAGS        (1 << 5) /*!< Number of \c LXC_CLONE_* flags 
*/
 #define LXC_CREATE_QUIET          (1 << 0) /*!< Redirect \c stdin to \c 
/dev/zero and \c stdout and \c stderr to \c /dev/null */
 #define LXC_CREATE_MAXFLAGS       (1 << 1) /*!< Number of \c LXC_CREATE* flags 
*/
+#define LXC_MOUNT_API_V1                  1
 
 struct bdev_specs;
 
@@ -53,6 +54,10 @@ struct migrate_opts;
 
 struct lxc_console_log;
 
+struct lxc_mount {
+       int version;
+};
+
 /*!
  * An LXC container.
  *
@@ -846,6 +851,14 @@ struct lxc_container {
         * \return \c true if the container was rebooted successfully, else \c 
false.
         */
        bool (*reboot2)(struct lxc_container *c, int timeout);
+
+       /*!
+        * \brief Mount the host's path `source` onto the container's path 
`target`.
+        */
+       int (*mount)(struct lxc_container *c,
+                                const char *source, const char *target,
+                                const char *filesystemtype, unsigned long 
mountflags,
+                                const void *data, struct lxc_mount *mnt);
 };
 
 /*!

From 8536cf1e6f4005d327216dfe6342b5f879d75398 Mon Sep 17 00:00:00 2001
From: Liza Tretyakova <[email protected]>
Date: Wed, 2 May 2018 11:54:06 +0300
Subject: [PATCH 6/6] tests/mount_injection, tests/Makefile: add mount
 injection tests

Signed-off-by: Liza Tretyakova <[email protected]>
---
 src/tests/Makefile.am       |   5 +-
 src/tests/mount_injection.c | 304 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 308 insertions(+), 1 deletion(-)
 create mode 100644 src/tests/mount_injection.c

diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index f39c3e047..59f8370e0 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -33,6 +33,7 @@ lxc_test_state_server_SOURCES = state_server.c lxctest.h
 lxc_test_share_ns_SOURCES = share_ns.c lxctest.h
 lxc_test_criu_check_feature_SOURCES = criu_check_feature.c lxctest.h
 lxc_test_raw_clone_SOURCES = lxc_raw_clone.c lxctest.h
+lxc_test_mount_injection_SOURCES = mount_injection.c
 
 AM_CFLAGS=-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
        -DLXCPATH=\"$(LXCPATH)\" \
@@ -63,7 +64,8 @@ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests 
lxc-test-startone \
        lxc-test-apparmor lxc-test-utils lxc-test-parse-config-file \
        lxc-test-config-jump-table lxc-test-shortlived \
        lxc-test-api-reboot lxc-test-state-server lxc-test-share-ns \
-       lxc-test-criu-check-feature lxc-test-raw-clone
+       lxc-test-criu-check-feature lxc-test-raw-clone \
+       lxc-test-mount-injection
 
 bin_SCRIPTS =
 if ENABLE_TOOLS
@@ -120,6 +122,7 @@ EXTRA_DIST = \
        lxc-test-unpriv \
        lxc-test-utils.c \
        may_control.c \
+       mount_injection.c \
        parse_config_file.c \
        saveconfig.c \
        shortlived.c \
diff --git a/src/tests/mount_injection.c b/src/tests/mount_injection.c
new file mode 100644
index 000000000..1420e5174
--- /dev/null
+++ b/src/tests/mount_injection.c
@@ -0,0 +1,304 @@
+/* mount_injection
+ *
+ * Copyright © 2018 Elizaveta Tretiakova <[email protected]>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <lxc/lxccontainer.h>
+#include <lxc/list.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "lxctest.h"
+#include "utils.h"
+
+#define NAME "mount_injection_test-"
+#define TEMPLATE P_tmpdir"/mount_injection_XXXXXX"
+
+struct mountinfo_strings {
+       const char *mount_root;
+       const char *mount_point;
+       const char *fstype;
+       const char *mount_source;
+       const char *message;
+};
+
+static int comp_field(char *line, const char *str, int nfields)
+{
+       char *p, *p2;
+       int i, ret;
+
+       if(!line)
+               return -1;
+
+       if (!str)
+               return 0;
+
+       for (p = line, i = 0; p && i < nfields; i++)
+               p = strchr(p + 1, ' ');
+       if (!p)
+               return -1;
+       p2 = strchr(p + 1, ' ');
+       if (p2)
+               *p2 = '\0';
+       ret = strcmp(p + 1, str);
+       if (p2)
+               *p2 = ' ';
+       return ret;
+}
+
+static int find_in_proc_mounts(void *data)
+{
+       char buf[LXC_LINELEN];
+       FILE *f;
+       struct mountinfo_strings *strs = (struct mountinfo_strings *) data;
+
+       fprintf(stderr, "%s", strs->message);
+
+       f = fopen("/proc/self/mountinfo", "r");
+       if (!f)
+               return 0;
+       while (fgets(buf, LXC_LINELEN, f)) {
+               if (comp_field(buf, strs->mount_root, 3) == 0 && 
comp_field(buf, strs->mount_point, 4) == 0) {
+                       char *buf2 = strchr(buf, '-');
+                       if (comp_field(buf2, strs->fstype, 1) == 0 && 
comp_field(buf2, strs->mount_source, 2) == 0) {
+                               fclose(f);
+                               fprintf(stderr, "OK\n");
+                               _exit(EXIT_SUCCESS);
+                       }
+               }
+       }
+       fclose(f);
+       fprintf(stderr, "ERR\n");
+       _exit(EXIT_FAILURE);
+}
+
+static int check_containers_mountinfo(struct lxc_container *c, struct 
mountinfo_strings *d)
+{
+       pid_t pid;
+       int ret = -1;
+       lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
+
+       ret = c->attach(c, find_in_proc_mounts, d, &attach_options, &pid);
+       if (ret < 0) {
+               fprintf(stderr, "Check of the container's mountinfo failed\n");
+               return ret;
+       }
+
+       ret = wait_for_pid(pid);
+       if (ret < 0)
+               fprintf(stderr, "Attached function failed");
+
+       return ret;
+}
+
+/* config_items: NULL-terminated array of config pairs */
+static int perform_container_test(const char *name, const char *config_items[])
+{
+       int i;
+       char *sret;
+       char template_log[sizeof(TEMPLATE)], template_dir[sizeof(TEMPLATE)],
+                       device_message[sizeof("Check urandom deivce injected 
into "" - ") - 1 + strlen(name) + 1],
+                       dir_message[sizeof("Check dir "" injected into "" - ") 
- 1 + sizeof(TEMPLATE) - 1 + strlen(name) + 1];
+       struct lxc_container *c;
+       struct lxc_mount mnt;
+       struct lxc_log log;
+       int ret = -1, dev_msg_size = sizeof("Check urandom deivce injected into 
"" - ") - 1 + strlen(name) + 1,
+                       dir_msg_size = sizeof("Check dir "" injected into "" - 
") - 1 + sizeof(TEMPLATE) - 1 + strlen(name) + 1;
+       struct mountinfo_strings device = {
+               .mount_root = "/",
+               .mount_point = "/mnt/mount_injection_test_urandom",
+               .fstype = "devtmpfs",
+               .mount_source = "/dev/urandom",
+               .message = ""
+       }, dir = {
+               .mount_root = template_dir,
+               .mount_point = template_dir,
+               .fstype = "ext4",
+               .mount_source = NULL,
+               .message = ""
+       };
+
+       /* Temp paths and messages setup */
+       strcpy(template_dir, TEMPLATE);
+       sret = mkdtemp(template_dir);
+       if (!sret) {
+               lxc_error("Failed to create temporary src file for container 
%s\n", name);
+               exit(EXIT_FAILURE);
+       }
+
+       ret = snprintf(device_message, dev_msg_size, "Check urandom deivce 
injected into %s - ", name);
+       if (ret < 0 || ret >= dev_msg_size) {
+               fprintf(stderr, "Failed to create message for dev\n");
+               exit(EXIT_FAILURE);
+       }
+       device.message = &device_message[0];
+
+       ret = snprintf(dir_message, dir_msg_size, "Check dir %s injected into 
%s - ", template_dir, name);
+       if (ret < 0 || ret >= dir_msg_size) {
+               fprintf(stderr, "Failed to create message for dir\n");
+               exit(EXIT_FAILURE);
+       }
+       dir.message = &dir_message[0];
+
+       /* Setup logging*/
+       strcpy(template_log, TEMPLATE);
+       i = lxc_make_tmpfile(template_log, false);
+       if (i < 0) {
+               lxc_error("Failed to create temporary log file for container 
%s\n", name);
+               exit(EXIT_FAILURE);
+       } else {
+               lxc_debug("Using \"%s\" as temporary log file for container 
%s\n", template_log, name);
+               close(i);
+       }
+
+       log.name = name;
+       log.file = template_log;
+       log.level = "TRACE";
+       log.prefix = "mount-injection";
+       log.quiet = false;
+       log.lxcpath = NULL;
+       if (lxc_log_init(&log))
+               exit(EXIT_FAILURE);
+
+       /* Container setup */
+       c = lxc_container_new(name, NULL);
+       if (!c) {
+               fprintf(stderr, "Unable to instantiate container (%s)...\n", 
name);
+               goto out;
+       }
+
+       if (c->is_defined(c)) {
+               fprintf(stderr, "Container (%s) already exists\n", name);
+               goto out;
+       }
+
+       for (int i = 0; config_items[i]; i += 2) {
+               if (!c->set_config_item(c, config_items[i], config_items[i + 
1])) {
+                       fprintf(stderr, "Failed to set \"%s\" config option to 
\"%s\"\n", config_items[i], config_items[i + 1]);
+                       goto out;
+               }
+       }
+
+       if (!c->create(c, "busybox", NULL, NULL, 1, NULL)) {
+               fprintf(stderr, "Creating the container (%s) failed...\n", 
name);
+               goto out;
+       }
+
+       c->want_daemonize(c, true);
+
+       if (!c->start(c, false, NULL)) {
+               fprintf(stderr, "Starting the container (%s) failed...\n", 
name);
+               goto out;
+       }
+
+       mnt.version = LXC_MOUNT_API_V1;
+
+       /* Check device mounted */
+       ret = c->mount(c, "/dev/urandom", "/mnt/mount_injection_test_urandom", 
"devtmpfs", 0, NULL, &mnt);
+       if (ret < 0) {
+               fprintf(stderr, "Failed to mount \"/dev/urandom\"\n");
+               goto out;
+       }
+
+       ret = check_containers_mountinfo(c, &device);
+       if (ret < 0)
+               goto out;
+
+       /* Check dir mounted */
+       ret = c->mount(c, template_dir, template_dir, "ext4", MS_BIND, NULL, 
&mnt);
+       if (ret < 0) {
+               fprintf(stderr, "Failed to mount \"%s\"\n", template_dir);
+               goto out;
+       }
+
+       ret = check_containers_mountinfo(c, &dir);
+       if (ret < 0)
+               goto out;
+
+       if (!c->stop(c)) {
+               fprintf(stderr, "Stopping the container (%s) failed...\n", 
name);
+               goto out;
+       }
+
+       if (!c->destroy(c)) {
+               fprintf(stderr, "Destroying the container (%s) failed...\n", 
name);
+               goto out;
+       }
+
+       ret = 0;
+out:
+       lxc_container_put(c);
+
+       if (ret != 0) {
+               int fd;
+
+               fd = open(template_log, O_RDONLY);
+               if (fd >= 0) {
+                       char buf[4096];
+                       ssize_t buflen;
+                       while ((buflen = read(fd, buf, 1024)) > 0) {
+                               buflen = write(STDERR_FILENO, buf, buflen);
+                               if (buflen <= 0)
+                                       break;
+                       }
+                       close(fd);
+               }
+       }
+
+       unlink(template_log);
+       unlink(template_dir);
+
+       return ret;
+}
+
+static int do_priv_container_test()
+{
+       const char *config_items[] = {"lxc.mount.auto", 
"shmounts:/tmp/mount_injection_test", NULL};
+       return perform_container_test(NAME"privileged", config_items);
+}
+
+static int do_unpriv_container_test()
+{
+       const char *config_items[] = {
+               "lxc.mount.auto", "shmounts:/tmp/mount_injection_test",
+               "lxc.init.uid", "100000",
+               "lxc.init.gid", "100000",
+               NULL
+       };
+       return perform_container_test(NAME"unprivileged", config_items);
+}
+
+int main(int argc, char *argv[])
+{
+       if (do_priv_container_test()) {
+               fprintf(stderr, "Privileged mount injection test failed\n");
+               return -1;
+       }
+       if(do_unpriv_container_test()) {
+               fprintf(stderr, "Unprivileged mount injection test failed\n");
+               return -1;
+       }
+       return 0;
+}
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to