Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
d7e29edd02 | |||
d573c588b0 | |||
25ba8d7076 | |||
a6ec85c1a0 | |||
cf5d6387df |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
.idea
|
||||||
*.o
|
*.o
|
||||||
config.pb.h
|
config.pb.h
|
||||||
config.pb.cc
|
config.pb.cc
|
||||||
|
54
cgroup2.cc
54
cgroup2.cc
@ -271,10 +271,62 @@ bool initNsFromParent(nsjconf_t *nsjconf, pid_t pid) {
|
|||||||
return initNsFromParentCpu(nsjconf, pid);
|
return initNsFromParentCpu(nsjconf, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dumpCgroupStats(nsjconf_t *nsjconf, const std::string &cgroup_path) {
|
||||||
|
LOG_D("Dump stats to '%s'", nsjconf->dump_stats_file.c_str());
|
||||||
|
|
||||||
|
std::ofstream dump_file(nsjconf->dump_stats_file);
|
||||||
|
if (!dump_file.is_open()) {
|
||||||
|
PLOG_W("Failed to open dump stats file '%s'", nsjconf->dump_stats_file.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto res_name = [&](const std::string &res) -> std::string {
|
||||||
|
return cgroup_path + "/" + res;
|
||||||
|
};
|
||||||
|
auto get_length = [&](std::ifstream &f) -> size_t {
|
||||||
|
f.seekg(0, std::ios::end);
|
||||||
|
auto sz = f.tellg();
|
||||||
|
f.seekg(0, std::ios::beg);
|
||||||
|
return sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto stats = {"cpu.stat", "io.stat", "memory.stat"};
|
||||||
|
for (const auto &res : stats) {
|
||||||
|
auto path = res_name(res);
|
||||||
|
std::ifstream f(path);
|
||||||
|
if (!f.is_open()) {
|
||||||
|
PLOG_W("Invalid cgroup resource file '%s'", path.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
dump_file << f.rdbuf() << std::endl;
|
||||||
|
dump_file.clear();
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto mem_stats = {"memory.peak", "memory.swap.peak"};
|
||||||
|
for (const auto &res : mem_stats) {
|
||||||
|
auto path = res_name(res);
|
||||||
|
std::ifstream f(path);
|
||||||
|
if (!f.is_open()) {
|
||||||
|
PLOG_W("Invalid cgroup resource file '%s'", path.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::string line;
|
||||||
|
std::getline(f, line);
|
||||||
|
dump_file << res << ' ' << line << std::endl;
|
||||||
|
dump_file.clear();
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_file.close();
|
||||||
|
}
|
||||||
|
|
||||||
void finishFromParent(nsjconf_t *nsjconf, pid_t pid) {
|
void finishFromParent(nsjconf_t *nsjconf, pid_t pid) {
|
||||||
if (nsjconf->cgroup_mem_max != (size_t)0 || nsjconf->cgroup_pids_max != 0U ||
|
if (nsjconf->cgroup_mem_max != (size_t)0 || nsjconf->cgroup_pids_max != 0U ||
|
||||||
nsjconf->cgroup_cpu_ms_per_sec != 0U) {
|
nsjconf->cgroup_cpu_ms_per_sec != 0U) {
|
||||||
removeCgroup(getCgroupPath(nsjconf, pid));
|
auto cgroup_path = getCgroupPath(nsjconf, pid);
|
||||||
|
dumpCgroupStats(nsjconf, cgroup_path);
|
||||||
|
removeCgroup(cgroup_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
cmdline.cc
19
cmdline.cc
@ -170,6 +170,8 @@ static const struct custom_option custom_opts[] = {
|
|||||||
{ { "macvlan_vs_mo", required_argument, nullptr, 0x706 }, "Mode of the 'vs' interface. Can be either 'private', 'vepa', 'bridge' or 'passthru' (default: 'private')" },
|
{ { "macvlan_vs_mo", required_argument, nullptr, 0x706 }, "Mode of the 'vs' interface. Can be either 'private', 'vepa', 'bridge' or 'passthru' (default: 'private')" },
|
||||||
{ { "disable_tsc", no_argument, nullptr, 0x707 }, "Disable rdtsc and rdtscp instructions. WARNING: To make it effective, you also need to forbid `prctl(PR_SET_TSC, PR_TSC_ENABLE, ...)` in seccomp rules! (x86 and x86_64 only). Dynamic binaries produced by GCC seem to rely on RDTSC, but static ones should work." },
|
{ { "disable_tsc", no_argument, nullptr, 0x707 }, "Disable rdtsc and rdtscp instructions. WARNING: To make it effective, you also need to forbid `prctl(PR_SET_TSC, PR_TSC_ENABLE, ...)` in seccomp rules! (x86 and x86_64 only). Dynamic binaries produced by GCC seem to rely on RDTSC, but static ones should work." },
|
||||||
{ { "forward_signals", no_argument, nullptr, 0x708 }, "Forward fatal signals to the child process instead of always using SIGKILL." },
|
{ { "forward_signals", no_argument, nullptr, 0x708 }, "Forward fatal signals to the child process instead of always using SIGKILL." },
|
||||||
|
{ { "dump_stats", no_argument, nullptr, 0x1001 }, "Dump cgroups stat when process terminated. (Only work with MODE_STANDALONE_ONCE and cgroupv2)" },
|
||||||
|
{ { "dump_stats_file", required_argument, nullptr, 0x1002 }, "Location of dump_stats file." },
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
@ -540,6 +542,8 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char *argv[]) {
|
|||||||
nsjconf->seccomp_fprog.len = 0;
|
nsjconf->seccomp_fprog.len = 0;
|
||||||
nsjconf->seccomp_log = false;
|
nsjconf->seccomp_log = false;
|
||||||
nsjconf->nice_level = 19;
|
nsjconf->nice_level = 19;
|
||||||
|
nsjconf->dump_stats = false;
|
||||||
|
nsjconf->dump_stats_file = "/tmp/nsjail.log";
|
||||||
|
|
||||||
nsjconf->openfds.push_back(STDIN_FILENO);
|
nsjconf->openfds.push_back(STDIN_FILENO);
|
||||||
nsjconf->openfds.push_back(STDOUT_FILENO);
|
nsjconf->openfds.push_back(STDOUT_FILENO);
|
||||||
@ -985,6 +989,12 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char *argv[]) {
|
|||||||
case 0x903:
|
case 0x903:
|
||||||
nsjconf->nice_level = (int)strtol(optarg, NULL, 0);
|
nsjconf->nice_level = (int)strtol(optarg, NULL, 0);
|
||||||
break;
|
break;
|
||||||
|
case 0x1001:
|
||||||
|
nsjconf->dump_stats = true;
|
||||||
|
break;
|
||||||
|
case 0x1002:
|
||||||
|
nsjconf->dump_stats_file = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
cmdlineUsage(argv[0]);
|
cmdlineUsage(argv[0]);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -1008,6 +1018,15 @@ std::unique_ptr<nsjconf_t> parseArgs(int argc, char *argv[]) {
|
|||||||
LOG_F("cannot set both cgroup_mem_memsw_max and cgroup_mem_swap_max");
|
LOG_F("cannot set both cgroup_mem_memsw_max and cgroup_mem_swap_max");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nsjconf->dump_stats) {
|
||||||
|
if (nsjconf->mode != MODE_STANDALONE_ONCE) {
|
||||||
|
LOG_F("dump_stats can only be used with MODE_STANDALONE_ONCE");
|
||||||
|
}
|
||||||
|
if (!nsjconf->use_cgroupv2) {
|
||||||
|
LOG_E("dump_stats can only be used with cgroup v2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nsjconf;
|
return nsjconf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,12 +299,10 @@ static bool parseInternal(nsjconf_t* nsjconf, const nsjail::NsJailConfig& njc) {
|
|||||||
nsjconf->use_execveat = njc.exec_bin().exec_fd();
|
nsjconf->use_execveat = njc.exec_bin().exec_fd();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
nsjconf->dump_stats = njc.dump_stats();
|
||||||
}
|
nsjconf->dump_stats_file = njc.dump_stats_file();
|
||||||
|
|
||||||
static void logHandler(
|
return true;
|
||||||
google::protobuf::LogLevel level, const char* filename, int line, const std::string& message) {
|
|
||||||
LOG_W("config.cc: '%s'", message.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseFile(nsjconf_t* nsjconf, const char* file) {
|
bool parseFile(nsjconf_t* nsjconf, const char* file) {
|
||||||
@ -316,7 +314,6 @@ bool parseFile(nsjconf_t* nsjconf, const char* file) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
google::protobuf::SetLogHandler(logHandler);
|
|
||||||
google::protobuf::io::FileInputStream input(fd);
|
google::protobuf::io::FileInputStream input(fd);
|
||||||
input.SetCloseOnDelete(true);
|
input.SetCloseOnDelete(true);
|
||||||
|
|
||||||
|
@ -278,4 +278,8 @@ message NsJailConfig {
|
|||||||
|
|
||||||
/* Check whether cgroupv2 is available, and use it if available. */
|
/* Check whether cgroupv2 is available, and use it if available. */
|
||||||
optional bool detect_cgroupv2 = 95 [default = false];
|
optional bool detect_cgroupv2 = 95 [default = false];
|
||||||
|
|
||||||
|
/* Dump statistics to a file */
|
||||||
|
optional bool dump_stats = 96 [default = false];
|
||||||
|
optional string dump_stats_file = 97 [default = "/tmp/nsjail.log"];
|
||||||
}
|
}
|
||||||
|
2
nsjail.h
2
nsjail.h
@ -180,6 +180,8 @@ struct nsjconf_t {
|
|||||||
std::vector<int> caps;
|
std::vector<int> caps;
|
||||||
std::vector<std::string> ifaces;
|
std::vector<std::string> ifaces;
|
||||||
std::vector<pipemap_t> pipes;
|
std::vector<pipemap_t> pipes;
|
||||||
|
bool dump_stats;
|
||||||
|
std::string dump_stats_file;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _NSJAIL_H */
|
#endif /* _NSJAIL_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user