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"] [submodule "kafel"]
path = kafel path = kafel
url = https://github.com/google/kafel.git 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 CC ?= gcc
CXX ?= g++
EXTRA_CFLAGS := $(CFLAGS) COMMON_FLAGS += -O2 -c \
CFLAGS += -O2 -c -std=gnu11 \
-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 \ -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 \
-Wformat -Wformat=2 -Wformat-security -fPIE \ -Wformat -Wformat=2 -Wformat-security -fPIE \
-Wno-format-nonliteral \ -Wno-format-nonliteral \
-Wall -Wextra -Werror \ -Wall -Wextra -Werror \
-Ikafel/include -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 BIN = nsjail
LIBS = kafel/libkafel.a 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 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
OBJS = $(SRCS:.c=.o) 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 ifdef DEBUG
CFLAGS += -g -ggdb -gdwarf-4 CFLAGS += -g -ggdb -gdwarf-4
CXXFLAGS += -g -ggdb -gdwarf-4
endif endif
USE_NL3 ?= yes USE_NL3 ?= yes
@ -48,58 +54,18 @@ ifeq ($(NL3_EXISTS), yes)
endif endif
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 .PHONY: all clear depend indent
.c.o: %.c .c.o: %.c
$(CC) $(CFLAGS) $< -o $@ $(CC) $(CFLAGS) $< -o $@
.cc.o: %.cc
$(CXX) $(CXXFLAGS) $< -o $@
all: $(PROTO_DEPS) $(BIN) 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) $(BIN): $(LIBS) $(OBJS)
$(CC) -o $(BIN) $(OBJS) $(LIBS) $(LDFLAGS) $(CXX) -o $(BIN) $(OBJS) $(LIBS) $(LDFLAGS)
kafel/libkafel.a: kafel/libkafel.a:
ifeq ("$(wildcard kafel/Makefile)","") ifeq ("$(wildcard kafel/Makefile)","")
@ -107,39 +73,27 @@ ifeq ("$(wildcard kafel/Makefile)","")
endif endif
$(MAKE) -C kafel $(MAKE) -C kafel
protobuf-c-text/protobuf-c-text/.libs/libprotobuf-c-text.a: $(PROTO_DEPS): $(SRCS_PB)
ifeq ("$(wildcard protobuf-c-text/configure)","") protoc --cpp_out=. $(SRCS_PB)
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
clean: clean:
$(RM) core Makefile.bak $(OBJS) $(BIN) $(PROTO_DEPS) $(RM) core Makefile.bak $(OBJS) $(BIN) $(PROTO_DEPS)
ifneq ("$(wildcard kafel/Makefile)","") ifneq ("$(wildcard kafel/Makefile)","")
$(MAKE) -C kafel clean $(MAKE) -C kafel clean
endif endif
ifneq ("$(wildcard protobuf-c-text/Makefile)","")
$(MAKE) -C protobuf-c-text clean
endif
depend: depend:
makedepend -Y -Ykafel/include -- -- $(SRCS) makedepend -Y -Ykafel/include -- -- $(SRCS_C) $(SRCS_CXX)
indent: indent:
clang-format --style=WebKit -i -sort-includes *.c *.h $(SRCS_CXX)
indent -linux -l100 -lc100 *.c *.h; rm -f *~ indent -linux -l100 -lc100 *.c *.h; rm -f *~
# DO NOT DELETE THIS LINE -- make depend depends on it. # 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 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 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 cmdline.o: cmdline.h common.h caps.h config.h log.h mount.h user.h util.h
config.o: 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: 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 contain.o: user.h util.h uts.h
log.o: log.h common.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 util.o: util.h common.h log.h
uts.o: uts.h common.h log.h uts.o: uts.h common.h log.h
cpu.o: cpu.h common.h log.h util.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 "caps.h"
#include <sys/capability.h>
#include <string.h> #include <string.h>
#include <sys/capability.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
@ -30,7 +30,10 @@
#include "log.h" #include "log.h"
#include "util.h" #include "util.h"
#define VALSTR_STRUCT(x) { x, #x } #define VALSTR_STRUCT(x) \
{ \
x, #x \
}
/* *INDENT-OFF* */ /* *INDENT-OFF* */
static struct { static struct {
@ -209,7 +212,8 @@ bool capsInitNs(struct nsjconf_t *nsjconf)
} }
if (prctl if (prctl
(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)capNames[i].val, (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)", PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)",
capNames[i].name); capNames[i].name);
} else { } else {
@ -219,9 +223,9 @@ bool capsInitNs(struct nsjconf_t *nsjconf)
} else { } else {
struct ints_t *p; struct ints_t *p;
TAILQ_FOREACH(p, &nsjconf->caps, pointers) { TAILQ_FOREACH(p, &nsjconf->caps, pointers) {
if (prctl if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL,
(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, (unsigned long)p->val, 0UL, 0UL)
0UL) == -1) { == -1) {
PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)", PLOG_W("prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, %s)",
capsValToStr(p->val)); capsValToStr(p->val));
} else { } else {

174
cmdline.c
View File

@ -45,8 +45,8 @@
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
#include "mount.h" #include "mount.h"
#include "util.h"
#include "user.h" #include "user.h"
#include "util.h"
struct custom_option { struct custom_option {
struct option opt; struct option opt;
@ -55,8 +55,8 @@ struct custom_option {
/* *INDENT-OFF* */ /* *INDENT-OFF* */
struct custom_option custom_opts[] = { struct custom_option custom_opts[] = {
{{"help", no_argument, NULL, 'h'}, "Help plz.."}, { { "help", no_argument, NULL, 'h' }, "Help plz.." },
{{"mode", required_argument, NULL, 'M'}, { { "mode", required_argument, NULL, 'M' },
"Execution mode (default: o [MODE_STANDALONE_ONCE]):\n" "Execution mode (default: o [MODE_STANDALONE_ONCE]):\n"
"\tl: Wait for connections on a TCP port (specified with --port) " "\tl: Wait for connections on a TCP port (specified with --port) "
"[MODE_LISTEN_TCP]\n" "[MODE_LISTEN_TCP]\n"
@ -65,81 +65,81 @@ struct custom_option custom_opts[] = {
"\te: Immediately launch a single process on the console using execve " "\te: Immediately launch a single process on the console using execve "
"[MODE_STANDALONE_EXECVE]\n" "[MODE_STANDALONE_EXECVE]\n"
"\tr: Immediately launch a single process on the console, keep doing it " "\tr: Immediately launch a single process on the console, keep doing it "
"forever [MODE_STANDALONE_RERUN]"}, "forever [MODE_STANDALONE_RERUN]" },
{{"config", required_argument, NULL, 'C'}, "Configuration file in the config.proto ProtoBuf format"}, { { "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])"}, { { "exec_file", required_argument, NULL, 'x' }, "File to exec (default: argv[0])" },
{{"chroot", required_argument, NULL, 'c'}, "Directory containing / of the jail (default: none)"}, { { "chroot", required_argument, NULL, 'c' }, "Directory containing / of the jail (default: none)" },
{{"rw", no_argument, NULL, 0x601}, "Mount / and /proc as RW (default: RO)"}, { { "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"}, { { "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"}, { { "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')"}, { { "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: '/')"}, { { "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)"}, { { "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: '::')"}, { { "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))"}, { { "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", required_argument, NULL, 'l' }, "Log file (default: use log_fd)" },
{{"log_fd", required_argument, NULL, 'L'}, "Log FD (default: 2)"}, { { "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)"}, { { "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')"}, { { "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"}, { { "daemon", no_argument, NULL, 'd' }, "Daemonize after start" },
{{"verbose", no_argument, NULL, 'v'}, "Verbose output"}, { { "verbose", no_argument, NULL, 'v' }, "Verbose output" },
{{"quiet", no_argument, NULL, 'q'}, "Only output warning and more important messages"}, { { "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?"}, { { "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)"}, { { "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"}, { { "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"}, { { "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"}, { { "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"}, { { "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)"}, { { "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"}, { { "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_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_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_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_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_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_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')"}, { { "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_addr_compat_layout", no_argument, NULL, 0x0301 }, "personality(ADDR_COMPAT_LAYOUT)" },
{{"persona_mmap_page_zero", no_argument, NULL, 0x0302}, "personality(MMAP_PAGE_ZERO)"}, { { "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_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_limit_3gb", no_argument, NULL, 0x0304 }, "personality(ADDR_LIMIT_3GB)" },
{{"persona_addr_no_randomize", no_argument, NULL, 0x0305}, "personality(ADDR_NO_RANDOMIZE)"}, { { "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_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_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_newns", no_argument, NULL, 0x0403 }, "Don't use CLONE_NEWNS" },
{{"disable_clone_newpid", no_argument, NULL, 0x0404}, "Don't use CLONE_NEWPID"}, { { "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_newipc", no_argument, NULL, 0x0405 }, "Don't use CLONE_NEWIPC" },
{{"disable_clone_newuts", no_argument, NULL, 0x0406}, "Don't use CLONE_NEWUTS"}, { { "disable_clone_newuts", no_argument, NULL, 0x0406 }, "Don't use CLONE_NEWUTS" },
{{"enable_clone_newcgroup", no_argument, NULL, 0x0407}, "Use CLONE_NEWCGROUP"}, { { "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"}, { { "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"}, { { "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_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'"}, { { "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"}, { { "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)"}, { { "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"}, { { "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_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/)"}, { { "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_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_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_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_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_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')"}, { { "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"}, { { "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_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_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_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\")"}, { { "macvlan_vs_gw", required_argument, NULL, 0x703 }, "Default GW for the 'vs' interface (e.g. \"192.168.0.1\")" },
}; };
struct custom_option deprecated_opts[] = { struct custom_option deprecated_opts[] = {
// Compatibilty flags for MACVLAN. // Compatibilty flags for MACVLAN.
// TODO(rswiecki): Remove this at some point. // 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", 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_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_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_vs_gw", required_argument, NULL, 0x703 }, "Default GW for the 'vs' interface (e.g. \"192.168.0.1\")" },
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
@ -576,12 +576,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg; char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id); char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id); char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL size_t count = (cnt == NULL || strlen(cnt) == 0)
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt, ? 1U : (size_t) strtoull(cnt,
NULL, NULL,
0); 0);
if (userParseId(nsjconf, i_id, o_id, count, false /* is_gid */ , if (userParseId(nsjconf, i_id, o_id, count, false /* is_gid */ ,
false /* is_newidmap */ ) == false) { false /* is_newidmap */ )
== false) {
return false; return false;
} }
} }
@ -590,12 +591,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg; char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id); char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id); char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL size_t count = (cnt == NULL || strlen(cnt) == 0)
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt, ? 1U : (size_t) strtoull(cnt,
NULL, NULL,
0); 0);
if (userParseId(nsjconf, i_id, o_id, count, true /* is_gid */ , if (userParseId(nsjconf, i_id, o_id, count, true /* is_gid */ ,
false /* is_newidmap */ ) == false) { false /* is_newidmap */ )
== false) {
return false; return false;
} }
} }
@ -604,12 +606,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg; char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id); char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id); char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL size_t count = (cnt == NULL || strlen(cnt) == 0)
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt, ? 1U : (size_t) strtoull(cnt,
NULL, NULL,
0); 0);
if (userParseId(nsjconf, i_id, o_id, count, false /* is_gid */ , if (userParseId(nsjconf, i_id, o_id, count, false /* is_gid */ ,
true /* is_newidmap */ ) == false) { true /* is_newidmap */ )
== false) {
return false; return false;
} }
} }
@ -618,12 +621,13 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf)
char *i_id = optarg; char *i_id = optarg;
char *o_id = cmdlineSplitStrByColon(i_id); char *o_id = cmdlineSplitStrByColon(i_id);
char *cnt = cmdlineSplitStrByColon(o_id); char *cnt = cmdlineSplitStrByColon(o_id);
size_t count = (cnt == NULL size_t count = (cnt == NULL || strlen(cnt) == 0)
|| strlen(cnt) == 0) ? 1U : (size_t) strtoull(cnt, ? 1U : (size_t) strtoull(cnt,
NULL, NULL,
0); 0);
if (userParseId(nsjconf, i_id, o_id, count, true /* is_gid */ , if (userParseId(nsjconf, i_id, o_id, count, true /* is_gid */ ,
true /* is_newidmap */ ) == false) { true /* is_newidmap */ )
== false) {
return false; return false;
} }
} }

View File

@ -48,9 +48,9 @@ static void __attribute__ ((unused)) __clang_cleanup_func(void (^*dfunc) (void))
#else #else
#define __block #define __block
#define _DEFER(a, count) \ #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)); \ 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__) #define defer _DEFER(a, __COUNTER__)
#endif #endif
#endif #endif
@ -61,7 +61,8 @@ struct pids_t {
char remote_txt[64]; char remote_txt[64];
struct sockaddr_in6 remote_addr; struct sockaddr_in6 remote_addr;
int pid_syscall_fd; int pid_syscall_fd;
TAILQ_ENTRY(pids_t) pointers; TAILQ_ENTRY(pids_t)
pointers;
}; };
struct mounts_t { struct mounts_t {
@ -75,7 +76,8 @@ struct mounts_t {
bool isDir; bool isDir;
bool isSymlink; bool isSymlink;
bool mandatory; bool mandatory;
TAILQ_ENTRY(mounts_t) pointers; TAILQ_ENTRY(mounts_t)
pointers;
}; };
struct idmap_t { struct idmap_t {
@ -83,12 +85,14 @@ struct idmap_t {
uid_t outside_id; uid_t outside_id;
size_t count; size_t count;
bool is_newidmap; bool is_newidmap;
TAILQ_ENTRY(idmap_t) pointers; TAILQ_ENTRY(idmap_t)
pointers;
}; };
struct ints_t { struct ints_t {
int val; int val;
TAILQ_ENTRY(ints_t) pointers; TAILQ_ENTRY(ints_t)
pointers;
}; };
enum ns_mode_t { enum ns_mode_t {
@ -100,7 +104,8 @@ enum ns_mode_t {
struct charptr_t { struct charptr_t {
char *val; char *val;
TAILQ_ENTRY(charptr_t) pointers; TAILQ_ENTRY(charptr_t)
pointers;
}; };
enum llevel_t { enum llevel_t {
@ -167,13 +172,20 @@ struct nsjconf_t {
char *kafel_string; char *kafel_string;
uid_t orig_euid; uid_t orig_euid;
long num_cpus; long num_cpus;
TAILQ_HEAD(udmaplist, idmap_t) uids; TAILQ_HEAD(udmaplist, idmap_t)
TAILQ_HEAD(gdmaplist, idmap_t) gids; uids;
TAILQ_HEAD(envlist, charptr_t) envs; TAILQ_HEAD(gdmaplist, idmap_t)
TAILQ_HEAD(pidslist, pids_t) pids; gids;
TAILQ_HEAD(mountptslist, mounts_t) mountpts; TAILQ_HEAD(envlist, charptr_t)
TAILQ_HEAD(fdslistt, ints_t) open_fds; envs;
TAILQ_HEAD(capslistt, ints_t) caps; 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 */ #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 #ifndef NS_CONFIG_H
#define NS_CONFIG_H #define NS_CONFIG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "common.h" #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 */ #endif /* NS_CONFIG_H */

View File

@ -19,12 +19,12 @@ enum LogLevel {
message IdMap message IdMap
{ {
/* Empty string means "current uid/gid" */ /* Empty string means "current uid/gid" */
required string inside_id = 1 [ default = "" ]; optional string inside_id = 1 [ default = "" ];
required string outside_id = 2 [ default = "" ]; optional string outside_id = 2 [ default = "" ];
/* See 'man user_namespaces' for the meaning of count */ /* 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? */ /* 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 message MountPt
{ {
@ -41,18 +41,18 @@ message MountPt
/* Can be empty for mount --bind mounts */ /* Can be empty for mount --bind mounts */
optional string fstype = 6 [ default = "" ]; optional string fstype = 6 [ default = "" ];
/* E.g. size=5000000 for 'tmpfs' */ /* 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 */ /* 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 */ /* 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 /* Is it directory? If not specified an internal
heuristics will be used to determine that */ heuristics will be used to determine that */
optional bool is_dir = 10; optional bool is_dir = 10;
/* Should the sandboxing fail if we cannot mount this resource? */ /* 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)? */ /* 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 message Exe
{ {
@ -67,32 +67,32 @@ message NsJailConfig
{ {
/* Optional name and description for this config */ /* Optional name and description for this config */
optional string name = 1 [ default = "" ]; optional string name = 1 [ default = "" ];
optional string description = 2 [ default = "" ]; repeated string description = 2;
/* Execution mode: see 'msg Mode' description for more */ /* 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='/' */ /* Equivalent to a bind mount with dst='/' */
optional string chroot_dir = 4; optional string chroot_dir = 4;
/* Applies both to the chroot_dir and to /proc mounts */ /* 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 */ /* Hostname inside jail */
required string hostname = 8 [ default = "NSJAIL" ]; optional string hostname = 8 [ default = "NSJAIL" ];
/* Initial current working directory for the binary */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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? */ /* 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 */ /* 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. */ /* FD to log to. */
optional int32 log_fd = 16; optional int32 log_fd = 16;
@ -104,52 +104,52 @@ message NsJailConfig
/* Should the current environment variables be kept /* Should the current environment variables be kept
when executing the binary */ 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 */ /* EnvVars to be set before executing binaries */
repeated string envar = 20; repeated string envar = 20;
/* Should capabilities be preserved or dropped */ /* 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. /* Which capabilities should be preserved if keep_caps == false.
Format: "CAP_SYS_PTRACE" */ Format: "CAP_SYS_PTRACE" */
repeated string cap = 63; repeated string cap = 63;
/* Should nsjail close FD=0,1,2 before executing the process */ /* 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? /* Should the child process have control over terminal?
Can be useful to allow /bin/sh to provide Can be useful to allow /bin/sh to provide
job control / signals */ 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 /* Which FDs should be passed to the newly executed process
By default only FD=0,1,2 are passed */ By default only FD=0,1,2 are passed */
repeated int32 pass_fd = 24; repeated int32 pass_fd = 24;
/* Setting it to true will allow to have set-uid binaries /* Setting it to true will allow to have set-uid binaries
inside the jail */ 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 */ optional uint64 rlimit_as = 26 [ default = 512 ]; /* In MiB */
required uint64 rlimit_core = 27 [ default = 0 ]; /* In MiB */ optional uint64 rlimit_core = 27 [ default = 0 ]; /* In MiB */
required uint64 rlimit_cpu = 28 [ default = 600 ]; /* In seconds */ optional uint64 rlimit_cpu = 28 [ default = 600 ]; /* In seconds */
required uint64 rlimit_fsize = 29 [ default = 1 ]; /* In MiB */ optional uint64 rlimit_fsize = 29 [ default = 1 ]; /* In MiB */
required uint64 rlimit_nofile = 30 [ default = 32 ]; optional uint64 rlimit_nofile = 30 [ default = 32 ];
optional uint64 rlimit_nproc = 31; /* This is system-wide: tricky to use */ optional uint64 rlimit_nproc = 31; /* This is system-wide: tricky to use */
optional uint64 rlimit_stack = 32; /* In MiB */ optional uint64 rlimit_stack = 32; /* In MiB */
/* See 'man personality' for more */ /* See 'man personality' for more */
required bool persona_addr_compat_layout = 33 [ default = false ]; optional bool persona_addr_compat_layout = 33 [ default = false ];
required bool persona_mmap_page_zero = 34 [ default = false ]; optional bool persona_mmap_page_zero = 34 [ default = false ];
required bool persona_read_implies_exec = 35 [ default = false ]; optional bool persona_read_implies_exec = 35 [ default = false ];
required bool persona_addr_limit_3gb = 36 [ default = false ]; optional bool persona_addr_limit_3gb = 36 [ default = false ];
required bool persona_addr_no_randomize = 37 [ default = false ]; optional bool persona_addr_no_randomize = 37 [ default = false ];
/* Which name-spaces should be used? */ /* Which name-spaces should be used? */
required bool clone_newnet = 38 [ default = true ]; optional bool clone_newnet = 38 [ default = true ];
required bool clone_newuser = 39 [ default = true ]; optional bool clone_newuser = 39 [ default = true ];
required bool clone_newns = 40 [ default = true ]; optional bool clone_newns = 40 [ default = true ];
required bool clone_newpid = 41 [ default = true ]; optional bool clone_newpid = 41 [ default = true ];
required bool clone_newipc = 42 [ default = true ]; optional bool clone_newipc = 42 [ default = true ];
required bool clone_newuts = 43 [ default = true ]; optional bool clone_newuts = 43 [ default = true ];
/* It's only supported in newer kernels, hence disabled by default */ /* 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' /* Mappings for UIDs and GIDs. See the description for 'msg IdMap'
for more */ for more */
@ -158,7 +158,7 @@ message NsJailConfig
/* Should /proc be mounted (R/O)? This can also be added in the 'mount' /* Should /proc be mounted (R/O)? This can also be added in the 'mount'
section below */ 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' /* Mount points inside the jail. See the description for 'msg MountPt'
for more */ for more */
repeated MountPt mount = 48; repeated MountPt mount = 48;
@ -166,30 +166,30 @@ message NsJailConfig
/* Kafel seccomp-bpf policy file or a string: /* Kafel seccomp-bpf policy file or a string:
Homepage of the project: https://github.com/google/kafel */ Homepage of the project: https://github.com/google/kafel */
optional string seccomp_policy_file = 49; 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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 */ /* 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? */ /* 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 */ /* Parameters for the cloned MACVLAN interface inside jail */
optional string macvlan_iface = 58; /* Interface to be cloned, eg 'eth0' */ optional string macvlan_iface = 58; /* Interface to be cloned, eg 'eth0' */
required string macvlan_vs_ip = 59 [ default = "192.168.0.2" ]; optional string macvlan_vs_ip = 59 [ default = "192.168.0.2" ];
required string macvlan_vs_nm = 60 [ default = "255.255.255.0" ]; optional 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_gw = 61 [ default = "192.168.0.1" ];
/* Binary path (with arguments) to be executed. If not specified here, it /* Binary path (with arguments) to be executed. If not specified here, it
can be specified with cmd-line as "-- /path/to/command arg1 arg2" */ can be specified with cmd-line as "-- /path/to/command arg1 arg2" */

View File

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

View File

@ -1,13 +1,11 @@
name: "bash-with-fake-geteuid" name: "bash-with-fake-geteuid"
description: description: "An example/demo policy which allows to execute /bin/bash and other commands in "
"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 "
a fairly restricted jail containing only some directories from the main description: "system, and with blocked __NR_syslog syscall. Also, __NR_geteuid returns -1337 "
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 "
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. "
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 "
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"
mode: ONCE mode: ONCE
hostname: "JAILED-BASH" hostname: "JAILED-BASH"
@ -169,14 +167,13 @@ mount {
mandatory: false mandatory: false
} }
seccomp_string: " seccomp_string: "POLICY example { "
POLICY example { seccomp_string: " ERRNO(1337) { geteuid }, "
ERRNO(1337) { geteuid }, seccomp_string: " "
KILL { syslog }, seccomp_string: " KILL { syslog }, "
ERRNO(0) { ptrace } seccomp_string: " ERRNO(0) { ptrace } "
} seccomp_string: "} "
USE example DEFAULT ALLOW seccomp_string: "USE example DEFAULT ALLOW "
"
exec_bin { exec_bin {
path: "/bin/bash" path: "/bin/bash"

View File

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

View File

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

View File

@ -1,18 +1,17 @@
name: "firefox-with-net" 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. description: "This policy allows to run firefox inside a jail. Access to networking is"
The rest of available on the FS files/dires are libs and X-related files/dirs. description: "permitted with this setup (clone_newnet: false)."
description: ""
Run as: 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."
./nsjail --config configs/firefox-with-net.cfg description: ""
description: "Run as:"
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: "./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 mode: ONCE
hostname: "FIREFOX" hostname: "FIREFOX"
@ -138,16 +137,14 @@ mount {
is_bind: true is_bind: true
} }
seccomp_string: " seccomp_string: " POLICY example {"
POLICY example { seccomp_string: " KILL {"
KILL { seccomp_string: " ptrace,"
ptrace, seccomp_string: " process_vm_readv,"
process_vm_readv, seccomp_string: " process_vm_writev"
process_vm_writev seccomp_string: " }"
} seccomp_string: " }"
} seccomp_string: " USE example DEFAULT ALLOW"
USE example DEFAULT ALLOW
"
exec_bin { exec_bin {
path: "/usr/lib/firefox/firefox" path: "/usr/lib/firefox/firefox"

View File

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

View File

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

2
log.c
View File

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

13
mount.c
View File

@ -25,8 +25,8 @@
#include <fcntl.h> #include <fcntl.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <sched.h> #include <sched.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -40,10 +40,13 @@
#include "subproc.h" #include "subproc.h"
#include "util.h" #include "util.h"
#define VALSTR_STRUCT(x) { x, #x } #define VALSTR_STRUCT(x) \
{ \
x, #x \
}
#if !defined(MS_LAZYTIME) #if !defined(MS_LAZYTIME)
#define MS_LAZYTIME (1<<25) #define MS_LAZYTIME (1 << 25)
#endif /* if !defined(MS_LAZYTIME) */ #endif /* if !defined(MS_LAZYTIME) */
const char *mountFlagsToStr(uintptr_t flags) 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, bool mountAddMountPt(struct nsjconf_t * nsjconf, const char *src, const char *dst,
const char *fstype, const char *options, uintptr_t flags, const bool * isDir, const char *fstype, const char *options, uintptr_t flags, const bool * isDir,
bool mandatory, const char *src_env, const char *dst_env, 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)); 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; p->src_content_len = src_content_len;
TAILQ_INSERT_TAIL(&nsjconf->mountpts, p, pointers); 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, bool mountAddMountPt(struct nsjconf_t *nsjconf, const char *src, const char *dst,
const char *fstype, const char *options, uintptr_t flags, const bool * isDir, const char *fstype, const char *options, uintptr_t flags, const bool * isDir,
bool mandatory, const char *src_env, const char *dst_env, 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); const char *mountDescribeMountPt(struct mounts_t *mpt);
#endif /* NS_MOUNT_H */ #endif /* NS_MOUNT_H */

8
net.c
View File

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

View File

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

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

View File

@ -29,8 +29,8 @@
#include <sched.h> #include <sched.h>
#include <setjmp.h> #include <setjmp.h>
#include <signal.h> #include <signal.h>
#include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/prctl.h> #include <sys/prctl.h>
@ -41,8 +41,8 @@
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "common.h"
#include "cgroup.h" #include "cgroup.h"
#include "common.h"
#include "contain.h" #include "contain.h"
#include "log.h" #include "log.h"
#include "net.h" #include "net.h"
@ -52,7 +52,10 @@
static const char subprocDoneChar = 'D'; static const char subprocDoneChar = 'D';
#define VALSTR_STRUCT(x) { x, #x } #define VALSTR_STRUCT(x) \
{ \
x, #x \
}
#if !defined(CLONE_NEWCGROUP) #if !defined(CLONE_NEWCGROUP)
#define CLONE_NEWCGROUP 0x02000000 #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, LOG_D("setresgid(%d, %d, %d)", TAILQ_FIRST(&nsjconf->gids)->inside_id,
TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id); TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id);
if (syscall if (syscall(__NR_setresgid, TAILQ_FIRST(&nsjconf->gids)->inside_id,
(__NR_setresgid, TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id, TAILQ_FIRST(&nsjconf->gids)->inside_id)
TAILQ_FIRST(&nsjconf->gids)->inside_id, == -1) {
TAILQ_FIRST(&nsjconf->gids)->inside_id) == -1) {
PLOG_E("setresgid(%u)", TAILQ_FIRST(&nsjconf->gids)->inside_id); PLOG_E("setresgid(%u)", TAILQ_FIRST(&nsjconf->gids)->inside_id);
return false; return false;
} }
LOG_D("setresuid(%d, %d, %d)", TAILQ_FIRST(&nsjconf->uids)->inside_id, LOG_D("setresuid(%d, %d, %d)", TAILQ_FIRST(&nsjconf->uids)->inside_id,
TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id); TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id);
if (syscall if (syscall(__NR_setresuid, TAILQ_FIRST(&nsjconf->uids)->inside_id,
(__NR_setresuid, TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id, TAILQ_FIRST(&nsjconf->uids)->inside_id)
TAILQ_FIRST(&nsjconf->uids)->inside_id, == -1) {
TAILQ_FIRST(&nsjconf->uids)->inside_id) == -1) {
PLOG_E("setresuid(%u)", TAILQ_FIRST(&nsjconf->uids)->inside_id); PLOG_E("setresuid(%u)", TAILQ_FIRST(&nsjconf->uids)->inside_id);
return false; return false;
} }