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/capabilities.c | 116 ------------- jail/capabilities.h | 14 -- jail/elf.c | 355 ---------------------------------------- jail/elf.h | 38 ----- jail/jail.c | 459 ---------------------------------------------------- jail/log.h | 27 ---- jail/preload.c | 80 --------- jail/seccomp-bpf.h | 89 ---------- jail/seccomp.c | 142 ---------------- jail/seccomp.h | 19 --- 10 files changed, 1339 deletions(-) delete mode 100644 jail/capabilities.c delete mode 100644 jail/capabilities.h delete mode 100644 jail/elf.c delete mode 100644 jail/elf.h delete mode 100644 jail/jail.c delete mode 100644 jail/log.h delete mode 100644 jail/preload.c delete mode 100644 jail/seccomp-bpf.h delete mode 100644 jail/seccomp.c delete mode 100644 jail/seccomp.h (limited to 'jail') diff --git a/jail/capabilities.c b/jail/capabilities.c deleted file mode 100644 index b5ea965..0000000 --- a/jail/capabilities.c +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2015 Etienne CHAMPETIER - * - * 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 1 -#include -#include - -#include -#include - -#include "log.h" -#include "../capabilities-names.h" -#include "capabilities.h" - -static int find_capabilities(const char *name) -{ - int i; - - for (i = 0; i <= CAP_LAST_CAP; i++) - if (capabilities_names[i] && !strcmp(capabilities_names[i], name)) - return i; - - return -1; -} - -int drop_capabilities(const char *file) -{ - enum { - CAP_KEEP, - CAP_DROP, - __CAP_MAX - }; - static const struct blobmsg_policy policy[__CAP_MAX] = { - [CAP_KEEP] = { .name = "cap.keep", .type = BLOBMSG_TYPE_ARRAY }, - [CAP_DROP] = { .name = "cap.drop", .type = BLOBMSG_TYPE_ARRAY }, - }; - struct blob_buf b = { 0 }; - struct blob_attr *tb[__CAP_MAX]; - struct blob_attr *cur; - int rem, cap; - char *name; - uint64_t capdrop = 0LLU; - - DEBUG("dropping capabilities\n"); - - blob_buf_init(&b, 0); - if (!blobmsg_add_json_from_file(&b, file)) { - ERROR("failed to load %s\n", file); - return -1; - } - - blobmsg_parse(policy, __CAP_MAX, tb, blob_data(b.head), blob_len(b.head)); - if (!tb[CAP_KEEP] && !tb[CAP_DROP]) { - ERROR("failed to parse %s\n", file); - return -1; - } - - blobmsg_for_each_attr(cur, tb[CAP_KEEP], rem) { - name = blobmsg_get_string(cur); - if (!name) { - ERROR("invalid capability name in cap.keep\n"); - return -1; - } - cap = find_capabilities(name); - if (cap == -1) { - ERROR("unknown capability %s in cap.keep\n", name); - return -1; - } - capdrop |= (1LLU << cap); - } - - if (capdrop == 0LLU) { - DEBUG("cap.keep empty -> only dropping capabilities from cap.drop (blacklist)\n"); - capdrop = 0xffffffffffffffffLLU; - } else { - DEBUG("cap.keep has at least one capability -> dropping every capabilities not in cap.keep (whitelist)\n"); - } - - blobmsg_for_each_attr(cur, tb[CAP_DROP], rem) { - name = blobmsg_get_string(cur); - if (!name) { - ERROR("invalid capability name in cap.drop\n"); - return -1; - } - cap = find_capabilities(name); - if (cap == -1) { - ERROR("unknown capability %s in cap.drop\n", name); - return -1; - } - capdrop &= ~(1LLU << cap); - } - - for (cap = 0; cap <= CAP_LAST_CAP; cap++) { - if ( (capdrop & (1LLU << cap)) == 0) { - DEBUG("dropping capability %s (%d)\n", capabilities_names[cap], cap); - if (prctl(PR_CAPBSET_DROP, cap, 0, 0, 0)) { - ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %s\n", cap, strerror(errno)); - return errno; - } - } else { - DEBUG("keeping capability %s (%d)\n", capabilities_names[cap], cap); - } - } - - return 0; -} diff --git a/jail/capabilities.h b/jail/capabilities.h deleted file mode 100644 index e6699e9..0000000 --- a/jail/capabilities.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) 2015 Etienne CHAMPETIER - * - * 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. - */ - -int drop_capabilities(const char *file); diff --git a/jail/elf.c b/jail/elf.c deleted file mode 100644 index cbb3051..0000000 --- a/jail/elf.c +++ /dev/null @@ -1,355 +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 "elf.h" - -struct avl_tree libraries; -static LIST_HEAD(library_paths); - -void alloc_library_path(const char *path) -{ - struct library_path *p; - char *_path; - - p = calloc_a(sizeof(*p), - &_path, strlen(path) + 1); - if (!p) - return; - - p->path = strcpy(_path, path); - - list_add_tail(&p->list, &library_paths); - DEBUG("adding ld.so path %s\n", path); -} - -static void alloc_library(const char *path, const char *name) -{ - struct library *l; - char *_name, *_path; - - l = calloc_a(sizeof(*l), - &_path, strlen(path) + 1, - &_name, strlen(name) + 1); - if (!l) - return; - - l->avl.key = l->name = strcpy(_name, name); - l->path = strcpy(_path, path); - - avl_insert(&libraries, &l->avl); - DEBUG("adding library %s/%s\n", path, name); -} - -static int elf_open(char **dir, char *file) -{ - struct library_path *p; - char path[256]; - int fd = -1; - - *dir = NULL; - - list_for_each_entry(p, &library_paths, list) { - if (strlen(p->path)) - snprintf(path, sizeof(path), "%s/%s", p->path, file); - else - strncpy(path, file, sizeof(path)); - fd = open(path, O_RDONLY); - if (fd >= 0) { - *dir = p->path; - break; - } - } - - if (fd == -1) - fd = open(file, O_RDONLY); - - return fd; -} - -char* find_lib(char *file) -{ - struct library *l; - static char path[256]; - const char *p; - - l = avl_find_element(&libraries, file, l, avl); - if (!l) - return NULL; - - p = l->path; - if (strstr(p, "local")) - p = "/lib"; - - snprintf(path, sizeof(path), "%s/%s", p, file); - - return path; -} - -static int elf64_find_section(char *map, unsigned int type, unsigned int *offset, unsigned int *size, unsigned int *vaddr) -{ - Elf64_Ehdr *e; - Elf64_Phdr *ph; - int i; - - e = (Elf64_Ehdr *) map; - ph = (Elf64_Phdr *) (map + e->e_phoff); - - for (i = 0; i < e->e_phnum; i++) { - if (ph[i].p_type == type) { - *offset = ph[i].p_offset; - if (size) - *size = ph[i].p_filesz; - if (vaddr) - *vaddr = ph[i].p_vaddr; - return 0; - } - } - - return -1; -} - -static int elf32_find_section(char *map, unsigned int type, unsigned int *offset, unsigned int *size, unsigned int *vaddr) -{ - Elf32_Ehdr *e; - Elf32_Phdr *ph; - int i; - - e = (Elf32_Ehdr *) map; - ph = (Elf32_Phdr *) (map + e->e_phoff); - - for (i = 0; i < e->e_phnum; i++) { - if (ph[i].p_type == type) { - *offset = ph[i].p_offset; - if (size) - *size = ph[i].p_filesz; - if (vaddr) - *vaddr = ph[i].p_vaddr; - return 0; - } - } - - return -1; -} - -static int elf_find_section(char *map, unsigned int type, unsigned int *offset, unsigned int *size, unsigned int *vaddr) -{ - int clazz = map[EI_CLASS]; - - if (clazz == ELFCLASS32) - return elf32_find_section(map, type, offset, size, vaddr); - else if (clazz == ELFCLASS64) - return elf64_find_section(map, type, offset, size, vaddr); - - ERROR("unknown elf format %d\n", clazz); - - return -1; -} - -static int elf32_scan_dynamic(char *map, int dyn_offset, int dyn_size, int load_offset) -{ - Elf32_Dyn *dynamic = (Elf32_Dyn *) (map + dyn_offset); - char *strtab = NULL; - - while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { - Elf32_Dyn *curr = dynamic; - - dynamic++; - if (curr->d_tag != DT_STRTAB) - continue; - - strtab = map + (curr->d_un.d_val - load_offset); - break; - } - - if (!strtab) - return -1; - - dynamic = (Elf32_Dyn *) (map + dyn_offset); - while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { - Elf32_Dyn *curr = dynamic; - - dynamic++; - if (curr->d_tag != DT_NEEDED) - continue; - - if (elf_load_deps(&strtab[curr->d_un.d_val])) - return -1; - } - - return 0; -} - -static int elf64_scan_dynamic(char *map, int dyn_offset, int dyn_size, int load_offset) -{ - Elf64_Dyn *dynamic = (Elf64_Dyn *) (map + dyn_offset); - char *strtab = NULL; - - while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { - Elf64_Dyn *curr = dynamic; - - dynamic++; - if (curr->d_tag != DT_STRTAB) - continue; - - strtab = map + (curr->d_un.d_val - load_offset); - break; - } - - if (!strtab) - return -1; - - dynamic = (Elf64_Dyn *) (map + dyn_offset); - while ((void *) dynamic < (void *) (map + dyn_offset + dyn_size)) { - Elf64_Dyn *curr = dynamic; - - dynamic++; - if (curr->d_tag != DT_NEEDED) - continue; - - if (elf_load_deps(&strtab[curr->d_un.d_val])) - return -1; - } - - return 0; -} - -int elf_load_deps(char *library) -{ - unsigned int dyn_offset, dyn_size; - unsigned int load_offset, load_vaddr; - struct stat s; - char *map = NULL, *dir = NULL; - int clazz, fd, ret = -1; - - if (avl_find(&libraries, library)) - return 0; - - fd = elf_open(&dir, library); - - if (fd < 0) { - ERROR("failed to open %s\n", library); - return -1; - } - - if (fstat(fd, &s) == -1) { - ERROR("failed to stat %s\n", library); - ret = -1; - goto err_out; - } - - map = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (map == MAP_FAILED) { - ERROR("failed to mmap %s\n", library); - ret = -1; - goto err_out; - } - - if (elf_find_section(map, PT_LOAD, &load_offset, NULL, &load_vaddr)) { - ERROR("failed to load the .load section from %s\n", library); - ret = -1; - goto err_out; - } - - if (elf_find_section(map, PT_DYNAMIC, &dyn_offset, &dyn_size, NULL)) { - ERROR("failed to load the .dynamic section from %s\n", library); - ret = -1; - goto err_out; - } - - if (dir) { - alloc_library(dir, library); - } else { - char *elf = strdup(library); - - alloc_library(dirname(elf), basename(library)); - free(elf); - } - clazz = map[EI_CLASS]; - - if (clazz == ELFCLASS32) - ret = elf32_scan_dynamic(map, dyn_offset, dyn_size, load_vaddr - load_offset); - else if (clazz == ELFCLASS64) - ret = elf64_scan_dynamic(map, dyn_offset, dyn_size, load_vaddr - load_offset); - -err_out: - if (map) - munmap(map, s.st_size); - close(fd); - - return ret; -} - -void load_ldso_conf(const char *conf) -{ - FILE* fp = fopen(conf, "r"); - char line[256]; - - if (!fp) { - DEBUG("failed to open %s\n", conf); - return; - } - - while (!feof(fp)) { - int len; - - if (!fgets(line, 256, fp)) - break; - len = strlen(line); - if (len < 2) - continue; - if (*line == '#') - continue; - if (line[len - 1] == '\n') - line[len - 1] = '\0'; - if (!strncmp(line, "include ", 8)) { - char *sep = strstr(line, " "); - glob_t gl; - int i; - - if (!sep) - continue;; - while (*sep == ' ') - sep++; - if (glob(sep, GLOB_NOESCAPE | GLOB_MARK, NULL, &gl)) { - ERROR("glob failed on %s\n", sep); - continue; - } - for (i = 0; i < gl.gl_pathc; i++) - load_ldso_conf(gl.gl_pathv[i]); - globfree(&gl); - } else { - struct stat s; - - if (stat(line, &s)) - continue; - alloc_library_path(line); - } - } - - fclose(fp); -} diff --git a/jail/elf.h b/jail/elf.h deleted file mode 100644 index 3ae311e..0000000 --- a/jail/elf.h +++ /dev/null @@ -1,38 +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. - */ - -#ifndef _ELF_H__ -#include -#include - -#include "log.h" - -struct library { - struct avl_node avl; - char *name; - char *path; -}; - -struct library_path { - struct list_head list; - char *path; -}; - -extern struct avl_tree libraries; - -extern void alloc_library_path(const char *path); -extern char* find_lib(char *file); -extern int elf_load_deps(char *library); -extern void load_ldso_conf(const char *conf); - -#endif 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; -} diff --git a/jail/log.h b/jail/log.h deleted file mode 100644 index b1d201e..0000000 --- a/jail/log.h +++ /dev/null @@ -1,27 +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. - */ - -extern int debug; -#include - -#define INFO(fmt, ...) do { \ - printf("jail: "fmt, ## __VA_ARGS__); \ - } while (0) -#define ERROR(fmt, ...) do { \ - syslog(LOG_ERR, "jail: "fmt, ## __VA_ARGS__); \ - fprintf(stderr,"jail: "fmt, ## __VA_ARGS__); \ - } while (0) -#define DEBUG(fmt, ...) do { \ - if (debug) printf("jail: "fmt, ## __VA_ARGS__); \ - } while (0) - diff --git a/jail/preload.c b/jail/preload.c deleted file mode 100644 index a1cc0b6..0000000 --- a/jail/preload.c +++ /dev/null @@ -1,80 +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 "seccomp.h" -#include "../preload.h" - -static main_t __main__; - -static int __preload_main__(int argc, char **argv, char **envp) -{ - char *env_file = getenv("SECCOMP_FILE"); - - if (install_syscall_filter(*argv, env_file)) - return -1; - - unsetenv("LD_PRELOAD"); - unsetenv("SECCOMP_FILE"); - - return (*__main__)(argc, argv, envp); -} - -int __libc_start_main(main_t main, - int argc, - char **argv, - ElfW(auxv_t) *auxvec, - __typeof (main) init, - void (*fini) (void), - void (*rtld_fini) (void), - void *stack_end) -{ - start_main_t __start_main__; - - __start_main__ = dlsym(RTLD_NEXT, "__libc_start_main"); - if (!__start_main__) - INFO("failed to find __libc_start_main %s\n", dlerror()); - - __main__ = main; - - return (*__start_main__)(__preload_main__, argc, argv, auxvec, - init, fini, rtld_fini, stack_end); -} - -void __uClibc_main(main_t main, - int argc, - char **argv, - void (*app_init)(void), - void (*app_fini)(void), - void (*rtld_fini)(void), - void *stack_end attribute_unused) -{ - uClibc_main __start_main__; - - __start_main__ = dlsym(RTLD_NEXT, "__uClibc_main"); - if (!__start_main__) - INFO("failed to find __uClibc_main %s\n", dlerror()); - - __main__ = main; - - return (*__start_main__)(__preload_main__, argc, argv, - app_init, app_fini, rtld_fini, stack_end); -} diff --git a/jail/seccomp-bpf.h b/jail/seccomp-bpf.h deleted file mode 100644 index 82c0669..0000000 --- a/jail/seccomp-bpf.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * seccomp example for x86 (32-bit and 64-bit) with BPF macros - * - * Copyright (c) 2012 The Chromium OS Authors - * Authors: - * Will Drewry - * Kees Cook - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef _SECCOMP_BPF_H_ -#define _SECCOMP_BPF_H_ - -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#ifndef PR_SET_NO_NEW_PRIVS -# define PR_SET_NO_NEW_PRIVS 38 -#endif - -#include -#include -#include - -#ifdef HAVE_LINUX_SECCOMP_H -# include -#endif - -#ifndef SECCOMP_MODE_FILTER -#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ -#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ -#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ -#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ -#define SECCOMP_RET_LOG 0x00070000U -#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ -#define SECCOMP_RET_ERROR(x) (SECCOMP_RET_ERRNO | ((x) & 0x0000ffffU)) -#define SECCOMP_RET_LOGGER(x) (SECCOMP_RET_LOG | ((x) & 0x0000ffffU)) - -struct seccomp_data { - int nr; - __u32 arch; - __u64 instruction_pointer; - __u64 args[6]; -}; -#endif - -#ifndef SYS_SECCOMP -# define SYS_SECCOMP 1 -#endif - -#define syscall_nr (offsetof(struct seccomp_data, nr)) -#define arch_nr (offsetof(struct seccomp_data, arch)) - -#if defined(__i386__) -# define REG_SYSCALL REG_EAX -# define ARCH_NR AUDIT_ARCH_I386 -#elif defined(__x86_64__) -# define REG_SYSCALL REG_RAX -# define ARCH_NR AUDIT_ARCH_X86_64 -#elif defined(__mips__) -# define REG_SYSCALL regs[2] -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define ARCH_NR AUDIT_ARCH_MIPSEL -# else -# define ARCH_NR AUDIT_ARCH_MIPS -# endif -#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__)) -# define REG_SYSCALL regs.uregs[7] -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define ARCH_NR AUDIT_ARCH_ARM -# else -# define ARCH_NR AUDIT_ARCH_ARMEB -# endif -#else -# warning "Platform does not support seccomp filter yet" -# define REG_SYSCALL 0 -# define ARCH_NR 0 -#endif - -#endif /* _SECCOMP_BPF_H_ */ diff --git a/jail/seccomp.c b/jail/seccomp.c deleted file mode 100644 index de01fc6..0000000 --- a/jail/seccomp.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * seccomp example with syscall reporting - * - * Copyright (c) 2012 The Chromium OS Authors - * Authors: - * Kees Cook - * Will Drewry - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "seccomp-bpf.h" -#include "seccomp.h" -#include "../syscall-names.h" - -static int max_syscall = ARRAY_SIZE(syscall_names); - -static int find_syscall(const char *name) -{ - int i; - - for (i = 0; i < max_syscall; i++) - if (syscall_names[i] && !strcmp(syscall_names[i], name)) - return i; - - return -1; -} - -static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) -{ - filter->code = code; - filter->jt = jt; - filter->jf = jf; - filter->k = k; -} - -int install_syscall_filter(const char *argv, const char *file) -{ - enum { - SECCOMP_WHITELIST, - SECCOMP_POLICY, - __SECCOMP_MAX - }; - static const struct blobmsg_policy policy[__SECCOMP_MAX] = { - [SECCOMP_WHITELIST] = { .name = "whitelist", .type = BLOBMSG_TYPE_ARRAY }, - [SECCOMP_POLICY] = { .name = "policy", .type = BLOBMSG_TYPE_INT32 }, - }; - struct blob_buf b = { 0 }; - struct blob_attr *tb[__SECCOMP_MAX]; - struct blob_attr *cur; - int rem; - - struct sock_filter *filter; - struct sock_fprog prog = { 0 }; - int sz = 5, idx = 0, default_policy = 0; - - INFO("%s: setting up syscall filter\n", argv); - - blob_buf_init(&b, 0); - if (!blobmsg_add_json_from_file(&b, file)) { - INFO("%s: failed to load %s\n", argv, file); - return -1; - } - - blobmsg_parse(policy, __SECCOMP_MAX, tb, blob_data(b.head), blob_len(b.head)); - if (!tb[SECCOMP_WHITELIST]) { - INFO("%s: %s is missing the syscall table\n", argv, file); - return -1; - } - - if (tb[SECCOMP_POLICY]) - default_policy = blobmsg_get_u32(tb[SECCOMP_POLICY]); - - blobmsg_for_each_attr(cur, tb[SECCOMP_WHITELIST], rem) - sz += 2; - - filter = calloc(sz, sizeof(struct sock_filter)); - if (!filter) { - INFO("failed to allocate filter memory\n"); - return -1; - } - - /* validate arch */ - set_filter(&filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); - set_filter(&filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 1, 0, ARCH_NR); - set_filter(&filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); - - /* get syscall */ - set_filter(&filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); - - blobmsg_for_each_attr(cur, tb[SECCOMP_WHITELIST], rem) { - char *name = blobmsg_get_string(cur); - int nr; - - if (!name) { - INFO("%s: invalid syscall name\n", argv); - continue; - } - - nr = find_syscall(name); - if (nr == -1) { - INFO("%s: unknown syscall %s\n", argv, name); - continue; - } - - /* add whitelist */ - set_filter(&filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 1, nr); - set_filter(&filter[idx++], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_ALLOW); - } - - if (default_policy) - /* return -1 and set errno */ - set_filter(&filter[idx], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_LOGGER(default_policy)); - else - /* kill the process */ - set_filter(&filter[idx], BPF_RET + BPF_K, 0, 0, SECCOMP_RET_KILL); - - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { - INFO("%s: prctl(PR_SET_NO_NEW_PRIVS) failed: %s\n", argv, strerror(errno)); - return errno; - } - - prog.len = (unsigned short) idx + 1; - prog.filter = filter; - - if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) { - INFO("%s: prctl(PR_SET_SECCOMP) failed: %s\n", argv, strerror(errno)); - return errno; - } - return 0; -} diff --git a/jail/seccomp.h b/jail/seccomp.h deleted file mode 100644 index 45eede7..0000000 --- a/jail/seccomp.h +++ /dev/null @@ -1,19 +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 INFO(fmt, ...) do { \ - syslog(LOG_INFO,"preload-seccomp: "fmt, ## __VA_ARGS__); \ - fprintf(stderr,"preload-seccomp: "fmt, ## __VA_ARGS__); \ - } while (0) - -int install_syscall_filter(const char *argv, const char *file); -- cgit v1.2.3