jail: add support for launching extroot containers
authorDaniel Golle <daniel@makrotopia.org>
Fri, 20 Mar 2020 18:19:53 +0000 (18:19 +0000)
committerDaniel Golle <daniel@makrotopia.org>
Thu, 9 Apr 2020 11:45:19 +0000 (12:45 +0100)
Add option to ujail to use an existing rootfs when launching a
containerized service. Later on this option will also be used to
launch full-system containers.

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

index 5414519ce4d397474d293f290fd9aef60e124ad5..df1bda7666e3535d47c53a6ebfbb00949f84f5fb 100644 (file)
@@ -40,7 +40,7 @@
 #include <libubus.h>
 
 #define STACK_SIZE     (1024 * 1024)
-#define OPT_ARGS       "S:C:n:h:r:w:d:psulocU:G:N"
+#define OPT_ARGS       "S:C:n:h:r:w:d:psulocU:G:NR:"
 
 #define NAMESPACE_MOUNT                (1U << 0)
 #define NAMESPACE_IPC          (1U << 1)
@@ -58,6 +58,7 @@ static struct {
        char *capabilities;
        char *user;
        char *group;
+       char *extroot;
        int no_new_privs;
        int namespace;
        int procfs;
@@ -164,9 +165,16 @@ static int build_jail_fs(void)
                return -1;
        }
 
-       if (mount("tmpfs", jail_root, "tmpfs", MS_NOATIME, "mode=0755")) {
-               ERROR("tmpfs mount failed %m\n");
-               return -1;
+       if (opts.extroot) {
+               if (mount(opts.extroot, jail_root, NULL, MS_BIND | MS_REC, NULL)) {
+                       ERROR("extroot mount failed %m\n");
+                       return -1;
+               }
+       } else {
+               if (mount("tmpfs", jail_root, "tmpfs", MS_NOATIME, "mode=0755")) {
+                       ERROR("tmpfs mount failed %m\n");
+                       return -1;
+               }
        }
 
        if (chdir(jail_root)) {
@@ -230,6 +238,7 @@ static char** build_envp(const char *seccomp)
        static char preload_var[PATH_MAX];
        static char seccomp_var[PATH_MAX];
        static char debug_var[] = "LD_DEBUG=all";
+       static char container_var[] = "container=ujail";
        const char *preload_lib = find_lib("libpreload-seccomp.so");
        int count = 0;
 
@@ -243,6 +252,10 @@ static char** build_envp(const char *seccomp)
                snprintf(preload_var, sizeof(preload_var), "LD_PRELOAD=%s", preload_lib);
                envp[count++] = preload_var;
        }
+
+       if (is_extroot)
+               envp[count++] = container_var;
+
        if (debug > 1)
                envp[count++] = debug_var;
 
@@ -269,6 +282,7 @@ static void usage(void)
        fprintf(stderr, "  -U <name>\tuser to run jailed process\n");
        fprintf(stderr, "  -G <name>\tgroup to run jailed process\n");
        fprintf(stderr, "  -o\t\tremont jail root (/) read only\n");
+       fprintf(stderr, "  -R <dir>\texternal jail rootfs (system container)\n");
        fprintf(stderr, "\nWarning: by default root inside the jail is the same\n\
 and he has the same powers as root outside the jail,\n\
 thus he can escape the jail and/or break stuff.\n\
@@ -437,6 +451,10 @@ int main(int argc, char **argv)
                        opts.namespace |= NAMESPACE_MOUNT;
                        opts.ronly = 1;
                        break;
+               case 'R':
+                       opts.namespace |= NAMESPACE_MOUNT | NAMESPACE_UTS;
+                       opts.extroot = optarg;
+                       break;
                case 's':
                        opts.namespace |= NAMESPACE_MOUNT;
                        opts.sysfs = 1;
@@ -502,14 +520,16 @@ int main(int argc, char **argv)
 
        opts.jail_argv = &argv[optind];
 
-       if (opts.namespace && add_path_and_deps(*opts.jail_argv, 1, -1, 0)) {
-               ERROR("failed to load dependencies\n");
-               return -1;
-       }
+       if (!opts.extroot) {
+               if (opts.namespace && add_path_and_deps(*opts.jail_argv, 1, -1, 0)) {
+                       ERROR("failed to load dependencies\n");
+                       return -1;
+               }
 
-       if (opts.namespace && opts.seccomp && add_path_and_deps("libpreload-seccomp.so", 1, -1, 1)) {
-               ERROR("failed to load libpreload-seccomp.so\n");
-               return -1;
+               if (opts.namespace && opts.seccomp && add_path_and_deps("libpreload-seccomp.so", 1, -1, 1)) {
+                       ERROR("failed to load libpreload-seccomp.so\n");
+                       return -1;
+               }
        }
 
        if (opts.name)
@@ -537,8 +557,11 @@ int main(int argc, char **argv)
                        flags |= CLONE_NEWNS;
                        add_mount("/dev/full", 0, -1);
                        add_mount("/dev/null", 0, -1);
+                       add_mount("/dev/random", 0, -1);
                        add_mount("/dev/urandom", 0, -1);
+                       add_mount("/dev/tty", 0, -1);
                        add_mount("/dev/zero", 0, -1);
+                       add_mount("/dev/console", 0, -1);
 
                        if (opts.user || opts.group) {
                                add_mount("/etc/passwd", 0, -1);
index ffaaaa172491b776a92481cebd341363792ea0c3..47b7d09dae2a5080203dd952aad346bfa074f828 100644 (file)
@@ -102,6 +102,7 @@ enum {
        JAIL_ATTR_MOUNT,
        JAIL_ATTR_NETNS,
        JAIL_ATTR_REQUIREJAIL,
+       JAIL_ATTR_EXTROOT,
        __JAIL_ATTR_MAX,
 };
 
@@ -116,6 +117,7 @@ static const struct blobmsg_policy jail_attr[__JAIL_ATTR_MAX] = {
        [JAIL_ATTR_MOUNT] = { "mount", BLOBMSG_TYPE_TABLE },
        [JAIL_ATTR_NETNS] = { "netns", BLOBMSG_TYPE_BOOL },
        [JAIL_ATTR_REQUIREJAIL] = { "requirejail", BLOBMSG_TYPE_BOOL },
+       [JAIL_ATTR_EXTROOT] = { "extroot", BLOBMSG_TYPE_STRING },
 };
 
 struct instance_netdev {
@@ -258,6 +260,11 @@ jail_run(struct service_instance *in, char **argv)
        if (jail->netns)
                argv[argc++] = "-N";
 
+       if (jail->extroot) {
+               argv[argc++] = "-R";
+               argv[argc++] = jail->extroot;
+       }
+
        blobmsg_list_for_each(&jail->mount, var) {
                const char *type = blobmsg_data(var->data);
 
@@ -863,6 +870,11 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr)
                jail->netns = blobmsg_get_bool(tb[JAIL_ATTR_NETNS]);
                jail->argc++;
        }
+       if (tb[JAIL_ATTR_EXTROOT]) {
+               jail->extroot = strdup(blobmsg_get_string(tb[JAIL_ATTR_EXTROOT]));
+               jail->argc += 2;
+       }
+
        if (tb[JAIL_ATTR_MOUNT]) {
                struct blob_attr *cur;
                int rem;
@@ -1139,6 +1151,7 @@ instance_free(struct service_instance *in)
        free(in->config);
        free(in->user);
        free(in->group);
+       free(in->jail.extroot);
        free(in->jail.name);
        free(in->jail.hostname);
        free(in->seccomp);
@@ -1262,6 +1275,8 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose)
                        blobmsg_add_string(b, "name", in->jail.name);
                if (in->jail.hostname)
                        blobmsg_add_string(b, "hostname", in->jail.hostname);
+               if (in->jail.extroot)
+                       blobmsg_add_string(b, "extroot", in->jail.extroot);
                blobmsg_add_u8(b, "procfs", in->jail.procfs);
                blobmsg_add_u8(b, "sysfs", in->jail.sysfs);
                blobmsg_add_u8(b, "ubus", in->jail.ubus);
index 003a8c999d0e66b4c30c9f6c58624bbb0ef9f2f5..29406c93ecbc71b0ffa0f91c015ffe1ded24fc84 100644 (file)
@@ -32,6 +32,7 @@ struct jail {
        bool netns;
        char *name;
        char *hostname;
+       char *extroot;
        struct blobmsg_list mount;
        int argc;
 };