return true;
}
+static bool cgroupInitNsFromParentNetCls(struct nsjconf_t* nsjconf, pid_t pid)
+{
+ if (nsjconf->cgroup_net_cls_classid == (unsigned int)0) {
+ return true;
+ }
+
+ char net_cls_cgroup_path[PATH_MAX];
+ snprintf(net_cls_cgroup_path, sizeof(net_cls_cgroup_path), "%s/%s/NSJAIL.%d",
+ nsjconf->cgroup_net_cls_mount, nsjconf->cgroup_net_cls_parent, (int)pid);
+ LOG_D("Create '%s' for PID=%d", net_cls_cgroup_path, (int)pid);
+ if (mkdir(net_cls_cgroup_path, 0700) == -1 && errno != EEXIST) {
+ PLOG_E("mkdir('%s', 0711) failed", net_cls_cgroup_path);
+ return false;
+ }
+
+ char fname[PATH_MAX];
+ if (nsjconf->cgroup_net_cls_classid != (unsigned int)0) {
+ char net_cls_classid_str[512];
+ snprintf(net_cls_classid_str, sizeof(net_cls_classid_str), "0x%x", nsjconf->cgroup_net_cls_classid);
+ snprintf(fname, sizeof(fname), "%s/net_cls.classid", net_cls_cgroup_path);
+ LOG_D("Setting '%s' to '%s'", fname, net_cls_classid_str);
+ if (!utilWriteBufToFile(
+ fname, net_cls_classid_str, strlen(net_cls_classid_str), O_WRONLY | O_CLOEXEC)) {
+ LOG_E("Could not update net_cls cgroup classid");
+ return false;
+ }
+ }
+
+ char pid_str[512];
+ snprintf(pid_str, sizeof(pid_str), "%d", (int)pid);
+ snprintf(fname, sizeof(fname), "%s/tasks", net_cls_cgroup_path);
+ LOG_D("Adding PID='%s' to '%s'", pid_str, fname);
+ if (!utilWriteBufToFile(fname, pid_str, strlen(pid_str), O_WRONLY | O_CLOEXEC)) {
+ LOG_E("Could not update net_cls cgroup task list");
+ return false;
+ }
+
+ return true;
+}
+
bool cgroupInitNsFromParent(struct nsjconf_t* nsjconf, pid_t pid)
{
if (cgroupInitNsFromParentMem(nsjconf, pid) == false) {
if (cgroupInitNsFromParentPids(nsjconf, pid) == false) {
return false;
}
+ if (cgroupInitNsFromParentNetCls(nsjconf, pid) == false) {
+ return false;
+ }
return true;
}
return;
}
+void cgroupFinishFromParentNetCls(struct nsjconf_t* nsjconf, pid_t pid)
+{
+ if (nsjconf->cgroup_net_cls_classid == (size_t)0) {
+ return;
+ }
+ char net_cls_cgroup_path[PATH_MAX];
+ snprintf(net_cls_cgroup_path, sizeof(net_cls_cgroup_path), "%s/%s/NSJAIL.%d",
+ nsjconf->cgroup_net_cls_mount, nsjconf->cgroup_net_cls_parent, (int)pid);
+ LOG_D("Remove '%s'", net_cls_cgroup_path);
+ if (rmdir(net_cls_cgroup_path) == -1) {
+ PLOG_W("rmdir('%s') failed", net_cls_cgroup_path);
+ }
+ return;
+}
+
void cgroupFinishFromParent(struct nsjconf_t* nsjconf, pid_t pid)
{
cgroupFinishFromParentMem(nsjconf, pid);
cgroupFinishFromParentPids(nsjconf, pid);
+ cgroupFinishFromParentNetCls(nsjconf, pid);
}
bool cgroupInitNs(void) { return true; }
{ { "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_parent", required_argument, NULL, 0x0813 }, "Which pre-existing pids cgroup to use as a parent (default: 'NSJAIL')" },
+ { { "cgroup_net_cls_classid", required_argument, NULL, 0x0821 }, "Class identifier of network packets in the group (default: '0' - disabled)" },
+ { { "cgroup_net_cls_mount", required_argument, NULL, 0x0822 }, "Location of net_cls cgroup FS (default: '/sys/fs/cgroup/net_cls')" },
+ { { "cgroup_net_cls_parent", required_argument, NULL, 0x0823 }, "Which pre-existing net_cls cgroup to use as a parent (default: 'NSJAIL')" },
{ { "iface_no_lo", no_argument, NULL, 0x700 }, "Don't bring the 'lo' interface up" },
{ { "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\")" },
.cgroup_pids_mount = "/sys/fs/cgroup/pids",
.cgroup_pids_parent = "NSJAIL",
.cgroup_pids_max = (size_t)0,
+ .cgroup_net_cls_mount = "/sys/fs/cgroup/net_cls",
+ .cgroup_net_cls_parent = "NSJAIL",
+ .cgroup_net_cls_classid = (unsigned int)0,
.iface_no_lo = false,
.iface_vs = NULL,
.iface_vs_ip = "0.0.0.0",
case 0x813:
nsjconf->cgroup_pids_parent = optarg;
break;
+ case 0x821:
+ nsjconf->cgroup_net_cls_classid = (unsigned int)strtoul(optarg, NULL, 0);
+ break;
+ case 0x822:
+ nsjconf->cgroup_net_cls_mount = optarg;
+ break;
+ case 0x823:
+ nsjconf->cgroup_net_cls_parent = optarg;
+ break;
case 'P':
if ((nsjconf->kafel_file = fopen(optarg, "r")) == NULL) {
PLOG_F("Couldn't open '%s'", optarg);
nsjconf->cgroup_pids_max = njc.cgroup_pids_max();
nsjconf->cgroup_pids_mount = njc.cgroup_pids_mount().c_str();
nsjconf->cgroup_pids_parent = njc.cgroup_pids_parent().c_str();
+ nsjconf->cgroup_net_cls_classid = njc.cgroup_net_cls_classid();
+ nsjconf->cgroup_net_cls_mount = njc.cgroup_net_cls_mount().c_str();
+ nsjconf->cgroup_net_cls_parent = njc.cgroup_net_cls_parent().c_str();
nsjconf->iface_no_lo = njc.iface_no_lo();
nsjconf->iface_vs = DUP_IF_SET(njc, macvlan_iface);
/* Binary path (with arguments) to be executed. If not specified here, it
can be specified with cmd-line as "-- /path/to/command arg1 arg2" */
optional Exe exec_bin = 70;
+
+ /* If > 0, Class identifier of network packets inside jail */
+ optional uint32 cgroup_net_cls_classid = 71 [ default = 0 ];
+ /* Mount point for cgroups-net-cls in your system */
+ optional string cgroup_net_cls_mount = 72 [ default = "/sys/fs/cgroup/net_cls" ];
+ /* Writeable directory (for the nsjail user) under cgroup_net_mount */
+ optional string cgroup_net_cls_parent = 73 [ default = "NSJAIL" ];
}
const char* cgroup_pids_mount;
const char* cgroup_pids_parent;
size_t cgroup_pids_max;
+ const char* cgroup_net_cls_mount;
+ const char* cgroup_net_cls_parent;
+ unsigned int cgroup_net_cls_classid;
FILE* kafel_file;
char* kafel_string;
long num_cpus;