jail: don't ignore return value of write()
[project/procd.git] / jail / jail.c
index c350be280fdfe3d4d6ced2beeacd41aa68a1cd91..92ced457dd3951388bc1141e677da68621bcc2bb 100644 (file)
@@ -270,6 +270,8 @@ static void free_opts(bool parent) {
        free(opts.uidmap);
        free(opts.gidmap);
        free(opts.annotations);
+       free(opts.extroot);
+       free(opts.overlaydir);
        free_hooklist(opts.hooks.createRuntime);
        free_hooklist(opts.hooks.createContainer);
        free_hooklist(opts.hooks.startContainer);
@@ -534,7 +536,10 @@ static int apply_sysctl(const char *jail_root)
                        ERROR("sysctl: can't open %s\n", fname);
                        return errno;
                }
-               write(f, (*cur)->value, strlen((*cur)->value));
+               if (write(f, (*cur)->value, strlen((*cur)->value)) < 0) {
+                       ERROR("sysctl: write to %s\n", fname);
+                       return errno;
+               }
 
                free(fname);
                close(f);
@@ -605,11 +610,11 @@ only_default_devices:
        }
 
        /* Dev symbolic links as defined in OCI spec */
-       symlink("/dev/pts/ptmx", "/dev/ptmx");
-       symlink("/proc/self/fd", "/dev/fd");
-       symlink("/proc/self/fd/0", "/dev/stdin");
-       symlink("/proc/self/fd/1", "/dev/stdout");
-       symlink("/proc/self/fd/2", "/dev/stderr");
+       (void) symlink("/dev/pts/ptmx", "/dev/ptmx");
+       (void) symlink("/proc/self/fd", "/dev/fd");
+       (void) symlink("/proc/self/fd/0", "/dev/stdin");
+       (void) symlink("/proc/self/fd/1", "/dev/stdout");
+       (void) symlink("/proc/self/fd/2", "/dev/stderr");
 
        return 0;
 }
@@ -621,6 +626,7 @@ static void enter_jail_fs(void);
 static int build_jail_fs(void)
 {
        char *overlaydir = NULL;
+       int ret;
 
        old_umask = umask(0);
 
@@ -672,8 +678,11 @@ static int build_jail_fs(void)
        if (opts.overlaydir)
                overlaydir = opts.overlaydir;
 
-       if (overlaydir)
-               mount_overlay(jail_root, overlaydir);
+       if (overlaydir) {
+               ret = mount_overlay(jail_root, overlaydir);
+               if (ret)
+                       return ret;
+       }
 
        if (chdir(jail_root)) {
                ERROR("chdir(%s) (jail_root) failed: %m\n", jail_root);
@@ -689,7 +698,7 @@ static int build_jail_fs(void)
                create_dev_console(jail_root);
 
        /* make sure /etc/resolv.conf exists if in new network namespace */
-       if (opts.namespace & CLONE_NEWNET) {
+       if (!opts.extroot && opts.namespace & CLONE_NEWNET) {
                char jailetc[PATH_MAX], jaillink[PATH_MAX];
 
                snprintf(jailetc, PATH_MAX, "%s/etc", jail_root);
@@ -698,7 +707,7 @@ static int build_jail_fs(void)
                if (overlaydir)
                        unlink(jaillink);
 
-               symlink("../dev/resolv.conf.d/resolv.conf.auto", jaillink);
+               (void) symlink("../dev/resolv.conf.d/resolv.conf.auto", jaillink);
        }
 
        run_hooks(opts.hooks.createContainer, enter_jail_fs);
@@ -891,7 +900,7 @@ static int apply_rlimits(void)
        return 0;
 }
 
-#define MAX_ENVP       16
+#define MAX_ENVP       64
 static char** build_envp(const char *seccomp, char **ocienvp)
 {
        static char *envp[MAX_ENVP];
@@ -1324,7 +1333,7 @@ static const struct blobmsg_policy oci_root_policy[] = {
 
 static int parseOCIroot(const char *jsonfile, struct blob_attr *msg)
 {
-       static char extroot[PATH_MAX] = { 0 };
+       char extroot[PATH_MAX] = { 0 };
        struct blob_attr *tb[__OCI_ROOT_MAX];
        char *cur;
        char *root_path;
@@ -1349,7 +1358,10 @@ static int parseOCIroot(const char *jsonfile, struct blob_attr *msg)
 
        strncat(extroot, root_path, PATH_MAX - (strlen(extroot) + 1));
 
-       opts.extroot = extroot;
+       /* follow symbolic link(s) */
+       opts.extroot = realpath(extroot, NULL);
+       if (!opts.extroot)
+               return errno;
 
        if (tb[OCI_ROOT_READONLY])
                opts.ronly = blobmsg_get_bool(tb[OCI_ROOT_READONLY]);
@@ -2408,6 +2420,18 @@ jail_writepid(pid_t pid)
        return 0;
 }
 
+static int checkpath(const char *path)
+{
+       int dirfd = open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+       if (dirfd == -1) {
+               ERROR("path %s open failed %m\n", path);
+               return -1;
+       }
+       close(dirfd);
+
+       return 0;
+}
+
 static struct ubus_method container_methods[] = {
        UBUS_METHOD_NOARG("start", handle_start),
        UBUS_METHOD_NOARG("state", handle_state),
@@ -2471,7 +2495,7 @@ int main(int argc, char **argv)
                        opts.namespace |= CLONE_NEWCGROUP;
                        break;
                case 'R':
-                       opts.extroot = optarg;
+                       opts.extroot = realpath(optarg, NULL);
                        break;
                case 's':
                        opts.namespace |= CLONE_NEWNS;
@@ -2520,7 +2544,7 @@ int main(int argc, char **argv)
                        opts.group = optarg;
                        break;
                case 'O':
-                       opts.overlaydir = optarg;
+                       opts.overlaydir = realpath(optarg, NULL);
                        break;
                case 'T':
                        opts.tmpoverlaysize = optarg;
@@ -2607,6 +2631,18 @@ int main(int argc, char **argv)
                goto errout;
        }
 
+       if (opts.extroot && checkpath(opts.extroot)) {
+               ERROR("invalid rootfs path '%s'", opts.extroot);
+               ret=-1;
+               goto errout;
+       }
+
+       if (opts.overlaydir && checkpath(opts.overlaydir)) {
+               ERROR("invalid rootfs overlay path '%s'", opts.overlaydir);
+               ret=-1;
+               goto errout;
+       }
+
        /* no <binary> param found */
        if (!opts.ocibundle && (argc - optind < 1)) {
                usage();
@@ -2783,7 +2819,10 @@ static void post_main(struct uloop_timeout *t)
                                ERROR("prctl(PR_SET_SECUREBITS) failed: %m\n");
                                free_and_exit(EXIT_FAILURE);
                        }
-                       seteuid(opts.root_map_uid);
+                       if (seteuid(opts.root_map_uid)) {
+                               ERROR("seteuid(%d) failed: %m\n", opts.root_map_uid);
+                               free_and_exit(EXIT_FAILURE);
+                       }
                }
 
                jail_process.pid = clone(exec_jail, child_stack + STACK_SIZE, SIGCHLD | (opts.namespace & (~CLONE_NEWCGROUP)), NULL);
@@ -2797,7 +2836,11 @@ static void post_main(struct uloop_timeout *t)
 
                uloop_process_add(&jail_process);
                jail_running = 1;
-               seteuid(0);
+               if (seteuid(0)) {
+                       ERROR("seteuid(%d) failed: %m\n", opts.root_map_uid);
+                       free_and_exit(EXIT_FAILURE);
+               }
+
                prctl(PR_SET_SECUREBITS, 0);
 
                if (pidns_fd != -1) {