Skip to content

Commit

Permalink
config: support --json to parse as Proto JSON
Browse files Browse the repository at this point in the history
JSON is an easier to generate than TextProto in some environments,
e.g. Jsonnet or Nix.

https://protobuf.dev/reference/cpp/api-docs/google.protobuf.util.json_util/
  • Loading branch information
tomfitzhenry committed Jun 23, 2024
1 parent a00a0ef commit a9e654d
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 12 deletions.
9 changes: 7 additions & 2 deletions cmdline.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ static const struct custom_option custom_opts[] = {
" e: [MODE_STANDALONE_EXECVE]\n\tLaunch a single process on the console using execve\n"
" r: [MODE_STANDALONE_RERUN]\n\tLaunch a single process on the console with clone/execve, keep doing it forever" },
{ { "config", required_argument, nullptr, 'C' }, "Configuration file in the config.proto ProtoBuf format (see configs/ directory for examples)" },
{ { "json", no_argument, nullptr, 'J' }, "Read configuration file as ProtoJSON" },
{ { "exec_file", required_argument, nullptr, 'x' }, "File to exec (default: argv[0])" },
{ { "execute_fd", no_argument, nullptr, 0x0607 }, "Use execveat() to execute a file-descriptor instead of executing the binary path. In such case argv[0]/exec_file denotes a file path before mount namespacing" },
{ { "chroot", required_argument, nullptr, 'c' }, "Directory containing / of the jail (default: none)" },
Expand Down Expand Up @@ -469,6 +470,7 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char *argv[]) {

nsjconf->use_execveat = false;
nsjconf->exec_fd = -1;
nsjconf->json = false;
nsjconf->hostname = "NSJAIL";
nsjconf->cwd = "/";
nsjconf->port = 0;
Expand Down Expand Up @@ -558,7 +560,7 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char *argv[]) {
int opt_index = 0;
for (;;) {
int c = getopt_long(argc, argv,
"x:H:D:C:c:p:i:u:g:l:L:t:M:NdvqQeh?E:R:B:T:m:s:P:I:U:G:", opts, &opt_index);
"x:H:D:J:C:c:p:i:u:g:l:L:t:M:NdvqQeh?E:R:B:T:m:s:P:I:U:G:", opts, &opt_index);
if (c == -1) {
break;
}
Expand All @@ -572,8 +574,11 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char *argv[]) {
case 'D':
nsjconf->cwd = optarg;
break;
case 'J':
nsjconf->json = true;
break;
case 'C':
if (!config::parseFile(nsjconf.get(), optarg)) {
if (!config::parseFile(nsjconf.get(), optarg, nsjconf->json)) {
LOG_F("Couldn't parse configuration from %s file", QC(optarg));
}
break;
Expand Down
28 changes: 19 additions & 9 deletions config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <fcntl.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/util/json_util.h>
#include <stdio.h>
#include <sys/mount.h>
#include <sys/personality.h>
Expand All @@ -32,6 +33,7 @@
#include <sys/types.h>

#include <fstream>
#include <sstream>
#include <string>
#include <vector>

Expand Down Expand Up @@ -307,26 +309,34 @@ static void logHandler(
LOG_W("config.cc: '%s'", message.c_str());
}

bool parseFile(nsjconf_t* nsjconf, const char* file) {
bool parseFile(nsjconf_t* nsjconf, const char* file, bool json) {
LOG_D("Parsing configuration from '%s'", file);

int fd = TEMP_FAILURE_RETRY(open(file, O_RDONLY | O_CLOEXEC));
if (fd == -1) {
std::ifstream ifs(file);
if (!ifs.is_open()) {
PLOG_W("Couldn't open config file '%s'", file);
return false;
}
std::string conf((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));

google::protobuf::SetLogHandler(logHandler);
google::protobuf::io::FileInputStream input(fd);
input.SetCloseOnDelete(true);

/* Use static so we can get c_str() pointers, and copy them into the nsjconf struct */
static 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 (json) {
auto status = google::protobuf::util::JsonStringToMessage(conf, &nsc);
if (!status.ok()) {
LOG_W("Couldn't parse file '%s' from JSON into ProtoBuf", file);
return false;
}
} else {
auto parser = google::protobuf::TextFormat::Parser();
if (!parser.ParseFromString(conf, &nsc)) {
LOG_W("Couldn't parse file '%s' from Text into ProtoBuf", file);
return false;
}
}
if (!parseInternal(nsjconf, nsc)) {
LOG_W("Couldn't parse the ProtoBuf from '%s'", file);
Expand Down
2 changes: 1 addition & 1 deletion config.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

namespace config {

bool parseFile(nsjconf_t* nsjconf, const char* file);
bool parseFile(nsjconf_t* nsjconf, const char* file, bool json);

} // namespace config

Expand Down
170 changes: 170 additions & 0 deletions configs/bash-with-fake-geteuid.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
{
"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 "
],
"mode": "ONCE",
"hostname": "JAILED-BASH",
"cwd": "/tmp",
"port": 31337,
"bindhost": "127.0.0.1",
"maxConnsPerIp": 10,
"timeLimit": 100,
"daemon": false,
"maxCpus": 1,
"keepEnv": false,
"envar": [
"ENVAR1=VALUE1",
"ENVAR2=VALUE2",
"TERM=linux",
"HOME=/",
"PS1=[\\H:\\t:\\s-\\V:\\w]\\$ "
],
"keepCaps": true,
"cap": [
"CAP_NET_ADMIN",
"CAP_NET_RAW"
],
"silent": false,
"skipSetsid": true,
"stderrToNull": false,
"passFd": [
100,
3
],
"disableNoNewPrivs": false,
"rlimitAs": "128",
"rlimitCore": "0",
"rlimitCpu": "10",
"rlimitFsize": "0",
"rlimitNofile": "32",
"rlimitNprocType": "SOFT",
"rlimitStackType": "SOFT",
"personaAddrCompatLayout": false,
"personaMmapPageZero": false,
"personaReadImpliesExec": false,
"personaAddrLimit3gb": false,
"personaAddrNoRandomize": false,
"cloneNewnet": true,
"cloneNewuser": true,
"cloneNewns": true,
"cloneNewpid": true,
"cloneNewipc": true,
"cloneNewuts": true,
"cloneNewcgroup": true,
"uidmap": [
{
"insideId": "0",
"outsideId": "",
"count": 1
}
],
"gidmap": [
{
"insideId": "0",
"outsideId": "",
"count": 1
}
],
"mountProc": false,
"mount": [
{
"src": "/lib",
"dst": "/lib",
"isBind": true,
"rw": false
},
{
"src": "/bin",
"dst": "/bin",
"isBind": true,
"rw": false
},
{
"src": "/sbin",
"dst": "/sbin",
"isBind": true,
"rw": false
},
{
"src": "/usr",
"dst": "/usr",
"isBind": true,
"rw": false
},
{
"src": "/lib64",
"dst": "/lib64",
"isBind": true,
"rw": false,
"mandatory": false
},
{
"src": "/lib32",
"dst": "/lib32",
"isBind": true,
"rw": false,
"mandatory": false
},
{
"dst": "/tmp",
"fstype": "tmpfs",
"isBind": false,
"rw": true,
"nosuid": true,
"nodev": true,
"noexec": true
},
{
"src": "/dev/null",
"dst": "/dev/null",
"isBind": true,
"rw": true
},
{
"dst": "/proc",
"fstype": "proc",
"rw": false
},
{
"srcContent": "VGhpcyBmaWxlIHdhcyBjcmVhdGVkIGR5bmFtaWNhbGx5",
"dst": "/DYNAMIC_FILE"
},
{
"src": "/nonexistent_777",
"dst": "/nonexistent_777",
"isBind": true,
"mandatory": false
},
{
"src": "/proc/self/fd",
"dst": "/dev/fd",
"isSymlink": true
},
{
"src": "/some/unimportant/target",
"dst": "/proc/no/symlinks/can/be/created/in/proc",
"mandatory": false,
"isSymlink": true
}
],
"seccompString": [
"ERRNO(1337) { geteuid }\t",
"ERRNO(1) { ptrace, sched_setaffinity }\t\t",
"KILL_PROCESS { syslog }\t\t",
"DEFAULT ALLOW\t\t\t"
],
"execBin": {
"path": "/bin/bash",
"arg": [
"-i"
],
"arg0": "sh"
}
}
1 change: 1 addition & 0 deletions nsjail.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct nsjconf_t {
bool use_execveat;
int exec_fd;
std::vector<std::string> argv;
bool json;
std::string hostname;
std::string cwd;
std::string chroot;
Expand Down

0 comments on commit a9e654d

Please sign in to comment.