Skip to content

Commit

Permalink
Merge pull request #233 from tomfitzhenry/protojson
Browse files Browse the repository at this point in the history
config: try to parse as ProtoJSON
  • Loading branch information
robertswiecki authored Jun 25, 2024
2 parents a00a0ef + acf9f45 commit b3d53a1
Show file tree
Hide file tree
Showing 2 changed files with 216 additions and 14 deletions.
60 changes: 46 additions & 14 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 <list>
#include <string>
#include <vector>

Expand Down Expand Up @@ -302,39 +304,69 @@ static bool parseInternal(nsjconf_t* nsjconf, const nsjail::NsJailConfig& njc) {
return true;
}

static std::list<std::string> error_messages;

static void logHandler(
google::protobuf::LogLevel level, const char* filename, int line, const std::string& message) {
LOG_W("config.cc: '%s'", message.c_str());
error_messages.push_back(message);
}

static void flushLog() {
for (auto message : error_messages) {
LOG_W("config.cc: '%s'", message.c_str());
}
error_messages.clear();
}

bool parseFile(nsjconf_t* nsjconf, const char* file) {
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;
}

google::protobuf::SetLogHandler(logHandler);
google::protobuf::io::FileInputStream input(fd);
input.SetCloseOnDelete(true);
std::string conf((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));

/* Use static so we can get c_str() pointers, and copy them into the nsjconf struct */
static nsjail::NsJailConfig nsc;
static nsjail::NsJailConfig json_nsc;
static nsjail::NsJailConfig text_nsc;

google::protobuf::SetLogHandler(logHandler);
auto json_status = google::protobuf::util::JsonStringToMessage(conf, &json_nsc);
bool text_parsed = google::protobuf::TextFormat::ParseFromString(conf, &text_nsc);

auto parser = google::protobuf::TextFormat::Parser();
if (!parser.Parse(&input, &nsc)) {
LOG_W("Couldn't parse file '%s' from Text into ProtoBuf", file);
if (json_status.ok() && text_parsed) {
LOG_W("Config file '%s' ambiguously parsed as TextProto and ProtoJSON", file);
return false;
}
if (!parseInternal(nsjconf, nsc)) {
LOG_W("Couldn't parse the ProtoBuf from '%s'", file);

if (!json_status.ok() && !text_parsed) {
LOG_W("Config file '%s' failed to parse as either TextProto or ProtoJSON", file);
flushLog();
LOG_W("config.cc: ProtoJSON parse status: '%s'", json_status.ToString().c_str());
return false;
}

LOG_D("Parsed config from '%s':\n'%s'", file, nsc.DebugString().c_str());
return true;
if (json_status.ok() && !text_parsed) {
if (!parseInternal(nsjconf, json_nsc)) {
LOG_W("Couldn't parse the ProtoJSON from '%s'", file);
return false;
}
LOG_D("Parsed JSON config from '%s':\n'%s'", file, json_nsc.DebugString().c_str());
return true;
}

if (text_parsed && !json_status.ok()) {
if (!parseInternal(nsjconf, text_nsc)) {
LOG_W("Couldn't parse the TextProto from '%s'", file);
return false;
}
LOG_D("Parsed TextProto config from '%s':\n'%s'", file, text_nsc.DebugString().c_str());
return true;
}
return false;
}

} // namespace config
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"
}
}

0 comments on commit b3d53a1

Please sign in to comment.