From 315b3837b47f5aaf4c07658624d3014e8e9580b0 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Masaya Date: Wed, 25 Oct 2017 17:15:03 +0900 Subject: [PATCH 1/2] Support cgroup net_cls subsystem --- cgroup.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ cmdline.c | 15 +++++++++++++ config.cc | 3 +++ config.proto | 7 +++++++ nsjail.h | 3 +++ 5 files changed, 87 insertions(+) diff --git a/cgroup.c b/cgroup.c index 1faca88..b74b2cf 100644 --- a/cgroup.c +++ b/cgroup.c @@ -123,6 +123,46 @@ static bool cgroupInitNsFromParentPids(struct nsjconf_t* nsjconf, pid_t pid) 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) { @@ -131,6 +171,9 @@ bool cgroupInitNsFromParent(struct nsjconf_t* nsjconf, pid_t pid) if (cgroupInitNsFromParentPids(nsjconf, pid) == false) { return false; } + if (cgroupInitNsFromParentNetCls(nsjconf, pid) == false) { + return false; + } return true; } @@ -164,10 +207,26 @@ void cgroupFinishFromParentPids(struct nsjconf_t* nsjconf, pid_t pid) 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; } diff --git a/cmdline.c b/cmdline.c index 9430bf6..513236d 100644 --- a/cmdline.c +++ b/cmdline.c @@ -127,6 +127,9 @@ struct custom_option custom_opts[] = { { { "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\")" }, @@ -361,6 +364,9 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf) .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", @@ -732,6 +738,15 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf) 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); diff --git a/config.cc b/config.cc index 91fa959..cd73090 100644 --- a/config.cc +++ b/config.cc @@ -276,6 +276,9 @@ static bool configParseInternal(struct nsjconf_t* nsjconf, const nsjail::NsJailC 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); diff --git a/config.proto b/config.proto index 3c727f3..d364960 100644 --- a/config.proto +++ b/config.proto @@ -213,4 +213,11 @@ message NsJailConfig /* 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" ]; } diff --git a/nsjail.h b/nsjail.h index 2eb7459..107cbb8 100644 --- a/nsjail.h +++ b/nsjail.h @@ -158,6 +158,9 @@ struct nsjconf_t { 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; From 6338c7763663340d1db8abc91926a989d5c6b843 Mon Sep 17 00:00:00 2001 From: YAMAMOTO Masaya Date: Wed, 25 Oct 2017 17:56:14 +0900 Subject: [PATCH 2/2] Update documents --- README.md | 6 ++++++ nsjail.1 | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/README.md b/README.md index 948b5e0..c2bc14a 100644 --- a/README.md +++ b/README.md @@ -462,6 +462,12 @@ Options: Location of pids cgroup FS (default: '/sys/fs/cgroup/pids') --cgroup_pids_parent VALUE Which pre-existing pids cgroup to use as a parent (default: 'NSJAIL') + --cgroup_net_cls_classid VALUE + Class identifier of network packets in the group (default: '0' - disabled) + --cgroup_net_cls_mount VALUE + Location of net_cls cgroup FS (default: '/sys/fs/cgroup/net_cls') + --cgroup_net_cls_parent VALUE + Which pre-existing net_cls cgroup to use as a parent (default: 'NSJAIL') --iface_no_lo Don't bring up the 'lo' interface --macvlan_iface|-I VALUE diff --git a/nsjail.1 b/nsjail.1 index 2c56ab2..5064e68 100644 --- a/nsjail.1 +++ b/nsjail.1 @@ -220,6 +220,15 @@ Location of pids cgroup FS (default: '/sys/fs/cgroup/pids') \fB\-\-cgroup_pids_parent\fR VALUE Which pre\-existing pids cgroup to use as a parent (default: 'NSJAIL') .TP +\fB\-\-cgroup_net_cls_classid\fR VALUE +Class identifier of network packets in the group (default: '0' \- disabled) +.TP +\fB\-\-cgroup_net_cls_mount\fR VALUE +Location of net_cls cgroup FS (default: '/sys/fs/cgroup/net_cls') +.TP +\fB\-\-cgroup_net_cls_parent\fR VALUE +Which pre\-existing net_cls cgroup to use as a parent (default: 'NSJAIL') +.TP \fB\-\-iface_no_lo\fR Don't bring up the 'lo' interface .TP