From 13590ca98ac2fd4939b683adbfdd63392b559f3f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 28 Nov 2015 14:58:01 +0100 Subject: Strip down procd to the necessary code, update copyright --- jail/jail.c | 459 ------------------------------------------------------------ 1 file changed, 459 deletions(-) delete mode 100644 jail/jail.c (limited to 'jail/jail.c') diff --git a/jail/jail.c b/jail/jail.c deleted file mode 100644 index 56dc9ca..0000000 --- a/jail/jail.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (C) 2015 John Crispin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 2.1 - * 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. - */ - -#define _GNU_SOURCE -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "elf.h" -#include "capabilities.h" - -#include -#include - -#define STACK_SIZE (1024 * 1024) -#define OPT_ARGS "P:S:C:n:r:w:d:psulo" - -static struct { - char *path; - char *name; - char **jail_argv; - char *seccomp; - char *capabilities; - int namespace; - int procfs; - int ronly; - int sysfs; -} opts; - -struct extra { - struct list_head list; - - const char *path; - const char *name; - int readonly; -}; - -static LIST_HEAD(extras); - -extern int pivot_root(const char *new_root, const char *put_old); - -int debug = 0; - -static char child_stack[STACK_SIZE]; - -static int mkdir_p(char *dir, mode_t mask) -{ - char *l = strrchr(dir, '/'); - int ret; - - if (!l) - return 0; - - *l = '\0'; - - if (mkdir_p(dir, mask)) - return -1; - - *l = '/'; - - ret = mkdir(dir, mask); - if (ret && errno == EEXIST) - return 0; - - if (ret) - ERROR("mkdir failed on %s: %s\n", dir, strerror(errno)); - - return ret; -} - -static int mount_bind(const char *root, const char *path, const char *name, int readonly, int error) -{ - const char *p = path; - struct stat s; - char old[256]; - char new[256]; - int fd; - - if (strstr(p, "local")) - p = "/lib"; - - snprintf(old, sizeof(old), "%s/%s", path, name); - snprintf(new, sizeof(new), "%s%s", root, p); - - mkdir_p(new, 0755); - - snprintf(new, sizeof(new), "%s%s/%s", root, p, name); - - if (stat(old, &s)) { - ERROR("%s does not exist\n", old); - return error; - } - - if (S_ISDIR(s.st_mode)) { - mkdir_p(new, 0755); - } else { - fd = creat(new, 0644); - if (fd == -1) { - ERROR("failed to create %s: %s\n", new, strerror(errno)); - return -1; - } - close(fd); - } - - if (mount(old, new, NULL, MS_BIND, NULL)) { - ERROR("failed to mount -B %s %s: %s\n", old, new, strerror(errno)); - return -1; - } - - if (readonly && mount(NULL, new, NULL, MS_BIND | MS_REMOUNT | MS_RDONLY, NULL)) { - ERROR("failed to remount ro %s: %s\n", new, strerror(errno)); - return -1; - } - - DEBUG("mount -B %s %s\n", old, new); - - return 0; -} - -static int build_jail_fs() -{ - struct library *l; - struct extra *m; - - if (mount("tmpfs", opts.path, "tmpfs", MS_NOATIME, "mode=0755")) { - ERROR("tmpfs mount failed %s\n", strerror(errno)); - return -1; - } - - if (chdir(opts.path)) { - ERROR("failed to chdir() in the jail root\n"); - return -1; - } - - avl_init(&libraries, avl_strcmp, false, NULL); - alloc_library_path("/lib64"); - alloc_library_path("/lib"); - alloc_library_path("/usr/lib"); - load_ldso_conf("/etc/ld.so.conf"); - - if (elf_load_deps(*opts.jail_argv)) { - ERROR("failed to load dependencies\n"); - return -1; - } - - if (opts.seccomp && elf_load_deps("libpreload-seccomp.so")) { - ERROR("failed to load libpreload-seccomp.so\n"); - return -1; - } - - avl_for_each_element(&libraries, l, avl) - if (mount_bind(opts.path, l->path, l->name, 1, -1)) - return -1; - - list_for_each_entry(m, &extras, list) - if (mount_bind(opts.path, m->path, m->name, m->readonly, 0)) - return -1; - - char *mpoint; - if (asprintf(&mpoint, "%s/old", opts.path) < 0) { - ERROR("failed to alloc pivot path: %s\n", strerror(errno)); - return -1; - } - mkdir_p(mpoint, 0755); - if (pivot_root(opts.path, mpoint) == -1) { - ERROR("pivot_root failed:%s\n", strerror(errno)); - free(mpoint); - return -1; - } - free(mpoint); - umount2("/old", MNT_DETACH); - rmdir("/old"); - if (opts.procfs) { - mkdir("/proc", 0755); - mount("proc", "/proc", "proc", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); - } - if (opts.sysfs) { - mkdir("/sys", 0755); - mount("sysfs", "/sys", "sysfs", MS_NOATIME | MS_NODEV | MS_NOEXEC | MS_NOSUID, 0); - } - if (opts.ronly) - mount(NULL, "/", NULL, MS_RDONLY | MS_REMOUNT, 0); - - return 0; -} - -#define MAX_ENVP 8 -static char** build_envp(const char *seccomp) -{ - static char *envp[MAX_ENVP]; - static char preload_var[64]; - static char seccomp_var[64]; - static char debug_var[] = "LD_DEBUG=all"; - char *preload_lib = find_lib("libpreload-seccomp.so"); - int count = 0; - - if (seccomp && !preload_lib) { - ERROR("failed to add preload-lib to env\n"); - return NULL; - } - if (seccomp) { - snprintf(seccomp_var, sizeof(seccomp_var), "SECCOMP_FILE=%s", seccomp); - envp[count++] = seccomp_var; - snprintf(preload_var, sizeof(preload_var), "LD_PRELOAD=%s", preload_lib); - envp[count++] = preload_var; - } - if (debug > 1) - envp[count++] = debug_var; - - return envp; -} - -static void usage(void) -{ - fprintf(stderr, "ujail -- \n"); - fprintf(stderr, " -d \tshow debug log (increase num to increase verbosity)\n"); - fprintf(stderr, " -S \tseccomp filter config\n"); - fprintf(stderr, " -C \tcapabilities drop config\n"); - fprintf(stderr, " -n \tthe name of the jail\n"); - fprintf(stderr, "namespace jail options:\n"); - fprintf(stderr, " -P \tpath where the jail will be staged\n"); - fprintf(stderr, " -r \treadonly files that should be staged\n"); - fprintf(stderr, " -w \twriteable files that should be staged\n"); - fprintf(stderr, " -p\t\tjail has /proc\n"); - fprintf(stderr, " -s\t\tjail has /sys\n"); - fprintf(stderr, " -l\t\tjail has /dev/log\n"); - fprintf(stderr, " -u\t\tjail has a ubus socket\n"); - fprintf(stderr, " -o\t\tremont jail root (/) read only\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\ -Please use seccomp/capabilities (-S/-C) to restrict his powers\n\n\ -If you use none of the namespace jail options,\n\ -ujail will not use namespace/build a jail,\n\ -and will only drop capabilities/apply seccomp filter.\n\n"); -} - -static int exec_jail() -{ - char **envp = build_envp(opts.seccomp); - if (!envp) - exit(EXIT_FAILURE); - - if (opts.capabilities && drop_capabilities(opts.capabilities)) - exit(EXIT_FAILURE); - - INFO("exec-ing %s\n", *opts.jail_argv); - execve(*opts.jail_argv, opts.jail_argv, envp); - //we get there only if execve fails - ERROR("failed to execve %s: %s\n", *opts.jail_argv, strerror(errno)); - exit(EXIT_FAILURE); -} - -static int spawn_jail(void *arg) -{ - if (opts.name && sethostname(opts.name, strlen(opts.name))) { - ERROR("failed to sethostname: %s\n", strerror(errno)); - } - - if (build_jail_fs()) { - ERROR("failed to build jail fs"); - exit(EXIT_FAILURE); - } - - return exec_jail(); -} - -static int jail_running = 1; -static int jail_return_code = 0; - -static void jail_process_handler(struct uloop_process *c, int ret) -{ - if (WIFEXITED(ret)) { - jail_return_code = WEXITSTATUS(ret); - INFO("jail (%d) exited with exit: %d\n", c->pid, jail_return_code); - } else { - jail_return_code = WTERMSIG(ret); - INFO("jail (%d) exited with signal: %d\n", c->pid, jail_return_code); - } - jail_running = 0; - uloop_end(); -} - -static struct uloop_process jail_process = { - .cb = jail_process_handler, -}; - -static void add_extra(char *name, int readonly) -{ - struct extra *f; - - if (*name != '/') { - ERROR("%s is not an absolute path\n", name); - return; - } - - f = calloc(1, sizeof(struct extra)); - - f->name = basename(name); - f->path = dirname(strdup(name)); - f->readonly = readonly; - - list_add_tail(&f->list, &extras); -} - -int main(int argc, char **argv) -{ - uid_t uid = getuid(); - char log[] = "/dev/log"; - char ubus[] = "/var/run/ubus.sock"; - int ret = EXIT_SUCCESS; - int ch; - - if (uid) { - ERROR("not root, aborting: %s\n", strerror(errno)); - return EXIT_FAILURE; - } - - umask(022); - - while ((ch = getopt(argc, argv, OPT_ARGS)) != -1) { - switch (ch) { - case 'd': - debug = atoi(optarg); - break; - case 'p': - opts.namespace = 1; - opts.procfs = 1; - break; - case 'o': - opts.namespace = 1; - opts.ronly = 1; - break; - case 's': - opts.namespace = 1; - opts.sysfs = 1; - break; - case 'S': - opts.seccomp = optarg; - add_extra(optarg, 1); - break; - case 'C': - opts.capabilities = optarg; - add_extra(optarg, 1); - break; - case 'P': - opts.namespace = 1; - opts.path = optarg; - break; - case 'n': - opts.name = optarg; - break; - case 'r': - opts.namespace = 1; - add_extra(optarg, 1); - break; - case 'w': - opts.namespace = 1; - add_extra(optarg, 0); - break; - case 'u': - opts.namespace = 1; - add_extra(ubus, 0); - break; - case 'l': - opts.namespace = 1; - add_extra(log, 0); - break; - } - } - - //no param found - if (argc - optind < 1) { - usage(); - return EXIT_FAILURE; - } - if (!(opts.namespace||opts.capabilities||opts.seccomp)) { - ERROR("Not using namespaces, capabilities or seccomp !!!\n\n"); - usage(); - return EXIT_FAILURE; - } - DEBUG("Using namespaces(%d), capabilities(%d), seccomp(%d)\n", - opts.namespace, - opts.capabilities != 0, - opts.seccomp != 0); - - opts.jail_argv = &argv[optind]; - - if (opts.name) - prctl(PR_SET_NAME, opts.name, NULL, NULL, NULL); - - if (opts.namespace && !opts.path && asprintf(&opts.path, "/tmp/%s", basename(*opts.jail_argv)) == -1) { - ERROR("failed to asprintf root path: %s\n", strerror(errno)); - return EXIT_FAILURE; - } - - if (opts.namespace && mkdir(opts.path, 0755)) { - ERROR("unable to create root path: %s (%s)\n", opts.path, strerror(errno)); - return EXIT_FAILURE; - } - - uloop_init(); - if (opts.namespace) { - jail_process.pid = clone(spawn_jail, - child_stack + STACK_SIZE, - CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | SIGCHLD, argv); - } else { - jail_process.pid = fork(); - } - - if (jail_process.pid > 0) { - //parent process - uloop_process_add(&jail_process); - uloop_run(); - uloop_done(); - if (jail_running) { - DEBUG("uloop interrupted, killing jail process\n"); - kill(jail_process.pid, SIGTERM); - waitpid(jail_process.pid, NULL, 0); - } - } else if (jail_process.pid == 0) { - //fork child process - return exec_jail(); - } else { - ERROR("failed to clone/fork: %s\n", strerror(errno)); - ret = EXIT_FAILURE; - } - - if (opts.namespace && rmdir(opts.path)) { - ERROR("Unable to remove root path: %s (%s)\n", opts.path, strerror(errno)); - ret = EXIT_FAILURE; - } - - if (ret) - return ret; - - return jail_return_code; -} -- cgit v1.2.3