config: Initial work on converting config.c to c++ protobuf lib

config: Initial work on converting config.c to c++ protobuf lib #2

config: Initial work on converting config.c to c++ protobuf lib #3

config: Initial work on converting config.c to c++ protobuf lib #4

config: Initial work on converting config.c to c++ protobuf lib #5

config: Initial work on converting config.c to c++ protobuf lib #6
This commit is contained in:
Robert Swiecki 2017-09-13 22:03:21 +02:00
parent dae05bfd31
commit 374f6cc4f0
24 changed files with 832 additions and 843 deletions

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "kafel"]
path = kafel
url = https://github.com/google/kafel.git
[submodule "protobuf-c-text"]
path = protobuf-c-text
url = https://github.com/protobuf-c/protobuf-c-text.git

View File

@ -18,25 +18,31 @@
#
CC ?= gcc
CXX ?= g++
EXTRA_CFLAGS := $(CFLAGS)
CFLAGS += -O2 -c -std=gnu11 \
COMMON_FLAGS += -O2 -c \
-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 \
-Wformat -Wformat=2 -Wformat-security -fPIE \
-Wno-format-nonliteral \
-Wall -Wextra -Werror \
-Ikafel/include
LDFLAGS += -Wl,-z,now -Wl,-z,relro -pie -Wl,-z,noexecstack -lpthread -lcap
CFLAGS += $(COMMON_FLAGS) -std=gnu11
CXXFLAGS += $(COMMON_FLAGS) $(shell pkg-config --cflags protobuf) -std=c++11 -Wno-unused
LDFLAGS += -Wl,-z,now -Wl,-z,relro -pie -Wl,-z,noexecstack -lpthread -lcap $(shell pkg-config --libs protobuf)
BIN = nsjail
LIBS = kafel/libkafel.a
SRCS = nsjail.c caps.c cmdline.c config.c contain.c log.c cgroup.c mount.c net.c pid.c sandbox.c subproc.c user.c util.c uts.c cpu.c
OBJS = $(SRCS:.c=.o)
SRCS_C = nsjail.c caps.c cmdline.c contain.c log.c cgroup.c mount.c net.c pid.c sandbox.c subproc.c user.c util.c uts.c cpu.c
SRCS_CXX = config.cc
SRCS_PB = config.proto
OBJS = $(SRCS_C:.c=.o) $(SRCS_CXX:.cc=.o) $(SRCS_PB:.proto=.pb.o)
PROTO_DEPS = config.pb.cc config.pb.h
ifdef DEBUG
CFLAGS += -g -ggdb -gdwarf-4
CXXFLAGS += -g -ggdb -gdwarf-4
endif
USE_NL3 ?= yes
@ -48,58 +54,18 @@ ifeq ($(NL3_EXISTS), yes)
endif
endif
USE_PROTOBUF ?= yes
ifeq ($(USE_PROTOBUF), yes)
ifeq ("$(shell which protoc-c)", "")
USE_PROTOBUF := no
PROTOC_WARNING := yes
endif
endif
ifeq ($(USE_PROTOBUF), no)
else ifeq ($(shell pkg-config --exists libprotobuf-c && echo yes), yes)
PROTO_DEPS = config.pb-c.h config.pb-c.c
SRCS += config.pb-c.c
CFLAGS += -DNSJAIL_WITH_PROTOBUF -Iprotobuf-c-text/protobuf-c-text $(shell pkg-config --cflags libprotobuf-c)
LIBS += protobuf-c-text/protobuf-c-text/.libs/libprotobuf-c-text.a
LDFLAGS += $(shell pkg-config --libs libprotobuf-c)
else ifneq ("$(wildcard /usr/include/google/protobuf-c/protobuf-c.h)", "")
PROTO_DEPS = config.pb-c.h config.pb-c.c
SRCS += config.pb-c.c
CFLAGS += -DNSJAIL_WITH_PROTOBUF -Iprotobuf-c-text/protobuf-c-text -I/usr/include/google
LIBS += protobuf-c-text/protobuf-c-text/.libs/libprotobuf-c-text.a
LDFLAGS += -Wl,-lprotobuf-c
else ifneq ("$(wildcard /usr/local/include/google/protobuf-c/protobuf-c.h)", "")
PROTO_DEPS = config.pb-c.h config.pb-c.c
SRCS += config.pb-c.c
CFLAGS += -DNSJAIL_WITH_PROTOBUF -Iprotobuf-c-text/protobuf-c-text -I/usr/local/include/google
LIBS += protobuf-c-text/protobuf-c-text/.libs/libprotobuf-c-text.a
LDFLAGS += -Wl,--library-path=/usr/local/lib -Wl,-lprotobuf-c
else
USE_PROTOBUF := no
endif
.PHONY: all clear depend indent
.c.o: %.c
$(CC) $(CFLAGS) $< -o $@
.cc.o: %.cc
$(CXX) $(CXXFLAGS) $< -o $@
all: $(PROTO_DEPS) $(BIN)
ifeq ($(PROTOC_WARNING), yes)
$(info *********************************************************)
$(info * 'protoc-c' is missing on your system *)
$(info * Install 'protobuf-c-compiler' or a similar package *)
$(info *********************************************************)
endif
ifeq ($(USE_PROTOBUF), no)
$(info *********************************************************)
$(info * Code compiled without libprotobuf-c/libprotobuf-c-dev *)
$(info * The --config commandline option will be unavailable *)
$(info *********************************************************)
endif
$(BIN): $(LIBS) $(OBJS)
$(CC) -o $(BIN) $(OBJS) $(LIBS) $(LDFLAGS)
$(CXX) -o $(BIN) $(OBJS) $(LIBS) $(LDFLAGS)
kafel/libkafel.a:
ifeq ("$(wildcard kafel/Makefile)","")
@ -107,39 +73,27 @@ ifeq ("$(wildcard kafel/Makefile)","")
endif
$(MAKE) -C kafel
protobuf-c-text/protobuf-c-text/.libs/libprotobuf-c-text.a:
ifeq ("$(wildcard protobuf-c-text/configure)","")
git submodule update --init
endif
ifeq ("$(wildcard protobuf-c-text/Makefile)","")
sh -c "cd protobuf-c-text; CFLAGS=\"-fPIC -I/usr/include/google $(EXTRA_CFLAGS)\" ./autogen.sh --enable-shared=no --disable-doxygen-doc;"
endif
$(MAKE) -C protobuf-c-text
$(PROTO_DEPS): config.proto
protoc-c --c_out=. config.proto
$(PROTO_DEPS): $(SRCS_PB)
protoc --cpp_out=. $(SRCS_PB)
clean:
$(RM) core Makefile.bak $(OBJS) $(BIN) $(PROTO_DEPS)
ifneq ("$(wildcard kafel/Makefile)","")
$(MAKE) -C kafel clean
endif
ifneq ("$(wildcard protobuf-c-text/Makefile)","")
$(MAKE) -C protobuf-c-text clean
endif
depend:
makedepend -Y -Ykafel/include -- -- $(SRCS)
makedepend -Y -Ykafel/include -- -- $(SRCS_C) $(SRCS_CXX)
indent:
clang-format --style=WebKit -i -sort-includes *.c *.h $(SRCS_CXX)
indent -linux -l100 -lc100 *.c *.h; rm -f *~
# DO NOT DELETE THIS LINE -- make depend depends on it.
nsjail.o: nsjail.h common.h caps.h cmdline.h log.h net.h subproc.h util.h
caps.o: caps.h common.h log.h util.h
cmdline.o: cmdline.h common.h caps.h config.h log.h mount.h util.h user.h
config.o: common.h caps.h config.h log.h mount.h user.h util.h
cmdline.o: cmdline.h common.h caps.h config.h log.h mount.h user.h util.h
contain.o: contain.h common.h caps.h cgroup.h cpu.h log.h mount.h net.h pid.h
contain.o: user.h util.h uts.h
log.o: log.h common.h
@ -154,3 +108,4 @@ user.o: user.h common.h log.h subproc.h util.h
util.o: util.h common.h log.h
uts.o: uts.h common.h log.h
cpu.o: cpu.h common.h log.h util.h
config.o: common.h caps.h config.h log.h mount.h user.h util.h

16
caps.c
View File

@ -21,8 +21,8 @@
#include "caps.h"
#include <sys/capability.h>
#include <string.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
@ -30,7 +30,10 @@
#include "log.h"
#include "util.h"
#define VALSTR_STRUCT(x) { x, #x }
#define VALSTR_STRUCT(x) \
{ \
x, #x \
}
/* *INDENT-OFF* */
static struct {
@ -209,7 +212,8 @@ bool capsInitNs(struct nsjconf_t *nsjconf)
}
if (prctl
(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)capNames[i].val,
0UL, 0UL) == -1) {
0UL, 0UL)
== -1) {
PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)",
capNames[i].name);
} else {
@ -219,9 +223,9 @@ bool capsInitNs(struct nsjconf_t *nsjconf)
} else {
struct ints_t *p;
TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
if (prctl
(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL,
0UL) == -1) {
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL,
0UL)
== -1) {
PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)",
capsValToStr(p->val));
} else {

174
cmdline.c
View File

@ -45,8 +45,8 @@
#include "config.h"
#include "log.h"
#include "mount.h"
#include "util.h"
#include "user.h"
#include "util.h"
struct custom_option {
struct option opt;
@ -55,8 +55,8 @@ struct custom_option {
/* *INDENT-OFF* */
struct custom_option custom_opts[] = {
{{"help", no_argument, NULL, 'h'}, "Help plz.."},
{{"mode", required_argument, NULL, 'M'},
{ { "help", no_argument, NULL, 'h' }, "Help plz.." },
{ { "mode", required_argument, NULL, 'M' },
"Execution mode (default: o [MODE_STANDALONE_ONCE]):\n"
"\tl: Wait for connections on a TCP port (specified with --port) "
"[MODE_LISTEN_TCP]\n"
@ -65,81 +65,81 @@ struct custom_option custom_opts[] = {
"\te: Immediately launch a single process on the console using execve "
"[MODE_STANDALONE_EXECVE]\n"
"\tr: Immediately launch a single process on the console, keep doing it "
"forever [MODE_STANDALONE_RERUN]"},
{{"config", required_argument, NULL, 'C'}, "Configuration file in the config.proto ProtoBuf format"},
{{"exec_file", required_argument, NULL, 'x'}, "File to exec (default: argv[0])"},
{{"chroot", required_argument, NULL, 'c'}, "Directory containing / of the jail (default: none)"},
{{"rw", no_argument, NULL, 0x601}, "Mount / and /proc as RW (default: RO)"},
{{"user", required_argument, NULL, 'u'}, "Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid:count convention here. Can be specified multiple times"},
{{"group", required_argument, NULL, 'g'}, "Groupname/gid of processess inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid:count convention here. Can be specified multiple times"},
{{"hostname", required_argument, NULL, 'H'}, "UTS name (hostname) of the jail (default: 'NSJAIL')"},
{{"cwd", required_argument, NULL, 'D'}, "Directory in the namespace the process will run (default: '/')"},
{{"port", required_argument, NULL, 'p'}, "TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)"},
{{"bindhost", required_argument, NULL, 0x604}, "IP address to bind the port to (only in [MODE_LISTEN_TCP]), (default: '::')"},
{{"max_conns_per_ip", required_argument, NULL, 'i'}, "Maximum number of connections per one IP (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))"},
{{"log", required_argument, NULL, 'l'}, "Log file (default: use log_fd)"},
{{"log_fd", required_argument, NULL, 'L'}, "Log FD (default: 2)"},
{{"time_limit", required_argument, NULL, 't'}, "Maximum time that a jail can exist, in seconds (default: 600)"},
{{"max_cpus", required_argument, NULL, 0x508}, "Maximum number of CPUs a single jailed process can use (default: 0 'no limit')"},
{{"daemon", no_argument, NULL, 'd'}, "Daemonize after start"},
{{"verbose", no_argument, NULL, 'v'}, "Verbose output"},
{{"quiet", no_argument, NULL, 'q'}, "Only output warning and more important messages"},
{{"keep_env", no_argument, NULL, 'e'}, "Should all environment variables be passed to the child?"},
{{"env", required_argument, NULL, 'E'}, "Environment variable (can be used multiple times)"},
{{"keep_caps", no_argument, NULL, 0x0501}, "Don't drop capabilities in the local namespace"},
{{"silent", no_argument, NULL, 0x0502}, "Redirect child's fd:0/1/2 to /dev/null"},
{{"skip_setsid", no_argument, NULL, 0x0504}, "Don't call setsid(), allows for terminal signal handling in the sandboxed process"},
{{"pass_fd", required_argument, NULL, 0x0505}, "Don't close this FD before executing child (can be specified multiple times), by default: 0/1/2 are kept open"},
{{"disable_no_new_privs", no_argument, NULL, 0x0507}, "Don't set the prctl(NO_NEW_PRIVS, 1) (DANGEROUS)"},
{{"cap", required_argument, NULL, 0x0509}, "Retain this capability in local namespace (e.g. CAP_PTRACE). Can be specified multiple times"},
{{"rlimit_as", required_argument, NULL, 0x0201}, "RLIMIT_AS in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 512)"},
{{"rlimit_core", required_argument, NULL, 0x0202}, "RLIMIT_CORE in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 0)"},
{{"rlimit_cpu", required_argument, NULL, 0x0203}, "RLIMIT_CPU, 'max' for RLIM_INFINITY, 'def' for the current value (default: 600)"},
{{"rlimit_fsize", required_argument, NULL, 0x0204}, "RLIMIT_FSIZE in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 1)"},
{{"rlimit_nofile", required_argument, NULL, 0x0205}, "RLIMIT_NOFILE, 'max' for RLIM_INFINITY, 'def' for the current value (default: 32)"},
{{"rlimit_nproc", required_argument, NULL, 0x0206}, "RLIMIT_NPROC, 'max' for RLIM_INFINITY, 'def' for the current value (default: 'def')"},
{{"rlimit_stack", required_argument, NULL, 0x0207}, "RLIMIT_STACK in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 'def')"},
{{"persona_addr_compat_layout", no_argument, NULL, 0x0301}, "personality(ADDR_COMPAT_LAYOUT)"},
{{"persona_mmap_page_zero", no_argument, NULL, 0x0302}, "personality(MMAP_PAGE_ZERO)"},
{{"persona_read_implies_exec", no_argument, NULL, 0x0303}, "personality(READ_IMPLIES_EXEC)"},
{{"persona_addr_limit_3gb", no_argument, NULL, 0x0304}, "personality(ADDR_LIMIT_3GB)"},
{{"persona_addr_no_randomize", no_argument, NULL, 0x0305}, "personality(ADDR_NO_RANDOMIZE)"},
{{"disable_clone_newnet", no_argument, NULL, 'N'}, "Don't use CLONE_NEWNET. Enable networking inside the jail"},
{{"disable_clone_newuser", no_argument, NULL, 0x0402}, "Don't use CLONE_NEWUSER. Requires euid==0"},
{{"disable_clone_newns", no_argument, NULL, 0x0403}, "Don't use CLONE_NEWNS"},
{{"disable_clone_newpid", no_argument, NULL, 0x0404}, "Don't use CLONE_NEWPID"},
{{"disable_clone_newipc", no_argument, NULL, 0x0405}, "Don't use CLONE_NEWIPC"},
{{"disable_clone_newuts", no_argument, NULL, 0x0406}, "Don't use CLONE_NEWUTS"},
{{"enable_clone_newcgroup", no_argument, NULL, 0x0407}, "Use CLONE_NEWCGROUP"},
{{"uid_mapping", required_argument, NULL, 'U'}, "Add a custom uid mapping of the form inside_uid:outside_uid:count. Setting this requires newuidmap to be present"},
{{"gid_mapping", required_argument, NULL, 'G'}, "Add a custom gid mapping of the form inside_gid:outside_gid:count. Setting this requires newgidmap to be present"},
{{"bindmount_ro", required_argument, NULL, 'R'}, "List of mountpoints to be mounted --bind (ro) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'"},
{{"bindmount", required_argument, NULL, 'B'}, "List of mountpoints to be mounted --bind (rw) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'"},
{{"tmpfsmount", required_argument, NULL, 'T'}, "List of mountpoints to be mounted as RW/tmpfs inside the container. Can be specified multiple times. Supports 'dest' syntax"},
{{"tmpfs_size", required_argument, NULL, 0x0602}, "Number of bytes to allocate for tmpfsmounts (default: 4194304)"},
{{"disable_proc", no_argument, NULL, 0x0603}, "Disable mounting /proc in the jail"},
{{"seccomp_policy", required_argument, NULL, 'P'}, "Path to file containing seccomp-bpf policy (see kafel/)"},
{{"seccomp_string", required_argument, NULL, 0x0901}, "String with kafel seccomp-bpf policy (see kafel/)"},
{{"cgroup_mem_max", required_argument, NULL, 0x0801}, "Maximum number of bytes to use in the group (default: '0' - disabled)"},
{{"cgroup_mem_mount", required_argument, NULL, 0x0802}, "Location of memory cgroup FS (default: '/sys/fs/cgroup/memory')"},
{{"cgroup_mem_parent", required_argument, NULL, 0x0803}, "Which pre-existing memory cgroup to use as a parent (default: 'NSJAIL')"},
{{"cgroup_pids_max", required_argument, NULL, 0x0811}, "Maximum number of pids in a cgroup (default: '0' - disabled)"},
{{"cgroup_pids_mount", required_argument, NULL, 0x0812}, "Location of pids cgroup FS (default: '/sys/fs/cgroup/pids')"},
{{"cgroup_pids_parent", required_argument, NULL, 0x0813}, "Which pre-existing pids cgroup to use as a parent (default: 'NSJAIL')"},
{{"iface_no_lo", no_argument, NULL, 0x700}, "Don't bring up the 'lo' interface"},
{{"macvlan_iface", required_argument, NULL, 'I'}, "Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs'"},
{{"macvlan_vs_ip", required_argument, NULL, 0x701}, "IP of the 'vs' interface (e.g. \"192.168.0.1\")"},
{{"macvlan_vs_nm", required_argument, NULL, 0x702}, "Netmask of the 'vs' interface (e.g. \"255.255.255.0\")"},
{{"macvlan_vs_gw", required_argument, NULL, 0x703}, "Default GW for the 'vs' interface (e.g. \"192.168.0.1\")"},
"forever [MODE_STANDALONE_RERUN]" },
{ { "config", required_argument, NULL, 'C' }, "Configuration file in the config.proto ProtoBuf format" },
{ { "exec_file", required_argument, NULL, 'x' }, "File to exec (default: argv[0])" },
{ { "chroot", required_argument, NULL, 'c' }, "Directory containing / of the jail (default: none)" },
{ { "rw", no_argument, NULL, 0x601 }, "Mount / and /proc as RW (default: RO)" },
{ { "user", required_argument, NULL, 'u' }, "Username/uid of processess inside the jail (default: your current uid). You can also use inside_ns_uid:outside_ns_uid:count convention here. Can be specified multiple times" },
{ { "group", required_argument, NULL, 'g' }, "Groupname/gid of processess inside the jail (default: your current gid). You can also use inside_ns_gid:global_ns_gid:count convention here. Can be specified multiple times" },
{ { "hostname", required_argument, NULL, 'H' }, "UTS name (hostname) of the jail (default: 'NSJAIL')" },
{ { "cwd", required_argument, NULL, 'D' }, "Directory in the namespace the process will run (default: '/')" },
{ { "port", required_argument, NULL, 'p' }, "TCP port to bind to (enables MODE_LISTEN_TCP) (default: 0)" },
{ { "bindhost", required_argument, NULL, 0x604 }, "IP address to bind the port to (only in [MODE_LISTEN_TCP]), (default: '::')" },
{ { "max_conns_per_ip", required_argument, NULL, 'i' }, "Maximum number of connections per one IP (only in [MODE_LISTEN_TCP]), (default: 0 (unlimited))" },
{ { "log", required_argument, NULL, 'l' }, "Log file (default: use log_fd)" },
{ { "log_fd", required_argument, NULL, 'L' }, "Log FD (default: 2)" },
{ { "time_limit", required_argument, NULL, 't' }, "Maximum time that a jail can exist, in seconds (default: 600)" },
{ { "max_cpus", required_argument, NULL, 0x508 }, "Maximum number of CPUs a single jailed process can use (default: 0 'no limit')" },
{ { "daemon", no_argument, NULL, 'd' }, "Daemonize after start" },
{ { "verbose", no_argument, NULL, 'v' }, "Verbose output" },
{ { "quiet", no_argument, NULL, 'q' }, "Only output warning and more important messages" },
{ { "keep_env", no_argument, NULL, 'e' }, "Should all environment variables be passed to the child?" },
{ { "env", required_argument, NULL, 'E' }, "Environment variable (can be used multiple times)" },
{ { "keep_caps", no_argument, NULL, 0x0501 }, "Don't drop capabilities in the local namespace" },
{ { "silent", no_argument, NULL, 0x0502 }, "Redirect child's fd:0/1/2 to /dev/null" },
{ { "skip_setsid", no_argument, NULL, 0x0504 }, "Don't call setsid(), allows for terminal signal handling in the sandboxed process" },
{ { "pass_fd", required_argument, NULL, 0x0505 }, "Don't close this FD before executing child (can be specified multiple times), by default: 0/1/2 are kept open" },
{ { "disable_no_new_privs", no_argument, NULL, 0x0507 }, "Don't set the prctl(NO_NEW_PRIVS, 1) (DANGEROUS)" },
{ { "cap", required_argument, NULL, 0x0509 }, "Retain this capability in local namespace (e.g. CAP_PTRACE). Can be specified multiple times" },
{ { "rlimit_as", required_argument, NULL, 0x0201 }, "RLIMIT_AS in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 512)" },
{ { "rlimit_core", required_argument, NULL, 0x0202 }, "RLIMIT_CORE in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 0)" },
{ { "rlimit_cpu", required_argument, NULL, 0x0203 }, "RLIMIT_CPU, 'max' for RLIM_INFINITY, 'def' for the current value (default: 600)" },
{ { "rlimit_fsize", required_argument, NULL, 0x0204 }, "RLIMIT_FSIZE in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 1)" },
{ { "rlimit_nofile", required_argument, NULL, 0x0205 }, "RLIMIT_NOFILE, 'max' for RLIM_INFINITY, 'def' for the current value (default: 32)" },
{ { "rlimit_nproc", required_argument, NULL, 0x0206 }, "RLIMIT_NPROC, 'max' for RLIM_INFINITY, 'def' for the current value (default: 'def')" },
{ { "rlimit_stack", required_argument, NULL, 0x0207 }, "RLIMIT_STACK in MB, 'max' for RLIM_INFINITY, 'def' for the current value (default: 'def')" },
{ { "persona_addr_compat_layout", no_argument, NULL, 0x0301 }, "personality(ADDR_COMPAT_LAYOUT)" },
{ { "persona_mmap_page_zero", no_argument, NULL, 0x0302 }, "personality(MMAP_PAGE_ZERO)" },
{ { "persona_read_implies_exec", no_argument, NULL, 0x0303 }, "personality(READ_IMPLIES_EXEC)" },
{ { "persona_addr_limit_3gb", no_argument, NULL, 0x0304 }, "personality(ADDR_LIMIT_3GB)" },
{ { "persona_addr_no_randomize", no_argument, NULL, 0x0305 }, "personality(ADDR_NO_RANDOMIZE)" },
{ { "disable_clone_newnet", no_argument, NULL, 'N' }, "Don't use CLONE_NEWNET. Enable networking inside the jail" },
{ { "disable_clone_newuser", no_argument, NULL, 0x0402 }, "Don't use CLONE_NEWUSER. Requires euid==0" },
{ { "disable_clone_newns", no_argument, NULL, 0x0403 }, "Don't use CLONE_NEWNS" },
{ { "disable_clone_newpid", no_argument, NULL, 0x0404 }, "Don't use CLONE_NEWPID" },
{ { "disable_clone_newipc", no_argument, NULL, 0x0405 }, "Don't use CLONE_NEWIPC" },
{ { "disable_clone_newuts", no_argument, NULL, 0x0406 }, "Don't use CLONE_NEWUTS" },
{ { "enable_clone_newcgroup", no_argument, NULL, 0x0407 }, "Use CLONE_NEWCGROUP" },
{ { "uid_mapping", required_argument, NULL, 'U' }, "Add a custom uid mapping of the form inside_uid:outside_uid:count. Setting this requires newuidmap to be present" },
{ { "gid_mapping", required_argument, NULL, 'G' }, "Add a custom gid mapping of the form inside_gid:outside_gid:count. Setting this requires newgidmap to be present" },
{ { "bindmount_ro", required_argument, NULL, 'R' }, "List of mountpoints to be mounted --bind (ro) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'" },
{ { "bindmount", required_argument, NULL, 'B' }, "List of mountpoints to be mounted --bind (rw) inside the container. Can be specified multiple times. Supports 'source' syntax, or 'source:dest'" },
{ { "tmpfsmount", required_argument, NULL, 'T' }, "List of mountpoints to be mounted as RW/tmpfs inside the container. Can be specified multiple times. Supports 'dest' syntax" },
{ { "tmpfs_size", required_argument, NULL, 0x0602 }, "Number of bytes to allocate for tmpfsmounts (default: 4194304)" },
{ { "disable_proc", no_argument, NULL, 0x0603 }, "Disable mounting /proc in the jail" },
{ { "seccomp_policy", required_argument, NULL, 'P' }, "Path to file containing seccomp-bpf policy (see kafel/)" },
{ { "seccomp_string", required_argument, NULL, 0x0901 }, "String with kafel seccomp-bpf policy (see kafel/)" },
{ { "cgroup_mem_max", required_argument, NULL, 0x0801 }, "Maximum number of bytes to use in the group (default: '0' - disabled)" },
{ { "cgroup_mem_mount", required_argument, NULL, 0x0802 }, "Location of memory cgroup FS (default: '/sys/fs/cgroup/memory')" },
{ { "cgroup_mem_parent", required_argument, NULL, 0x0803 }, "Which pre-existing memory cgroup to use as a parent (default: 'NSJAIL')" },
{ { "cgroup_pids_max", required_argument, NULL, 0x0811 }, "Maximum number of pids in a cgroup (default: '0' - disabled)" },
{ { "cgroup_pids_mount", required_argument, NULL, 0x0812 }, "Location of pids cgroup FS (default: '/sys/fs/cgroup/pids')" },
{ { "cgroup_pids_parent", required_argument, NULL, 0x0813 }, "Which pre-existing pids cgroup to use as a parent (default: 'NSJAIL')" },
{ { "iface_no_lo", no_argument, NULL, 0x700 }, "Don't bring up the 'lo' interface" },
{ { "macvlan_iface", required_argument, NULL, 'I' }, "Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs'" },
{ { "macvlan_vs_ip", required_argument, NULL, 0x701 }, "IP of the 'vs' interface (e.g. \"192.168.0.1\")" },
{ { "macvlan_vs_nm", required_argument, NULL, 0x702 }, "Netmask of the 'vs' interface (e.g. \"255.255.255.0\")" },
{ { "macvlan_vs_gw", required_argument, NULL, 0x703 }, "Default GW for the 'vs' interface (e.g. \"192.168.0.1\")" },
};
struct custom_option deprecated_opts[] = {
// Compatibilty flags for MACVLAN.
// TODO(rswiecki): Remove this at some point.
{{"iface", required_argument, NULL, 'I'}, "Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs'"},
{{"iface_vs_ip", required_argument, NULL, 0x701}, "IP of the 'vs' interface (e.g. \"192.168.0.1\")"},
{{"iface_vs_nm", required_argument, NULL, 0x702}, "Netmask of the 'vs' interface (e.g. \"255.255.255.0\")"},
{{"iface_vs_gw", required_argument, NULL, 0x703}, "Default GW for the 'vs' interface (e.g. \"192.168.0.1\")"},
{ { "iface", required_argument, NULL, 'I' }, "Interface which will be cloned (MACVLAN) and put inside the subprocess' namespace as 'vs'" },
{ { "iface_vs_ip", required_argument, NULL, 0x701 }, "IP of the 'vs' interface (e.g. \"192.168.0.1\")" },
{ { "iface_vs_nm", required_argument, NULL, 0x702 }, "Netmask of the 'vs' interface (e.g. \"255.255.255.0\")" },
{ { "iface_vs_gw", required_argument, NULL, 0x703 }, "Default GW for the 'vs' interface (e.g. \"192.168.0.1\")" },
};
/* *INDENT-ON* */
@ -576,12 +576,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt,
size_t count = (cnt == NULL || strlen(cnt) == 0)
? 1U : (size_t) strtoull(cnt,
NULL,
0);
if (userParseId(nsjconf, i_id, o_id, count, false /* is_gid */ ,
false /* is_newidmap */ ) == false) {
false /* is_newidmap */ )
== false) {
return false;
}
}
@ -590,12 +591,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt,
size_t count = (cnt == NULL || strlen(cnt) == 0)
? 1U : (size_t) strtoull(cnt,
NULL,
0);
if (userParseId(nsjconf, i_id, o_id, count, true /* is_gid */ ,
false /* is_newidmap */ ) == false) {
false /* is_newidmap */ )
== false) {
return false;
}
}
@ -604,12 +606,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt,
size_t count = (cnt == NULL || strlen(cnt) == 0)
? 1U : (size_t) strtoull(cnt,
NULL,
0);
if (userParseId(nsjconf, i_id, o_id, count, false /* is_gid */ ,
true /* is_newidmap */ ) == false) {
true /* is_newidmap */ )
== false) {
return false;
}
}
@ -618,12 +621,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt,
size_t count = (cnt == NULL || strlen(cnt) == 0)
? 1U : (size_t) strtoull(cnt,
NULL,
0);
if (userParseId(nsjconf, i_id, o_id, count, true /* is_gid */ ,
true /* is_newidmap */ ) == false) {
true /* is_newidmap */ )
== false) {
return false;
}
}

View File

@ -48,9 +48,9 @@ static void __attribute__ ((unused)) __clang_cleanup_func(void (^*dfunc) (void))
#else
#define __block
#define _DEFER(a, count) \
auto void _STRMERGE(__defer_f_, count)(void *_defer_arg __attribute__((unused))); \
auto void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused))); \
int _STRMERGE(__defer_var_, count) __attribute__((cleanup(_STRMERGE(__defer_f_, count)))) __attribute__((unused)); \
void _STRMERGE(__defer_f_, count)(void *_defer_arg __attribute__((unused)))
void _STRMERGE(__defer_f_, count)(void* _defer_arg __attribute__((unused)))
#define defer _DEFER(a, __COUNTER__)
#endif
#endif
@ -61,7 +61,8 @@ struct pids_t {
char remote_txt[64];
struct sockaddr_in6 remote_addr;
int pid_syscall_fd;
TAILQ_ENTRY(pids_t) pointers;
TAILQ_ENTRY(pids_t)
pointers;
};
struct mounts_t {
@ -75,7 +76,8 @@ struct mounts_t {
bool isDir;
bool isSymlink;
bool mandatory;
TAILQ_ENTRY(mounts_t) pointers;
TAILQ_ENTRY(mounts_t)
pointers;
};
struct idmap_t {
@ -83,12 +85,14 @@ struct idmap_t {
uid_t outside_id;
size_t count;
bool is_newidmap;
TAILQ_ENTRY(idmap_t) pointers;
TAILQ_ENTRY(idmap_t)
pointers;
};
struct ints_t {
int val;
TAILQ_ENTRY(ints_t) pointers;
TAILQ_ENTRY(ints_t)
pointers;
};
enum ns_mode_t {
@ -100,7 +104,8 @@ enum ns_mode_t {
struct charptr_t {
char *val;
TAILQ_ENTRY(charptr_t) pointers;
TAILQ_ENTRY(charptr_t)
pointers;
};
enum llevel_t {
@ -167,13 +172,20 @@ struct nsjconf_t {
char *kafel_string;
uid_t orig_euid;
long num_cpus;
TAILQ_HEAD(udmaplist, idmap_t) uids;
TAILQ_HEAD(gdmaplist, idmap_t) gids;
TAILQ_HEAD(envlist, charptr_t) envs;
TAILQ_HEAD(pidslist, pids_t) pids;
TAILQ_HEAD(mountptslist, mounts_t) mountpts;
TAILQ_HEAD(fdslistt, ints_t) open_fds;
TAILQ_HEAD(capslistt, ints_t) caps;
TAILQ_HEAD(udmaplist, idmap_t)
uids;
TAILQ_HEAD(gdmaplist, idmap_t)
gids;
TAILQ_HEAD(envlist, charptr_t)
envs;
TAILQ_HEAD(pidslist, pids_t)
pids;
TAILQ_HEAD(mountptslist, mounts_t)
mountpts;
TAILQ_HEAD(fdslistt, ints_t)
open_fds;
TAILQ_HEAD(capslistt, ints_t)
caps;
};
#endif /* NS_COMMON_H */

293
config.c
View File

@ -1,293 +0,0 @@
/*
nsjail - config parsing
-----------------------------------------
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "common.h"
#include <stdio.h>
#include <sys/mount.h>
#include <sys/personality.h>
#include "caps.h"
#include "config.h"
#include "log.h"
#include "mount.h"
#include "user.h"
#include "util.h"
#if !defined(NSJAIL_WITH_PROTOBUF)
bool configParse(struct nsjconf_t * nsjconf UNUSED, const char *file UNUSED)
{
LOG_W("nsjail was not compiled with the protobuf-c library");
return false;
}
#else /* !defined(NSJAIL_WITH_PROTOBUF) */
#include "config.pb-c.h"
#include "protobuf-c-text.h"
static bool configParseInternal(struct nsjconf_t *nsjconf, Nsjail__NsJailConfig * njc)
{
switch (njc->mode) {
case NSJAIL__MODE__LISTEN:
nsjconf->mode = MODE_LISTEN_TCP;
break;
case NSJAIL__MODE__ONCE:
nsjconf->mode = MODE_STANDALONE_ONCE;
break;
case NSJAIL__MODE__RERUN:
nsjconf->mode = MODE_STANDALONE_RERUN;
break;
case NSJAIL__MODE__EXECVE:
nsjconf->mode = MODE_STANDALONE_EXECVE;
break;
default:
LOG_E("Uknown running mode: %d", njc->mode);
return false;
}
nsjconf->chroot = utilStrDup(njc->chroot_dir);
nsjconf->is_root_rw = njc->is_root_rw;
nsjconf->hostname = utilStrDup(njc->hostname);
nsjconf->cwd = utilStrDup(njc->cwd);
nsjconf->port = njc->port;
nsjconf->bindhost = utilStrDup(njc->bindhost);
nsjconf->max_conns_per_ip = njc->max_conns_per_ip;
nsjconf->tlimit = njc->time_limit;
nsjconf->max_cpus = njc->max_cpus;
nsjconf->daemonize = njc->daemon;
if (njc->has_log_fd) {
nsjconf->log_fd = njc->log_fd;
}
nsjconf->logfile = utilStrDup(njc->log_file);
if (njc->has_log_level) {
switch (njc->log_level) {
case NSJAIL__LOG_LEVEL__DEBUG:
nsjconf->loglevel = DEBUG;
break;
case NSJAIL__LOG_LEVEL__INFO:
nsjconf->loglevel = INFO;
break;
case NSJAIL__LOG_LEVEL__WARNING:
nsjconf->loglevel = WARNING;
break;
case NSJAIL__LOG_LEVEL__ERROR:
nsjconf->loglevel = ERROR;
break;
case NSJAIL__LOG_LEVEL__FATAL:
nsjconf->loglevel = FATAL;
break;
default:
LOG_E("Unknown log_level: %d", njc->log_level);
return false;
}
}
if (njc->has_log_fd || njc->log_file || njc->has_log_level) {
if (logInitLogFile(nsjconf) == false) {
return false;
}
}
nsjconf->keep_env = njc->keep_env;
for (size_t i = 0; i < njc->n_envar; i++) {
struct charptr_t *p = utilMalloc(sizeof(struct charptr_t));
p->val = utilStrDup(njc->envar[i]);
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
}
nsjconf->keep_caps = njc->keep_caps;
for (size_t i = 0; i < njc->n_cap; i++) {
struct ints_t *f = utilMalloc(sizeof(struct ints_t));
f->val = capsNameToVal(njc->cap[i]);
if (f->val == -1) {
return false;
}
TAILQ_INSERT_HEAD(&nsjconf->caps, f, pointers);
}
nsjconf->is_silent = njc->silent;
nsjconf->skip_setsid = njc->skip_setsid;
for (size_t i = 0; i < njc->n_pass_fd; i++) {
struct ints_t *f = utilMalloc(sizeof(struct ints_t));
f->val = njc->pass_fd[i];
TAILQ_INSERT_HEAD(&nsjconf->open_fds, f, pointers);
}
nsjconf->disable_no_new_privs = njc->disable_no_new_privs;
nsjconf->rl_as = njc->rlimit_as * 1024ULL * 1024ULL;
nsjconf->rl_core = njc->rlimit_core * 1024ULL * 1024ULL;
nsjconf->rl_cpu = njc->rlimit_cpu;
nsjconf->rl_fsize = njc->rlimit_fsize * 1024ULL * 1024ULL;
nsjconf->rl_nofile = njc->rlimit_nofile;
if (njc->has_rlimit_nproc) {
nsjconf->rl_nproc = njc->rlimit_nproc;
}
if (njc->has_rlimit_stack) {
nsjconf->rl_stack = njc->rlimit_stack * 1024ULL * 1024ULL;
}
if (njc->persona_addr_compat_layout) {
nsjconf->personality |= ADDR_COMPAT_LAYOUT;
}
if (njc->persona_mmap_page_zero) {
nsjconf->personality |= MMAP_PAGE_ZERO;
}
if (njc->persona_read_implies_exec) {
nsjconf->personality |= READ_IMPLIES_EXEC;
}
if (njc->persona_addr_limit_3gb) {
nsjconf->personality |= ADDR_LIMIT_3GB;
}
if (njc->persona_addr_no_randomize) {
nsjconf->personality |= ADDR_NO_RANDOMIZE;
}
nsjconf->clone_newnet = njc->clone_newnet;
nsjconf->clone_newuser = njc->clone_newuser;
nsjconf->clone_newns = njc->clone_newns;
nsjconf->clone_newpid = njc->clone_newpid;
nsjconf->clone_newipc = njc->clone_newipc;
nsjconf->clone_newuts = njc->clone_newuts;
nsjconf->clone_newcgroup = njc->clone_newcgroup;
for (size_t i = 0; i < njc->n_uidmap; i++) {
if (userParseId
(nsjconf, njc->uidmap[i]->inside_id, njc->uidmap[i]->outside_id,
njc->uidmap[i]->count, false /* is_gid */ ,
njc->uidmap[i]->use_newidmap) == false) {
return false;
}
}
for (size_t i = 0; i < njc->n_gidmap; i++) {
if (userParseId
(nsjconf, njc->gidmap[i]->inside_id, njc->gidmap[i]->outside_id,
njc->gidmap[i]->count, true /* is_gid */ ,
njc->gidmap[i]->use_newidmap) == false) {
return false;
}
}
nsjconf->mount_proc = njc->mount_proc;
for (size_t i = 0; i < njc->n_mount; i++) {
const char *src = njc->mount[i]->src;
const char *src_env = njc->mount[i]->prefix_src_env;
const char *dst = njc->mount[i]->dst;
const char *dst_env = njc->mount[i]->prefix_dst_env;
const char *fstype = njc->mount[i]->fstype;
const char *options = njc->mount[i]->options;
uintptr_t flags = (njc->mount[i]->rw == false) ? MS_RDONLY : 0;
flags |= njc->mount[i]->is_bind ? (MS_BIND | MS_REC) : 0;
bool mandatory = njc->mount[i]->mandatory;
const bool *isDir =
(njc->mount[i]->has_is_dir) ? (const bool *)&njc->mount[i]->is_dir : NULL;
uint8_t *src_content = NULL;
size_t src_content_len = 0;
if (njc->mount[i]->has_src_content) {
src_content = njc->mount[i]->src_content.data;
src_content_len = njc->mount[i]->src_content.len;
}
if (mountAddMountPt
(nsjconf, src, dst, fstype, options, flags, isDir, mandatory, src_env,
dst_env, src_content, src_content_len, njc->mount[i]->is_symlink) == false) {
LOG_E("Couldn't add mountpoint for src:'%s' dst:'%s'", src, dst);
return false;
}
}
if (njc->seccomp_policy_file) {
if ((nsjconf->kafel_file = fopen(njc->seccomp_policy_file, "rb")) == NULL) {
PLOG_W("Couldn't open file with seccomp policy '%s'",
njc->seccomp_policy_file);
return false;
}
}
nsjconf->kafel_string = utilStrDup(njc->seccomp_string);
nsjconf->cgroup_mem_max = njc->cgroup_mem_max;
nsjconf->cgroup_mem_mount = utilStrDup(njc->cgroup_mem_mount);
nsjconf->cgroup_mem_parent = utilStrDup(njc->cgroup_mem_parent);
nsjconf->cgroup_pids_max = njc->cgroup_pids_max;
nsjconf->cgroup_pids_mount = utilStrDup(njc->cgroup_pids_mount);
nsjconf->cgroup_pids_parent = utilStrDup(njc->cgroup_pids_parent);
nsjconf->iface_no_lo = njc->iface_no_lo;
nsjconf->iface_vs = utilStrDup(njc->macvlan_iface);
nsjconf->iface_vs_ip = utilStrDup(njc->macvlan_vs_ip);
nsjconf->iface_vs_nm = utilStrDup(njc->macvlan_vs_nm);
nsjconf->iface_vs_gw = utilStrDup(njc->macvlan_vs_gw);
if (njc->exec_bin) {
char **argv = utilCalloc(sizeof(const char *) * (njc->exec_bin->n_arg + 2));
if (njc->exec_bin->arg0) {
argv[0] = utilStrDup(njc->exec_bin->arg0);
} else {
argv[0] = utilStrDup(njc->exec_bin->path);
}
for (size_t i = 0; i < njc->exec_bin->n_arg; i++) {
argv[i + 1] = utilStrDup(njc->exec_bin->arg[i]);
}
argv[njc->exec_bin->n_arg + 1] = NULL;
nsjconf->exec_file = utilStrDup(njc->exec_bin->path);
nsjconf->argv = argv;
}
return true;
}
bool configParse(struct nsjconf_t * nsjconf, const char *file)
{
LOG_I("Parsing configuration from '%s'", file);
FILE *f = fopen(file, "rb");
if (f == NULL) {
PLOG_W("Couldn't open '%s' for reading", file);
return false;
}
ProtobufCTextError error;
Nsjail__NsJailConfig *njc =
(Nsjail__NsJailConfig *) protobuf_c_text_from_file(&nsjail__ns_jail_config__descriptor,
f, &error, NULL);
if (njc == NULL) {
LOG_W("Couldn't parse config from '%s': %s", file, error.error_txt);
fclose(f);
return false;
}
bool ret = configParseInternal(nsjconf, njc);
char *config_str = protobuf_c_text_to_string((ProtobufCMessage *) njc, NULL);
if (config_str) {
LOG_D("Parsed config:\n%s", config_str);
free(config_str);
}
fclose(f);
return ret;
}
#endif /* !defined(NSJAIL_WITH_PROTOBUF) */

326
config.cc Normal file
View File

@ -0,0 +1,326 @@
/*
nsjail - config parsing
-----------------------------------------
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
extern "C" {
#include "common.h"
#include <fcntl.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/personality.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "caps.h"
#include "config.h"
#include "log.h"
#include "mount.h"
#include "user.h"
#include "util.h"
}
#include <fstream>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include <string>
#include "config.pb.h"
static bool configParseInternal(struct nsjconf_t* nsjconf,
const nsjail::NsJailConfig& njc)
{
switch (njc.mode()) {
case nsjail::Mode::LISTEN:
nsjconf->mode = MODE_LISTEN_TCP;
break;
case nsjail::Mode::ONCE:
nsjconf->mode = MODE_STANDALONE_ONCE;
break;
case nsjail::Mode::RERUN:
nsjconf->mode = MODE_STANDALONE_RERUN;
break;
case nsjail::Mode::EXECVE:
nsjconf->mode = MODE_STANDALONE_EXECVE;
break;
default:
LOG_E("Uknown running mode: %d", njc.mode());
return false;
}
nsjconf->chroot = njc.has_chroot_dir() ? utilStrDup(njc.chroot_dir().c_str()) : NULL;
nsjconf->is_root_rw = njc.is_root_rw();
nsjconf->hostname = njc.has_hostname() ? utilStrDup(njc.hostname().c_str()) : NULL;
nsjconf->cwd = njc.has_cwd() ? utilStrDup(njc.cwd().c_str()) : NULL;
nsjconf->port = njc.port();
nsjconf->bindhost = njc.has_bindhost() ? utilStrDup(njc.bindhost().c_str()) : NULL;
nsjconf->max_conns_per_ip = njc.max_conns_per_ip();
nsjconf->tlimit = njc.time_limit();
nsjconf->max_cpus = njc.max_cpus();
nsjconf->daemonize = njc.daemon();
if (njc.has_log_fd()) {
nsjconf->log_fd = njc.log_fd();
}
nsjconf->logfile = njc.has_log_file() ? utilStrDup(njc.log_file().c_str()) : NULL;
if (njc.has_log_level()) {
switch (njc.log_level()) {
case nsjail::LogLevel::DEBUG:
nsjconf->loglevel = DEBUG;
break;
case nsjail::LogLevel::INFO:
nsjconf->loglevel = INFO;
break;
case nsjail::LogLevel::WARNING:
nsjconf->loglevel = WARNING;
break;
case nsjail::LogLevel::ERROR:
nsjconf->loglevel = ERROR;
break;
case nsjail::LogLevel::FATAL:
nsjconf->loglevel = FATAL;
break;
default:
LOG_E("Unknown log_level: %d", njc.log_level());
return false;
}
}
if (njc.has_log_fd() || njc.has_log_file() || njc.has_log_level()) {
if (logInitLogFile(nsjconf) == false) {
return false;
}
}
nsjconf->keep_env = njc.keep_env();
for (ssize_t i = 0; i < njc.envar_size(); i++) {
struct charptr_t* p = reinterpret_cast<charptr_t*>(utilMalloc(sizeof(struct charptr_t)));
p->val = utilStrDup(njc.envar(i).c_str());
TAILQ_INSERT_TAIL(&nsjconf->envs, p, pointers);
}
nsjconf->keep_caps = njc.keep_caps();
for (ssize_t i = 0; i < njc.cap_size(); i++) {
struct ints_t* f = reinterpret_cast<struct ints_t*>(utilMalloc(sizeof(struct ints_t)));
f->val = capsNameToVal(njc.cap(i).c_str());
if (f->val == -1) {
return false;
}
TAILQ_INSERT_HEAD(&nsjconf->caps, f, pointers);
}
nsjconf->is_silent = njc.silent();
nsjconf->skip_setsid = njc.skip_setsid();
for (ssize_t i = 0; i < njc.pass_fd_size(); i++) {
struct ints_t* f = reinterpret_cast<struct ints_t*>(utilMalloc(sizeof(struct ints_t)));
f->val = njc.pass_fd(i);
TAILQ_INSERT_HEAD(&nsjconf->open_fds, f, pointers);
}
nsjconf->disable_no_new_privs = njc.disable_no_new_privs();
nsjconf->rl_as = njc.rlimit_as() * 1024ULL * 1024ULL;
nsjconf->rl_core = njc.rlimit_core() * 1024ULL * 1024ULL;
nsjconf->rl_cpu = njc.rlimit_cpu();
nsjconf->rl_fsize = njc.rlimit_fsize() * 1024ULL * 1024ULL;
nsjconf->rl_nofile = njc.rlimit_nofile();
if (njc.has_rlimit_nproc()) {
nsjconf->rl_nproc = njc.rlimit_nproc();
}
if (njc.has_rlimit_stack()) {
nsjconf->rl_stack = njc.rlimit_stack() * 1024ULL * 1024ULL;
}
if (njc.persona_addr_compat_layout()) {
nsjconf->personality |= ADDR_COMPAT_LAYOUT;
}
if (njc.persona_mmap_page_zero()) {
nsjconf->personality |= MMAP_PAGE_ZERO;
}
if (njc.persona_read_implies_exec()) {
nsjconf->personality |= READ_IMPLIES_EXEC;
}
if (njc.persona_addr_limit_3gb()) {
nsjconf->personality |= ADDR_LIMIT_3GB;
}
if (njc.persona_addr_no_randomize()) {
nsjconf->personality |= ADDR_NO_RANDOMIZE;
}
nsjconf->clone_newnet = njc.clone_newnet();
nsjconf->clone_newuser = njc.clone_newuser();
nsjconf->clone_newns = njc.clone_newns();
nsjconf->clone_newpid = njc.clone_newpid();
nsjconf->clone_newipc = njc.clone_newipc();
nsjconf->clone_newuts = njc.clone_newuts();
nsjconf->clone_newcgroup = njc.clone_newcgroup();
for (ssize_t i = 0; i < njc.uidmap_size(); i++) {
if (userParseId(
nsjconf,
njc.uidmap(i).has_inside_id() ? njc.uidmap(i).inside_id().c_str()
: NULL,
njc.uidmap(i).has_outside_id() ? njc.uidmap(i).outside_id().c_str()
: NULL,
njc.uidmap(i).count(), false /* is_gid */,
njc.uidmap(i).use_newidmap())
== false) {
return false;
}
}
for (ssize_t i = 0; i < njc.gidmap_size(); i++) {
if (userParseId(
nsjconf,
njc.gidmap(i).has_inside_id() ? njc.gidmap(i).inside_id().c_str()
: NULL,
njc.gidmap(i).has_outside_id() ? njc.gidmap(i).outside_id().c_str()
: NULL,
njc.gidmap(i).count(), true /* is_gid */,
njc.gidmap(i).use_newidmap())
== false) {
return false;
}
}
nsjconf->mount_proc = njc.mount_proc();
for (ssize_t i = 0; i < njc.mount_size(); i++) {
const char* src = (njc.mount(i).has_src()) ? njc.mount(i).src().c_str() : NULL;
const char* src_env = (njc.mount(i).has_prefix_src_env()) ? njc.mount(i).prefix_src_env().c_str() : NULL;
const char* dst = (njc.mount(i).has_dst()) ? njc.mount(i).dst().c_str() : NULL;
const char* dst_env = (njc.mount(i).has_prefix_dst_env()) ? njc.mount(i).prefix_dst_env().c_str() : NULL;
const char* fstype = (njc.mount(i).has_fstype()) ? njc.mount(i).fstype().c_str() : NULL;
const char* options = (njc.mount(i).has_options()) ? njc.mount(i).options().c_str() : NULL;
uintptr_t flags = (njc.mount(i).rw() == false) ? MS_RDONLY : 0;
flags |= njc.mount(i).is_bind() ? (MS_BIND | MS_REC) : 0;
bool mandatory = njc.mount(i).mandatory();
const bool isDir = (njc.mount(i).has_is_dir() && njc.mount(i).is_dir()) ? true : false;
const bool* isDirPtr = (njc.mount(i).has_is_dir()) ? &isDir : NULL;
const char* src_content = NULL;
size_t src_content_len = 0;
if (njc.mount(i).has_src_content()) {
src_content = njc.mount(i).src_content().data();
src_content_len = njc.mount(i).src_content().size();
}
if (mountAddMountPt(nsjconf, src, dst, fstype, options, flags, isDirPtr,
mandatory, src_env, dst_env, src_content,
src_content_len, njc.mount(i).is_symlink())
== false) {
LOG_E("Couldn't add mountpoint for src:'%s' dst:'%s'", src, dst);
return false;
}
}
if (njc.has_seccomp_policy_file()) {
if ((nsjconf->kafel_file = fopen(njc.seccomp_policy_file().c_str(), "rb")) == NULL) {
PLOG_W("Couldn't open file with seccomp policy '%s'",
njc.seccomp_policy_file().c_str());
return false;
}
}
std::string kafel_string;
for (ssize_t i = 0; i < njc.seccomp_string().size(); i++) {
kafel_string += njc.seccomp_string(i);
}
nsjconf->kafel_string = njc.seccomp_string().size() > 0
? utilStrDup(kafel_string.c_str())
: NULL;
nsjconf->cgroup_mem_max = njc.cgroup_mem_max();
nsjconf->cgroup_mem_mount = njc.has_cgroup_mem_mount()
? utilStrDup(njc.cgroup_mem_mount().c_str())
: NULL;
nsjconf->cgroup_mem_parent = njc.has_cgroup_mem_parent()
? utilStrDup(njc.cgroup_mem_parent().c_str())
: NULL;
nsjconf->cgroup_pids_max = njc.cgroup_pids_max();
nsjconf->cgroup_pids_mount = njc.has_cgroup_pids_mount()
? utilStrDup(njc.cgroup_pids_mount().c_str())
: NULL;
nsjconf->cgroup_pids_parent = njc.has_cgroup_pids_parent()
? utilStrDup(njc.cgroup_pids_parent().c_str())
: NULL;
nsjconf->iface_no_lo = njc.iface_no_lo();
nsjconf->iface_vs = njc.has_macvlan_iface() ? utilStrDup(njc.macvlan_iface().c_str()) : NULL;
nsjconf->iface_vs_ip = njc.has_macvlan_vs_ip() ? utilStrDup(njc.macvlan_vs_ip().c_str()) : NULL;
nsjconf->iface_vs_nm = njc.has_macvlan_vs_nm() ? utilStrDup(njc.macvlan_vs_nm().c_str()) : NULL;
nsjconf->iface_vs_gw = njc.has_macvlan_vs_gw() ? utilStrDup(njc.macvlan_vs_gw().c_str()) : NULL;
if (njc.has_exec_bin()) {
char** argv = reinterpret_cast<char**>(utilCalloc(sizeof(const char*) * (njc.exec_bin().arg().size() + 2)));
if (njc.exec_bin().has_arg0()) {
argv[0] = utilStrDup(njc.exec_bin().arg0().c_str());
} else {
argv[0] = utilStrDup(njc.exec_bin().path().c_str());
}
for (ssize_t i = 0; i < njc.exec_bin().arg().size(); i++) {
argv[i + 1] = utilStrDup(njc.exec_bin().arg(i).c_str());
}
argv[njc.exec_bin().arg().size() + 1] = NULL;
nsjconf->exec_file = njc.exec_bin().has_path()
? utilStrDup(njc.exec_bin().path().c_str())
: NULL;
nsjconf->argv = argv;
}
return true;
}
static void LogHandler(google::protobuf::LogLevel level, const char* filename, int line, const std::string& message)
{
LOG_W("config.cc: '%s'", message.c_str());
}
extern "C" bool configParse(struct nsjconf_t* nsjconf, const char* file)
{
LOG_I("Parsing configuration from '%s'", file);
int fd = open(file, O_RDONLY);
if (fd == -1) {
PLOG_W("Couldn't open config file '%s'", file);
return false;
}
SetLogHandler(LogHandler);
google::protobuf::io::FileInputStream input(fd);
input.SetCloseOnDelete(true);
nsjail::NsJailConfig nsc;
auto parser = google::protobuf::TextFormat::Parser();
if (!parser.Parse(&input, &nsc)) {
LOG_W("Couldn't parse file '%s' from Text into ProtoBuf", file);
return false;
}
if (!configParseInternal(nsjconf, nsc)) {
LOG_W("Couldn't parse the ProtoBuf");
return false;
}
LOG_D("Parsed config:\n'%s'", nsc.DebugString().c_str());
return true;
}

View File

@ -22,8 +22,14 @@
#ifndef NS_CONFIG_H
#define NS_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h"
bool configParse(struct nsjconf_t *nsjconf, const char *file);
bool configParse(struct nsjconf_t *nsjconf, const char *file);
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* NS_CONFIG_H */

View File

@ -19,12 +19,12 @@ enum LogLevel {
message IdMap
{
/* Empty string means "current uid/gid" */
required string inside_id = 1 [ default = "" ];
required string outside_id = 2 [ default = "" ];
optional string inside_id = 1 [ default = "" ];
optional string outside_id = 2 [ default = "" ];
/* See 'man user_namespaces' for the meaning of count */
required uint32 count = 3 [ default = 1 ];
optional uint32 count = 3 [ default = 1 ];
/* Does this map use /usr/bin/new[u|g]idmap binary? */
required bool use_newidmap = 4 [ default = false ];
optional bool use_newidmap = 4 [ default = false ];
}
message MountPt
{
@ -41,18 +41,18 @@ message MountPt
/* Can be empty for mount --bind mounts */
optional string fstype = 6 [ default = "" ];
/* E.g. size=5000000 for 'tmpfs' */
required string options = 7 [ default = "" ];
optional string options = 7 [ default = "" ];
/* Is it 'mount --bind src dst' type of mount */
required bool is_bind = 8 [ default = false ];
optional bool is_bind = 8 [ default = false ];
/* It it R/W mount */
required bool rw = 9 [ default = false ];
optional bool rw = 9 [ default = false ];
/* Is it directory? If not specified an internal
heuristics will be used to determine that */
optional bool is_dir = 10;
/* Should the sandboxing fail if we cannot mount this resource? */
required bool mandatory = 11 [ default = true ];
optional bool mandatory = 11 [ default = true ];
/* Is it a symlink (instead of real mount point)? */
required bool is_symlink = 12 [ default = false ];
optional bool is_symlink = 12 [ default = false ];
}
message Exe
{
@ -67,32 +67,32 @@ message NsJailConfig
{
/* Optional name and description for this config */
optional string name = 1 [ default = "" ];
optional string description = 2 [ default = "" ];
repeated string description = 2;
/* Execution mode: see 'msg Mode' description for more */
required Mode mode = 3 [ default = ONCE ];
optional Mode mode = 3 [ default = ONCE ];
/* Equivalent to a bind mount with dst='/' */
optional string chroot_dir = 4;
/* Applies both to the chroot_dir and to /proc mounts */
required bool is_root_rw = 5 [ default = false ];
optional bool is_root_rw = 5 [ default = false ];
/* Hostname inside jail */
required string hostname = 8 [ default = "NSJAIL" ];
optional string hostname = 8 [ default = "NSJAIL" ];
/* Initial current working directory for the binary */
required string cwd = 9 [ default = "/" ];
optional string cwd = 9 [ default = "/" ];
/* TCP port to listen to. Valid with mode=LISTEN only */
required uint32 port = 10 [ default = 0 ];
optional uint32 port = 10 [ default = 0 ];
/* Host to bind to for mode=LISTEN. Must be in IPv6 format */
required string bindhost = 11 [ default = "::" ];
optional string bindhost = 11 [ default = "::" ];
/* For mode=LISTEN, maximum number of connections from a single IP */
required uint32 max_conns_per_ip = 12 [ default = 0 ];
optional uint32 max_conns_per_ip = 12 [ default = 0 ];
/* Wall-time time limit for commands */
required uint32 time_limit = 13 [ default = 600 ];
optional uint32 time_limit = 13 [ default = 600 ];
/* Should nsjail go into background? */
required bool daemon = 14 [ default = false ];
optional bool daemon = 14 [ default = false ];
/* Maximum number of CPUs to use: 0 - no limit */
required uint32 max_cpus = 15;
optional uint32 max_cpus = 15 [ default = 0 ];
/* FD to log to. */
optional int32 log_fd = 16;
@ -104,52 +104,52 @@ message NsJailConfig
/* Should the current environment variables be kept
when executing the binary */
required bool keep_env = 19 [ default = false ];
optional bool keep_env = 19 [ default = false ];
/* EnvVars to be set before executing binaries */
repeated string envar = 20;
/* Should capabilities be preserved or dropped */
required bool keep_caps = 21 [ default = false ];
optional bool keep_caps = 21 [ default = false ];
/* Which capabilities should be preserved if keep_caps == false.
Format: "CAP_SYS_PTRACE" */
repeated string cap = 63;
/* Should nsjail close FD=0,1,2 before executing the process */
required bool silent = 22 [ default = false ];
optional bool silent = 22 [ default = false ];
/* Should the child process have control over terminal?
Can be useful to allow /bin/sh to provide
job control / signals */
required bool skip_setsid = 23 [ default = false ];
optional bool skip_setsid = 23 [ default = false ];
/* Which FDs should be passed to the newly executed process
By default only FD=0,1,2 are passed */
repeated int32 pass_fd = 24;
/* Setting it to true will allow to have set-uid binaries
inside the jail */
required bool disable_no_new_privs = 25 [ default = false ];
optional bool disable_no_new_privs = 25 [ default = false ];
required uint64 rlimit_as = 26 [ default = 512 ]; /* In MiB */
required uint64 rlimit_core = 27 [ default = 0 ]; /* In MiB */
required uint64 rlimit_cpu = 28 [ default = 600 ]; /* In seconds */
required uint64 rlimit_fsize = 29 [ default = 1 ]; /* In MiB */
required uint64 rlimit_nofile = 30 [ default = 32 ];
optional uint64 rlimit_as = 26 [ default = 512 ]; /* In MiB */
optional uint64 rlimit_core = 27 [ default = 0 ]; /* In MiB */
optional uint64 rlimit_cpu = 28 [ default = 600 ]; /* In seconds */
optional uint64 rlimit_fsize = 29 [ default = 1 ]; /* In MiB */
optional uint64 rlimit_nofile = 30 [ default = 32 ];
optional uint64 rlimit_nproc = 31; /* This is system-wide: tricky to use */
optional uint64 rlimit_stack = 32; /* In MiB */
/* See 'man personality' for more */
required bool persona_addr_compat_layout = 33 [ default = false ];
required bool persona_mmap_page_zero = 34 [ default = false ];
required bool persona_read_implies_exec = 35 [ default = false ];
required bool persona_addr_limit_3gb = 36 [ default = false ];
required bool persona_addr_no_randomize = 37 [ default = false ];
optional bool persona_addr_compat_layout = 33 [ default = false ];
optional bool persona_mmap_page_zero = 34 [ default = false ];
optional bool persona_read_implies_exec = 35 [ default = false ];
optional bool persona_addr_limit_3gb = 36 [ default = false ];
optional bool persona_addr_no_randomize = 37 [ default = false ];
/* Which name-spaces should be used? */
required bool clone_newnet = 38 [ default = true ];
required bool clone_newuser = 39 [ default = true ];
required bool clone_newns = 40 [ default = true ];
required bool clone_newpid = 41 [ default = true ];
required bool clone_newipc = 42 [ default = true ];
required bool clone_newuts = 43 [ default = true ];
optional bool clone_newnet = 38 [ default = true ];
optional bool clone_newuser = 39 [ default = true ];
optional bool clone_newns = 40 [ default = true ];
optional bool clone_newpid = 41 [ default = true ];
optional bool clone_newipc = 42 [ default = true ];
optional bool clone_newuts = 43 [ default = true ];
/* It's only supported in newer kernels, hence disabled by default */
required bool clone_newcgroup = 44 [ default = false ];
optional bool clone_newcgroup = 44 [ default = false ];
/* Mappings for UIDs and GIDs. See the description for 'msg IdMap'
for more */
@ -158,7 +158,7 @@ message NsJailConfig
/* Should /proc be mounted (R/O)? This can also be added in the 'mount'
section below */
required bool mount_proc = 47 [ default = false ];
optional bool mount_proc = 47 [ default = false ];
/* Mount points inside the jail. See the description for 'msg MountPt'
for more */
repeated MountPt mount = 48;
@ -166,30 +166,30 @@ message NsJailConfig
/* Kafel seccomp-bpf policy file or a string:
Homepage of the project: https://github.com/google/kafel */
optional string seccomp_policy_file = 49;
optional string seccomp_string = 50;
repeated string seccomp_string = 50;
/* If > 0, maximum cumulative size of RAM used inside any jail */
required uint64 cgroup_mem_max = 51 [ default = 0 ]; /* In MiB */
optional uint64 cgroup_mem_max = 51 [ default = 0 ]; /* In MiB */
/* Mount point for cgroups-memory in your system */
required string cgroup_mem_mount = 52 [ default = "/sys/fs/cgroup/memory" ];
optional string cgroup_mem_mount = 52 [ default = "/sys/fs/cgroup/memory" ];
/* Writeable directory (for the nsjail user) under cgroup_mem_mount */
required string cgroup_mem_parent = 53 [ default = "NSJAIL" ];
optional string cgroup_mem_parent = 53 [ default = "NSJAIL" ];
/* If > 0, maximum number of PIDs (threads/processes) inside jail */
required uint64 cgroup_pids_max = 54 [ default = 0 ];
optional uint64 cgroup_pids_max = 54 [ default = 0 ];
/* Mount point for cgroups-pids in your system */
required string cgroup_pids_mount = 55 [ default = "/sys/fs/cgroup/pids" ];
optional string cgroup_pids_mount = 55 [ default = "/sys/fs/cgroup/pids" ];
/* Writeable directory (for the nsjail user) under cgroup_pids_mount */
required string cgroup_pids_parent = 56 [ default = "NSJAIL" ];
optional string cgroup_pids_parent = 56 [ default = "NSJAIL" ];
/* Should the 'lo' interface be brought up (active) inside this jail? */
required bool iface_no_lo = 57 [ default = false ];
optional bool iface_no_lo = 57 [ default = false ];
/* Parameters for the cloned MACVLAN interface inside jail */
optional string macvlan_iface = 58; /* Interface to be cloned, eg 'eth0' */
required string macvlan_vs_ip = 59 [ default = "192.168.0.2" ];
required string macvlan_vs_nm = 60 [ default = "255.255.255.0" ];
required string macvlan_vs_gw = 61 [ default = "192.168.0.1" ];
optional string macvlan_vs_ip = 59 [ default = "192.168.0.2" ];
optional string macvlan_vs_nm = 60 [ default = "255.255.255.0" ];
optional string macvlan_vs_gw = 61 [ default = "192.168.0.1" ];
/* Binary path (with arguments) to be executed. If not specified here, it
can be specified with cmd-line as "-- /path/to/command arg1 arg2" */

View File

@ -1,21 +1,15 @@
name: "apache-with-cloned-net"
description: "
Tested under Ubuntu 17.04. Other Linux distros might use different
locations for the Apache's HTTPD configuration files and system
libraries.
On the basis of (GitHub's) @farconada work in:
https://github.com/google/nsjail/issues/31
Run as: sudo ./nsjail --config configs/apache.cfg
"
description: "Tested under Ubuntu 17.04. Other Linux distros might "
description: "use different locations for the Apache's HTTPD configuration "
description: "files and system libraries"
description: "Run as: sudo ./nsjail --config configs/apache.cfg"
mode: ONCE
hostname: "APACHE-NSJ"
rlimit_as: 1024
rlimit_fsize: 1024
rlimit_cpu: -1
rlimit_cpu: 18446744073709551615
rlimit_nofile: 64
time_limit: 0
@ -123,16 +117,15 @@ mount {
is_bind: true
}
seccomp_string: "
POLICY example {
KILL {
ptrace,
process_vm_readv,
process_vm_writev
}
}
USE example DEFAULT ALLOW
"
seccomp_string: "seccomp_string: "
seccomp_string: " POLICY example {"
seccomp_string: " KILL {"
seccomp_string: " ptrace,"
seccomp_string: " process_vm_readv,"
seccomp_string: " process_vm_writev"
seccomp_string: " }"
seccomp_string: " }"
seccomp_string: " USE example DEFAULT ALLOW"
macvlan_iface: "enp0s31f6"
macvlan_vs_ip: "192.168.10.223"

View File

@ -1,13 +1,11 @@
name: "bash-with-fake-geteuid"
description:
"An example/demo policy which allows to execute /bin/bash and other commands in
a fairly restricted jail containing only some directories from the main
system, and with blocked __NR_syslog syscall. Also, __NR_geteuid returns -1337
value, which /usr/bin/id will show as euid=4294965959, and ptrace is blocked
but returns success, hence strange behavior of the strace command.
This is an example/demo policy, hence it repeats many default values from the
https://github.com/google/nsjail/blob/master/config.proto PB schema"
description: "An example/demo policy which allows to execute /bin/bash and other commands in "
description: "a fairly restricted jail containing only some directories from the main "
description: "system, and with blocked __NR_syslog syscall. Also, __NR_geteuid returns -1337 "
description: "value, which /usr/bin/id will show as euid=4294965959, and ptrace is blocked "
description: "but returns success, hence strange behavior of the strace command. "
description: "This is an example/demo policy, hence it repeats many default values from the "
description: "https://github.com/google/nsjail/blob/master/config.proto PB schema "
mode: ONCE
hostname: "JAILED-BASH"
@ -169,14 +167,13 @@ mount {
mandatory: false
}
seccomp_string: "
POLICY example {
ERRNO(1337) { geteuid },
KILL { syslog },
ERRNO(0) { ptrace }
}
USE example DEFAULT ALLOW
"
seccomp_string: "POLICY example { "
seccomp_string: " ERRNO(1337) { geteuid }, "
seccomp_string: " "
seccomp_string: " KILL { syslog }, "
seccomp_string: " ERRNO(0) { ptrace } "
seccomp_string: "} "
seccomp_string: "USE example DEFAULT ALLOW "
exec_bin {
path: "/bin/bash"

View File

@ -1,26 +1,25 @@
name: "chrome-with-net"
description: "
Don't use for anything serious - this is just a demo policy. See notes
at the end of this description for more.
This policy allows to run Chrome inside a jail. Access to networking is
permitted with this setup (clone_newnet: false).
The only permitted home directory is $HOME/.mozilla and $HOME/Documents.
The rest of available on the FS files/dires are libs and X-related files/dirs.
Run as:
./nsjail --config configs/chrome-with-net.cfg
You can then go to https://uploadfiles.io/ and try to upload a file in order
to see how your local directory (also, all system directories) look like.
Note: Using this profile for anything serious is *A VERY BAD* idea. Chrome
provides excellent FS&syscall sandbox for Linux, as this profile disables
this sandboxing with --no-sandbox and substitutes Chrome's syscall/ns policy
with more relaxed namespacing.
"
description: "Don't use for anything serious - this is just a demo policy. See notes"
description: "at the end of this description for more."
description: ""
description: "This policy allows to run Chrome inside a jail. Access to networking is"
description: "permitted with this setup (clone_newnet: false)."
description: ""
description: "The only permitted home directory is $HOME/.mozilla and $HOME/Documents."
description: "The rest of available on the FS files/dires are libs and X-related files/dirs."
description: ""
description: "Run as:"
description: ""
description: "./nsjail --config configs/chrome-with-net.cfg"
description: ""
description: "You can then go to https://uploadfiles.io/ and try to upload a file in order"
description: "to see how your local directory (also, all system directories) look like."
description: ""
description: "Note: Using this profile for anything serious is *A VERY BAD* idea. Chrome"
description: "provides excellent FS&syscall sandbox for Linux, as this profile disables"
description: "this sandboxing with --no-sandbox and substitutes Chrome's syscall/ns policy"
description: "with more relaxed namespacing."
mode: ONCE
hostname: "CHROME"
@ -166,16 +165,14 @@ mount {
is_bind: true
}
seccomp_string: "
POLICY example {
KILL {
ptrace,
process_vm_readv,
process_vm_writev
}
}
USE example DEFAULT ALLOW
"
seccomp_string: " POLICY example {"
seccomp_string: " KILL {"
seccomp_string: " ptrace,"
seccomp_string: " process_vm_readv,"
seccomp_string: " process_vm_writev"
seccomp_string: " }"
seccomp_string: " }"
seccomp_string: " USE example DEFAULT ALLOW"
exec_bin {
path: "/opt/google/chrome/google-chrome"

View File

@ -1,26 +1,25 @@
name: "firefox-with-cloned-net"
description: "
This policy allows to run firefox inside a jail on a separate eth interface.
A separate networking context separates process from the global \"lo\", and
from global abstract socket namespace.
The only permitted home directory is $HOME/.mozilla and $HOME/Documents.
The rest of available on the FS files/dires are libs and X-related files/dirs.
As this needs to be run as root, you will have to set-up correct uid&gid
mappings (here: 'jagger'), name of your local interface (here: 'enp0s31f6'),
and correct IPv4 addresses.
IPv6 should work out-of-the-box, given that your local IPv6 discovery is set
up correctly.
Run as:
sudo ./nsjail --config configs/firefox-with-cloned-net.cfg
You can then go to https://uploadfiles.io/ and try to upload a file in order
to see how your local directory (also, all system directories) look like.
"
description: "This policy allows to run firefox inside a jail on a separate eth interface."
description: "A separate networking context separates process from the global \"lo\", and"
description: "from global abstract socket namespace."
description: ""
description: "The only permitted home directory is $HOME/.mozilla and $HOME/Documents."
description: "The rest of available on the FS files/dires are libs and X-related files/dirs."
description: ""
description: "As this needs to be run as root, you will have to set-up correct uid&gid"
description: "mappings (here: 'jagger'), name of your local interface (here: 'enp0s31f6'),"
description: "and correct IPv4 addresses."
description: ""
description: "IPv6 should work out-of-the-box, given that your local IPv6 discovery is set"
description: "up correctly."
description: ""
description: "Run as:"
description: ""
description: "sudo ./nsjail --config configs/firefox-with-cloned-net.cfg"
description: ""
description: "You can then go to https://uploadfiles.io/ and try to upload a file in order"
description: "to see how your local directory (also, all system directories) look like."
mode: ONCE
hostname: "FF-MACVTAP"
@ -152,16 +151,14 @@ mount {
is_bind: true
}
seccomp_string: "
POLICY example {
KILL {
ptrace,
process_vm_readv,
process_vm_writev
}
}
USE example DEFAULT ALLOW
"
seccomp_string: " POLICY example {"
seccomp_string: " KILL {"
seccomp_string: " ptrace,"
seccomp_string: " process_vm_readv,"
seccomp_string: " process_vm_writev"
seccomp_string: " }"
seccomp_string: " }"
seccomp_string: " USE example DEFAULT ALLOW"
macvlan_iface: "enp0s31f6"
macvlan_vs_ip: "192.168.10.223"

View File

@ -1,18 +1,17 @@
name: "firefox-with-net"
description: "
This policy allows to run firefox inside a jail. Access to networking is
permitted with this setup (clone_newnet: false).
The only permitted home directory is $HOME/.mozilla and $HOME/Documents.
The rest of available on the FS files/dires are libs and X-related files/dirs.
Run as:
./nsjail --config configs/firefox-with-net.cfg
You can then go to https://uploadfiles.io/ and try to upload a file in order
to see how your local directory (also, all system directories) look like.
"
description: "This policy allows to run firefox inside a jail. Access to networking is"
description: "permitted with this setup (clone_newnet: false)."
description: ""
description: "The only permitted home directory is $HOME/.mozilla and $HOME/Documents."
description: "The rest of available on the FS files/dires are libs and X-related files/dirs."
description: ""
description: "Run as:"
description: ""
description: "./nsjail --config configs/firefox-with-net.cfg"
description: ""
description: "You can then go to https://uploadfiles.io/ and try to upload a file in order"
description: "to see how your local directory (also, all system directories) look like."
mode: ONCE
hostname: "FIREFOX"
@ -138,16 +137,14 @@ mount {
is_bind: true
}
seccomp_string: "
POLICY example {
KILL {
ptrace,
process_vm_readv,
process_vm_writev
}
}
USE example DEFAULT ALLOW
"
seccomp_string: " POLICY example {"
seccomp_string: " KILL {"
seccomp_string: " ptrace,"
seccomp_string: " process_vm_readv,"
seccomp_string: " process_vm_writev"
seccomp_string: " }"
seccomp_string: " }"
seccomp_string: " USE example DEFAULT ALLOW"
exec_bin {
path: "/usr/lib/firefox/firefox"

View File

@ -1,13 +1,12 @@
name: "documents-with-xorg"
description: "
This policy allows to run many X-org based tool, which are allowed
to access $HOME/Documents directory only. An example of use is:
./nsjail --config configs/documents-with-xorg.cfg -- \\
/usr/bin/geeqie /user/Documents/
What is more, this policy doesn't allow to access networking.
"
description: "This policy allows to run many X-org based tool, which are allowed"
description: "to access $HOME/Documents directory only. An example of use is:"
description: ""
description: "./nsjail --config configs/documents-with-xorg.cfg -- \\"
description: " /usr/bin/geeqie /user/Documents/"
description: ""
description: "What is more, this policy doesn't allow to access networking."
mode: ONCE
hostname: "NSJAIL"
@ -127,13 +126,11 @@ mount {
is_bind: true
}
seccomp_string: "
POLICY example {
KILL {
ptrace,
process_vm_readv,
process_vm_writev
}
}
USE example DEFAULT ALLOW
"
seccomp_string: " POLICY example {"
seccomp_string: " KILL {"
seccomp_string: " ptrace,"
seccomp_string: " process_vm_readv,"
seccomp_string: " process_vm_writev"
seccomp_string: " }"
seccomp_string: " }"
seccomp_string: " USE example DEFAULT ALLOW"

View File

@ -1,13 +1,12 @@
name: "imagemagick-convert"
description: "
This policy allows to run ImageMagick's convert inside a jail.
Your $HOME's Documents will be mapped as /user/Documents
Run as:
./nsjail --config imagemagick-convert.cfg -- /usr/bin/convert \\
jpg:/user/Documents/input.jpg png:/user/Documents/output.png
"
description: "This policy allows to run ImageMagick's convert inside a jail."
description: "Your $HOME's Documents will be mapped as /user/Documents"
description: ""
description: "Run as:"
description: ""
description: "./nsjail --config imagemagick-convert.cfg -- /usr/bin/convert \\"
description: " jpg:/user/Documents/input.jpg png:/user/Documents/output.png"
mode: ONCE
hostname: "IM-CONVERT"
@ -77,13 +76,11 @@ mount {
mandatory: false
}
seccomp_string: "
POLICY example {
KILL {
ptrace,
process_vm_readv,
process_vm_writev
}
}
USE example DEFAULT ALLOW
"
seccomp_string: " POLICY example {"
seccomp_string: " KILL {"
seccomp_string: " ptrace,"
seccomp_string: " process_vm_readv,"
seccomp_string: " process_vm_writev"
seccomp_string: " }"
seccomp_string: " }"
seccomp_string: " USE example DEFAULT ALLOW"

2
log.c
View File

@ -29,8 +29,8 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>

13
mount.c
View File

@ -25,8 +25,8 @@
#include <fcntl.h>
#include <linux/sched.h>
#include <sched.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
@ -40,10 +40,13 @@
#include "subproc.h"
#include "util.h"
#define VALSTR_STRUCT(x) { x, #x }
#define VALSTR_STRUCT(x) \
{ \
x, #x \
}
#if !defined(MS_LAZYTIME)
#define MS_LAZYTIME (1<<25)
#define MS_LAZYTIME (1 << 25)
#endif /* if !defined(MS_LAZYTIME) */
const char *mountFlagsToStr(uintptr_t flags)
@ -387,7 +390,7 @@ bool mountInitNs(struct nsjconf_t * nsjconf)
bool mountAddMountPt(struct nsjconf_t * nsjconf, const char *src, const char *dst,
const char *fstype, const char *options, uintptr_t flags, const bool * isDir,
bool mandatory, const char *src_env, const char *dst_env,
const uint8_t * src_content, size_t src_content_len, bool is_symlink)
const char *src_content, size_t src_content_len, bool is_symlink)
{
struct mounts_t *p = utilCalloc(sizeof(struct mounts_t));
@ -455,7 +458,7 @@ bool mountAddMountPt(struct nsjconf_t * nsjconf, const char *src, const char *ds
}
}
p->src_content = utilMemDup(src_content, src_content_len);
p->src_content = utilMemDup((const uint8_t *)src_content, src_content_len);
p->src_content_len = src_content_len;
TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers);

View File

@ -32,7 +32,7 @@ bool mountInitNs(struct nsjconf_t *nsjconf);
bool mountAddMountPt(struct nsjconf_t *nsjconf, const char *src, const char *dst,
const char *fstype, const char *options, uintptr_t flags, const bool * isDir,
bool mandatory, const char *src_env, const char *dst_env,
const uint8_t * src_content, size_t src_content_len, bool is_symlink);
const char *src_content, size_t src_content_len, bool is_symlink);
const char *mountDescribeMountPt(struct mounts_t *mpt);
#endif /* NS_MOUNT_H */

8
net.c
View File

@ -28,8 +28,8 @@
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <sched.h>
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
@ -171,9 +171,9 @@ bool netLimitConns(struct nsjconf_t * nsjconf, int connsock)
unsigned int cnt = 0;
struct pids_t *p;
TAILQ_FOREACH(p, &nsjconf->pids, pointers) {
if (memcmp
(addr.sin6_addr.s6_addr, p->remote_addr.sin6_addr.s6_addr,
sizeof(*p->remote_addr.sin6_addr.s6_addr)) == 0) {
if (memcmp(addr.sin6_addr.s6_addr, p->remote_addr.sin6_addr.s6_addr,
sizeof(*p->remote_addr.sin6_addr.s6_addr))
== 0) {
cnt++;
}
}

View File

@ -24,8 +24,8 @@
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>

@ -1 +0,0 @@
Subproject commit 198cfc0dbe159c75026600055f28e8b797bdac3b

View File

@ -29,8 +29,8 @@
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
@ -41,8 +41,8 @@
#include <time.h>
#include <unistd.h>
#include "common.h"
#include "cgroup.h"
#include "common.h"
#include "contain.h"
#include "log.h"
#include "net.h"
@ -52,7 +52,10 @@
static const char subprocDoneChar = 'D';
#define VALSTR_STRUCT(x) { x, #x }
#define VALSTR_STRUCT(x) \
{ \
x, #x \
}
#if !defined(CLONE_NEWCGROUP)
#define CLONE_NEWCGROUP 0x02000000

14
user.c
View File

@ -265,19 +265,17 @@ bool userInitNsFromChild(struct nsjconf_t * nsjconf)
}
LOG_D("setresgid(%d, %d, %d)", TAILQ_FIRST(&nsjconf->gids)->inside_id,
TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id);
if (syscall
(__NR_setresgid, TAILQ_FIRST(&nsjconf->gids)->inside_id,
TAILQ_FIRST(&nsjconf->gids)->inside_id,
TAILQ_FIRST(&nsjconf->gids)->inside_id) == -1) {
if (syscall(__NR_setresgid, TAILQ_FIRST(&nsjconf->gids)->inside_id,
TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id)
== -1) {
PLOG_E("setresgid(%u)", TAILQ_FIRST(&nsjconf->gids)->inside_id);
return false;
}
LOG_D("setresuid(%d, %d, %d)", TAILQ_FIRST(&nsjconf->uids)->inside_id,
TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id);
if (syscall
(__NR_setresuid, TAILQ_FIRST(&nsjconf->uids)->inside_id,
TAILQ_FIRST(&nsjconf->uids)->inside_id,
TAILQ_FIRST(&nsjconf->uids)->inside_id) == -1) {
if (syscall(__NR_setresuid, TAILQ_FIRST(&nsjconf->uids)->inside_id,
TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id)
== -1) {
PLOG_E("setresuid(%u)", TAILQ_FIRST(&nsjconf->uids)->inside_id);
return false;
}