jail: handle mount propagation flags
authorDaniel Golle <daniel@makrotopia.org>
Wed, 28 Oct 2020 00:30:03 +0000 (00:30 +0000)
committerDaniel Golle <daniel@makrotopia.org>
Wed, 28 Oct 2020 13:45:52 +0000 (13:45 +0000)
Add support for propagation mount options (private, slave, shared,
unbindable, rprivate, rslave, rshared, runbindable).

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
jail/fs.c
jail/fs.h
jail/jail.c

index fb0f504a79e7ad96a0aba27586530de21231ad95..4cc273eea973386a7cea2091928295ab0d1c79af 100644 (file)
--- a/jail/fs.c
+++ b/jail/fs.c
@@ -46,6 +46,7 @@ struct mount {
        const char *target;
        const char *filesystemtype;
        unsigned long mountflags;
+       unsigned long propflags;
        const char *optstr;
        int error;
        bool inner;
@@ -79,7 +80,7 @@ int mkdir_p(char *dir, mode_t mask)
 }
 
 static int do_mount(const char *root, const char *orig_source, const char *target, const char *filesystemtype,
-                   unsigned long orig_mountflags, const char *optstr, int error, bool inner)
+                   unsigned long orig_mountflags, unsigned long propflags, const char *optstr, int error, bool inner)
 {
        struct stat s;
        char new[PATH_MAX];
@@ -161,6 +162,16 @@ static int do_mount(const char *root, const char *orig_source, const char *targe
        DEBUG("mount %s%s %s (%s)\n", (mountflags & MS_BIND)?"-B ":"", source, new,
              (mountflags & MS_RDONLY)?"ro":"rw");
 
+       if (propflags && mount(NULL, new, NULL, propflags, NULL)) {
+               if (error)
+                       ERROR("failed to mount --make-... %s \n", new);
+
+               if (inner)
+                       free(source);
+
+               return error;
+       }
+
        if (inner)
                free(source);
 
@@ -168,7 +179,8 @@ static int do_mount(const char *root, const char *orig_source, const char *targe
 }
 
 static int _add_mount(const char *source, const char *target, const char *filesystemtype,
-             unsigned long mountflags, const char *optstr, int error, bool inner)
+                     unsigned long mountflags, unsigned long propflags, const char *optstr,
+                     int error, bool inner)
 {
        assert(target != NULL);
 
@@ -192,6 +204,7 @@ static int _add_mount(const char *source, const char *target, const char *filesy
                m->optstr = strdup(optstr);
 
        m->mountflags = mountflags;
+       m->propflags = propflags;
        m->error = error;
        m->inner = inner;
 
@@ -203,15 +216,15 @@ static int _add_mount(const char *source, const char *target, const char *filesy
 }
 
 int add_mount(const char *source, const char *target, const char *filesystemtype,
-             unsigned long mountflags, const char *optstr, int error)
+             unsigned long mountflags, unsigned long propflags, const char *optstr, int error)
 {
-       return _add_mount(source, target, filesystemtype, mountflags, optstr, error, false);
+       return _add_mount(source, target, filesystemtype, mountflags, propflags, optstr, error, false);
 }
 
 int add_mount_inner(const char *source, const char *target, const char *filesystemtype,
-             unsigned long mountflags, const char *optstr, int error)
+             unsigned long mountflags, unsigned long propflags, const char *optstr, int error)
 {
-       return _add_mount(source, target, filesystemtype, mountflags, optstr, error, true);
+       return _add_mount(source, target, filesystemtype, mountflags, propflags, optstr, error, true);
 }
 
 int add_mount_bind(const char *path, int readonly, int error)
@@ -221,7 +234,7 @@ int add_mount_bind(const char *path, int readonly, int error)
        if (readonly)
                mountflags |= MS_RDONLY;
 
-       return add_mount(path, path, NULL, mountflags, NULL, error);
+       return add_mount(path, path, NULL, mountflags, 0, NULL, error);
 }
 
 enum {
@@ -248,11 +261,12 @@ struct mount_opt {
 #define MS_LAZYTIME (1 << 25)
 #endif
 
-static int parseOCImountopts(struct blob_attr *msg, unsigned long *mount_flags, char **mount_data, int *error)
+static int parseOCImountopts(struct blob_attr *msg, unsigned long *mount_flags, unsigned long *propagation_flags, char **mount_data, int *error)
 {
        struct blob_attr *cur;
        int rem;
        unsigned long mf = 0;
+       unsigned long pf = 0;
        char *tmp;
        struct list_head fsopts = LIST_HEAD_INIT(fsopts);
        size_t len = 0;
@@ -318,6 +332,24 @@ static int parseOCImountopts(struct blob_attr *msg, unsigned long *mount_flags,
                        mf |= MS_NOSUID;
                else if (!strcmp("remount", tmp))
                        mf |= MS_REMOUNT;
+               /* propagation flags */
+               else if (!strcmp("private", tmp))
+                       pf |= MS_PRIVATE;
+               else if (!strcmp("rprivate", tmp))
+                       pf |= MS_PRIVATE | MS_REC;
+               else if (!strcmp("slave", tmp))
+                       pf |= MS_SLAVE;
+               else if (!strcmp("rslave", tmp))
+                       pf |= MS_SLAVE | MS_REC;
+               else if (!strcmp("shared", tmp))
+                       pf |= MS_SHARED;
+               else if (!strcmp("rshared", tmp))
+                       pf |= MS_SHARED | MS_REC;
+               else if (!strcmp("unbindable", tmp))
+                       pf |= MS_UNBINDABLE;
+               else if (!strcmp("runbindable", tmp))
+                       pf |= MS_UNBINDABLE | MS_REC;
+               /* special case: 'nofail' */
                else if(!strcmp("nofail", tmp))
                        *error = 0;
                else if (!strcmp("auto", tmp) ||
@@ -335,6 +367,7 @@ static int parseOCImountopts(struct blob_attr *msg, unsigned long *mount_flags,
        };
 
        *mount_flags = mf;
+       *propagation_flags = pf;
 
        list_for_each_entry(opt, &fsopts, list) {
                if (len)
@@ -343,25 +376,24 @@ static int parseOCImountopts(struct blob_attr *msg, unsigned long *mount_flags,
                len += strlen(opt->optstr);
        };
 
-       if (!len)
-               return 0;
-
-       *mount_data = calloc(len + 1, sizeof(char));
-       if (!mount_data)
-               return ENOMEM;
+       if (len) {
+               *mount_data = calloc(len + 1, sizeof(char));
+               if (!mount_data)
+                       return ENOMEM;
 
-       len = 0;
-       list_for_each_entry(opt, &fsopts, list) {
-               if (len)
-                       strcat(*mount_data, ",");
+               len = 0;
+               list_for_each_entry(opt, &fsopts, list) {
+                       if (len)
+                               strcat(*mount_data, ",");
 
-               strcat(*mount_data, opt->optstr);
-               ++len;
-       };
+                       strcat(*mount_data, opt->optstr);
+                       ++len;
+               };
 
-       list_del(&fsopts);
+               list_del(&fsopts);
+       }
 
-       DEBUG("mount flags(%08lx) fsopts(\"%s\")\n", mf, *mount_data?:"");
+       DEBUG("mount flags(%08lx) propagation(%08lx) fsopts(\"%s\")\n", mf, pf, *mount_data?:"");
 
        return 0;
 }
@@ -370,6 +402,7 @@ int parseOCImount(struct blob_attr *msg)
 {
        struct blob_attr *tb[__OCI_MOUNT_MAX];
        unsigned long mount_flags = 0;
+       unsigned long propagation_flags = 0;
        char *mount_data = NULL;
        int ret, err = -1;
 
@@ -379,7 +412,7 @@ int parseOCImount(struct blob_attr *msg)
                return EINVAL;
 
        if (tb[OCI_MOUNT_OPTIONS]) {
-               ret = parseOCImountopts(tb[OCI_MOUNT_OPTIONS], &mount_flags, &mount_data, &err);
+               ret = parseOCImountopts(tb[OCI_MOUNT_OPTIONS], &mount_flags, &propagation_flags, &mount_data, &err);
                if (ret)
                        return ret;
        }
@@ -387,7 +420,7 @@ int parseOCImount(struct blob_attr *msg)
        ret = add_mount(tb[OCI_MOUNT_SOURCE] ? blobmsg_get_string(tb[OCI_MOUNT_SOURCE]) : NULL,
                  blobmsg_get_string(tb[OCI_MOUNT_DESTINATION]),
                  tb[OCI_MOUNT_TYPE] ? blobmsg_get_string(tb[OCI_MOUNT_TYPE]) : NULL,
-                 mount_flags, mount_data, err);
+                 mount_flags, propagation_flags, mount_data, err);
 
        if (mount_data)
                free(mount_data);
@@ -416,7 +449,8 @@ int mount_all(const char *jailroot) {
                add_mount_bind(l->path, 1, -1);
 
        avl_for_each_element(&mounts, m, avl)
-               if (do_mount(jailroot, m->source, m->target, m->filesystemtype, m->mountflags, m->optstr, m->error, m->inner))
+               if (do_mount(jailroot, m->source, m->target, m->filesystemtype, m->mountflags,
+                            m->propflags, m->optstr, m->error, m->inner))
                        return -1;
 
        return 0;
index f94d8b1c921a74fed8ec6a9df05791f396e96746..eeb1e22df60613c0a9755324d5d95c3c6b2f5a44 100644 (file)
--- a/jail/fs.h
+++ b/jail/fs.h
@@ -18,9 +18,9 @@
 
 int mkdir_p(char *dir, mode_t mask);
 int add_mount(const char *source, const char *target, const char *filesystemtype,
-             unsigned long mountflags, const char *optstr, int error);
+             unsigned long mountflags, unsigned long propflags, const char *optstr, int error);
 int add_mount_inner(const char *source, const char *target, const char *filesystemtype,
-             unsigned long mountflags, const char *optstr, int error);
+             unsigned long mountflags, unsigned long propflags, const char *optstr, int error);
 int add_mount_bind(const char *path, int readonly, int error);
 int parseOCImount(struct blob_attr *msg);
 int add_path_and_deps(const char *path, int readonly, int error, int lib);
index 77315d23a30c9faede3a2d22c7d8b32073e543e9..99841af6103b8325221cda25f3ec9da6884471a7 100644 (file)
@@ -2085,7 +2085,7 @@ static int parseOCIlinux(struct blob_attr *msg)
 
        if (tb[OCI_LINUX_READONLYPATHS]) {
                blobmsg_for_each_attr(cur, tb[OCI_LINUX_READONLYPATHS], rem) {
-                       res = add_mount(NULL, blobmsg_get_string(cur), NULL, MS_BIND | MS_REC | MS_RDONLY, NULL, 0);
+                       res = add_mount(NULL, blobmsg_get_string(cur), NULL, MS_BIND | MS_REC | MS_RDONLY, 0, NULL, 0);
                        if (res)
                                return res;
                }
@@ -2093,7 +2093,7 @@ static int parseOCIlinux(struct blob_attr *msg)
 
        if (tb[OCI_LINUX_MASKEDPATHS]) {
                blobmsg_for_each_attr(cur, tb[OCI_LINUX_MASKEDPATHS], rem) {
-                       res = add_mount((void *)(-1), blobmsg_get_string(cur), NULL, 0, NULL, 1);
+                       res = add_mount((void *)(-1), blobmsg_get_string(cur), NULL, 0, 0, NULL, 1);
                        if (res)
                                return res;
                }
@@ -2651,15 +2651,15 @@ static void post_main(struct uloop_timeout *t)
 
                                snprintf(hostdir, PATH_MAX, "/tmp/resolv.conf-%s.d", opts.name);
                                mkdir_p(hostdir, 0755);
-                               add_mount(hostdir, "/dev/resolv.conf.d", NULL, MS_BIND | MS_NOEXEC | MS_NOATIME | MS_NOSUID | MS_NODEV | MS_RDONLY, NULL, -1);
+                               add_mount(hostdir, "/dev/resolv.conf.d", NULL, MS_BIND | MS_NOEXEC | MS_NOATIME | MS_NOSUID | MS_NODEV | MS_RDONLY, 0, NULL, -1);
                        }
 
                        /* default mounts */
-                       add_mount(NULL, "/dev", "tmpfs", MS_NOATIME | MS_NOEXEC | MS_NOSUID, "size=1M", -1);
-                       add_mount(NULL, "/dev/pts", "devpts", MS_NOATIME | MS_NOEXEC | MS_NOSUID, "newinstance,ptmxmode=0666,mode=0620,gid=5", 0);
+                       add_mount(NULL, "/dev", "tmpfs", MS_NOATIME | MS_NOEXEC | MS_NOSUID, 0, "size=1M", -1);
+                       add_mount(NULL, "/dev/pts", "devpts", MS_NOATIME | MS_NOEXEC | MS_NOSUID, 0, "newinstance,ptmxmode=0666,mode=0620,gid=5", 0);
 
                        if (opts.procfs || opts.ocibundle) {
-                               add_mount("proc", "/proc", "proc", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, NULL, -1);
+                               add_mount("proc", "/proc", "proc", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0, NULL, -1);
 
                                /*
                                 * hack to make /proc/sys/net read-write while the rest of /proc/sys is read-only
@@ -2677,17 +2677,17 @@ static void post_main(struct uloop_timeout *t)
                                 * move-mount of /proc/sys/net follows because 'e' preceeds 'y' in the ASCII
                                 * table (and in the alphabet).
                                 */
-                               if (!add_mount(NULL, "/proc/sys", NULL, MS_BIND | MS_RDONLY, NULL, -1))
+                               if (!add_mount(NULL, "/proc/sys", NULL, MS_BIND | MS_RDONLY, 0, NULL, -1))
                                        if (opts.namespace & CLONE_NEWNET)
-                                               if (!add_mount_inner("/proc/self/net", "/proc/sys/net", NULL, MS_MOVE, NULL, -1))
-                                                       add_mount_inner("/proc/sys/net", "/proc/self/net", NULL, MS_BIND, NULL, -1);
+                                               if (!add_mount_inner("/proc/self/net", "/proc/sys/net", NULL, MS_MOVE, 0, NULL, -1))
+                                                       add_mount_inner("/proc/sys/net", "/proc/self/net", NULL, MS_BIND, 0, NULL, -1);
 
                        }
                        if (opts.sysfs || opts.ocibundle)
-                               add_mount("sysfs", "/sys", "sysfs", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RDONLY, NULL, -1);
+                               add_mount("sysfs", "/sys", "sysfs", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RDONLY, 0, NULL, -1);
 
                        if (opts.ocibundle)
-                               add_mount("shm", "/dev/shm", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV, "mode=1777", -1);
+                               add_mount("shm", "/dev/shm", "tmpfs", MS_NOSUID | MS_NOEXEC | MS_NODEV, 0, "mode=1777", -1);
 
                }