summaryrefslogtreecommitdiffstats
path: root/jail
diff options
context:
space:
mode:
Diffstat (limited to 'jail')
-rw-r--r--jail/capabilities.c116
-rw-r--r--jail/capabilities.h14
-rw-r--r--jail/elf.c355
-rw-r--r--jail/elf.h38
-rw-r--r--jail/jail.c459
-rw-r--r--jail/log.h27
-rw-r--r--jail/preload.c80
-rw-r--r--jail/seccomp-bpf.h89
-rw-r--r--jail/seccomp.c142
-rw-r--r--jail/seccomp.h19
10 files changed, 0 insertions, 1339 deletions
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 <champetier.etienne@gmail.com>
- *
- * 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 <syslog.h>
-#include <sys/prctl.h>
-
-#include <libubox/blobmsg.h>
-#include <libubox/blobmsg_json.h>
-
-#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 <champetier.etienne@gmail.com>
- *
- * 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 <blogic@openwrt.org>
- *
- * 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 <sys/mman.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <glob.h>
-#include <elf.h>
-
-#include <libubox/utils.h>
-
-#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 <blogic@openwrt.org>
- *
- * 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 <libubox/avl.h>
-#include <libubox/avl-cmp.h>
-
-#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 <blogic@openwrt.org>
- *
- * 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 <sys/mount.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <values.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <sched.h>
-
-#include "elf.h"
-#include "capabilities.h"
-
-#include <libubox/list.h>
-#include <libubox/uloop.h>
-
-#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 <options> -- <binary> <params ...>\n");
- fprintf(stderr, " -d <num>\tshow debug log (increase num to increase verbosity)\n");
- fprintf(stderr, " -S <file>\tseccomp filter config\n");
- fprintf(stderr, " -C <file>\tcapabilities drop config\n");
- fprintf(stderr, " -n <name>\tthe name of the jail\n");
- fprintf(stderr, "namespace jail options:\n");
- fprintf(stderr, " -P <path>\tpath where the jail will be staged\n");
- fprintf(stderr, " -r <file>\treadonly files that should be staged\n");
- fprintf(stderr, " -w <file>\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 <binary> 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 <blogic@openwrt.org>
- *
- * 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 <syslog.h>
-
-#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 <blogic@openwrt.org>
- *
- * 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 <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <dlfcn.h>
-#include <syslog.h>
-
-#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 <chromium-os-dev@chromium.org>
- * Authors:
- * Will Drewry <wad@chromium.org>
- * Kees Cook <keescook@chromium.org>
- *
- * 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 <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <unistd.h>
-#include <endian.h>
-
-#include <sys/prctl.h>
-#ifndef PR_SET_NO_NEW_PRIVS
-# define PR_SET_NO_NEW_PRIVS 38
-#endif
-
-#include <linux/unistd.h>
-#include <linux/audit.h>
-#include <linux/filter.h>
-
-#ifdef HAVE_LINUX_SECCOMP_H
-# include <linux/seccomp.h>
-#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 <chromium-os-dev@chromium.org>
- * Authors:
- * Kees Cook <keescook@chromium.org>
- * Will Drewry <wad@chromium.org>
- *
- * 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 <stdio.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <syslog.h>
-
-#include <libubox/utils.h>
-#include <libubox/blobmsg.h>
-#include <libubox/blobmsg_json.h>
-
-#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 <blogic@openwrt.org>
- *
- * 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);