Support cgroup net_cls subsystem
authorYAMAMOTO Masaya <pandax381@gmail.com>
Wed, 25 Oct 2017 08:15:03 +0000 (17:15 +0900)
committerYAMAMOTO Masaya <pandax381@gmail.com>
Wed, 25 Oct 2017 08:15:03 +0000 (17:15 +0900)
cgroup.c
cmdline.c
config.cc
config.proto
nsjail.h

index 1faca88a5d6af445ae9cd62c0700ca8ce1983619..b74b2cf40126adc0a50a389d1bc8d2026938ecdf 100644 (file)
--- 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; }
index 9430bf666587aa972018e0cda2bcc005f1dfd0e5..513236da4af608a9b4b854a3b1cd1ae07428d8de 100644 (file)
--- 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);
index 91fa959f27fe406c93ebde8715239c26205c6bdc..cd7309087f8357d1388331d4b468624313aaad52 100644 (file)
--- 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);
index 3c727f3cb1f18b4196277bb47f941fca6a449101..d364960a8089d1192433ef24de42beed759d3146 100644 (file)
@@ -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" ];
 }
index 2eb745926b2b46c54651d3d3e1deb65a777ae396..107cbb8a2d5f247ac7c0a3784c9f5fa55670b455 100644 (file)
--- 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;