mirror of
https://github.com/google/nsjail.git
synced 2026-08-30 18:41:30 -07:00
config: try to parse as ProtoJSON
JSON is an easier to generate than TextProto in some environments, e.g. Jsonnet or Nix. File I/O had to be reworked to support the json_util API: https://protobuf.dev/reference/cpp/api-docs/google.protobuf.util.json_util/
This commit is contained in:
64
config.cc
64
config.cc
@@ -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>
|
||||
@@ -32,6 +33,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -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;
|
||||
|
||||
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 (!parseInternal(nsjconf, nsc)) {
|
||||
LOG_W("Couldn't parse the ProtoBuf from '%s'", file);
|
||||
google::protobuf::SetLogHandler(logHandler);
|
||||
auto json_status = google::protobuf::util::JsonStringToMessage(conf, &json_nsc);
|
||||
bool text_parsed = google::protobuf::TextFormat::ParseFromString(conf, &text_nsc);
|
||||
|
||||
if (json_status.ok() && text_parsed) {
|
||||
LOG_W("Config file '%s' ambiguously parsed as TextProto and ProtoJSON", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_D("Parsed config from '%s':\n'%s'", file, nsc.DebugString().c_str());
|
||||
return true;
|
||||
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;
|
||||
}
|
||||
|
||||
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
configs/bash-with-fake-geteuid.json
Normal file
170
configs/bash-with-fake-geteuid.json
Normal file
@@ -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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user