cgroups: add support for CPU cgroup

This commit is contained in:
Robert Swiecki 2018-02-04 04:15:19 +01:00
parent 19ea0703f2
commit 3ee825c4aa
4 changed files with 88 additions and 6 deletions

View File

@ -153,6 +153,44 @@ static bool cgroupInitNsFromParentNetCls(struct nsjconf_t* nsjconf, pid_t pid) {
return true;
}
static bool cgroupInitNsFromParentCpu(struct nsjconf_t* nsjconf, pid_t pid) {
if (nsjconf->cgroup_cpu_ms_per_sec == 0U) {
return true;
}
char cpu_cgroup_path[PATH_MAX];
snprintf(cpu_cgroup_path, sizeof(cpu_cgroup_path), "%s/%s/NSJAIL.%d",
nsjconf->cgroup_cpu_mount, nsjconf->cgroup_cpu_parent, (int)pid);
LOG_D("Create '%s' for PID=%d", cpu_cgroup_path, (int)pid);
if (mkdir(cpu_cgroup_path, 0700) == -1 && errno != EEXIST) {
PLOG_E("mkdir('%s', 0700) failed", cpu_cgroup_path);
return false;
}
char fname[PATH_MAX];
char cpu_ms_per_sec_str[512];
snprintf(cpu_ms_per_sec_str, sizeof(cpu_ms_per_sec_str), "0x%x",
nsjconf->cgroup_cpu_ms_per_sec * 1000U);
snprintf(fname, sizeof(fname), "%s/cpu.cfs_quota_us", cpu_cgroup_path);
LOG_D("Setting '%s' to '%s'", fname, cpu_ms_per_sec_str);
if (!utilWriteBufToFile(
fname, cpu_ms_per_sec_str, strlen(cpu_ms_per_sec_str), O_WRONLY | O_CLOEXEC)) {
LOG_E("Could not update cpu quota");
return false;
}
char pid_str[512];
snprintf(pid_str, sizeof(pid_str), "%d", (int)pid);
snprintf(fname, sizeof(fname), "%s/tasks", cpu_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 cpu cgroup task list");
return false;
}
return true;
}
bool cgroupInitNsFromParent(struct nsjconf_t* nsjconf, pid_t pid) {
if (!cgroupInitNsFromParentMem(nsjconf, pid)) {
return false;
@ -163,6 +201,9 @@ bool cgroupInitNsFromParent(struct nsjconf_t* nsjconf, pid_t pid) {
if (!cgroupInitNsFromParentNetCls(nsjconf, pid)) {
return false;
}
if (!cgroupInitNsFromParentCpu(nsjconf, pid)) {
return false;
}
return true;
}
@ -194,6 +235,20 @@ void cgroupFinishFromParentPids(struct nsjconf_t* nsjconf, pid_t pid) {
return;
}
void cgroupFinishFromParentCpu(struct nsjconf_t* nsjconf, pid_t pid) {
if (nsjconf->cgroup_cpu_ms_per_sec == 0U) {
return;
}
char cpu_cgroup_path[PATH_MAX];
snprintf(cpu_cgroup_path, sizeof(cpu_cgroup_path), "%s/%s/NSJAIL.%d",
nsjconf->cgroup_cpu_mount, nsjconf->cgroup_cpu_parent, (int)pid);
LOG_D("Remove '%s'", cpu_cgroup_path);
if (rmdir(cpu_cgroup_path) == -1) {
PLOG_W("rmdir('%s') failed", cpu_cgroup_path);
}
return;
}
void cgroupFinishFromParentNetCls(struct nsjconf_t* nsjconf, pid_t pid) {
if (nsjconf->cgroup_net_cls_classid == 0U) {
return;
@ -212,6 +267,7 @@ void cgroupFinishFromParent(struct nsjconf_t* nsjconf, pid_t pid) {
cgroupFinishFromParentMem(nsjconf, pid);
cgroupFinishFromParentPids(nsjconf, pid);
cgroupFinishFromParentNetCls(nsjconf, pid);
cgroupFinishFromParentCpu(nsjconf, pid);
}
bool cgroupInitNs(void) { return true; }

View File

@ -131,6 +131,9 @@ struct custom_option custom_opts[] = {
{ { "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')" },
{ { "cgroup_cpu_ms_per_sec", required_argument, NULL, 0x0831 }, "Number of us that the process group can use per second (default: '0' - disabled)" },
{ { "cgroup_cpu_mount", required_argument, NULL, 0x0822 }, "Location of cpu cgroup FS (default: '/sys/fs/cgroup/net_cls')" },
{ { "cgroup_cpu_parent", required_argument, NULL, 0x0833 }, "Which pre-existing cpu 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\")" },
@ -364,6 +367,9 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf) {
.cgroup_net_cls_mount = "/sys/fs/cgroup/net_cls",
.cgroup_net_cls_parent = "NSJAIL",
.cgroup_net_cls_classid = (unsigned int)0,
.cgroup_cpu_mount = "/sys/fs/cgroup/cpu",
.cgroup_cpu_parent = "NSJAIL",
.cgroup_cpu_ms_per_sec = (unsigned int)0,
.iface_no_lo = false,
.iface_vs = NULL,
.iface_vs_ip = "0.0.0.0",
@ -740,6 +746,15 @@ bool cmdlineParse(int argc, char* argv[], struct nsjconf_t* nsjconf) {
case 0x823:
nsjconf->cgroup_net_cls_parent = optarg;
break;
case 0x831:
nsjconf->cgroup_cpu_ms_per_sec = (unsigned int)strtoul(optarg, NULL, 0);
break;
case 0x832:
nsjconf->cgroup_cpu_mount = optarg;
break;
case 0x833:
nsjconf->cgroup_cpu_parent = optarg;
break;
case 'P':
nsjconf->kafel_file_path = optarg;
if (access(nsjconf->kafel_file_path, R_OK) == -1) {

View File

@ -205,16 +205,24 @@ message NsJailConfig {
optional string cgroup_net_cls_mount = 66 [default = "/sys/fs/cgroup/net_cls"];
/* Writeable directory (for the nsjail user) under cgroup_net_mount */
optional string cgroup_net_cls_parent = 67 [default = "NSJAIL"];
/* If > 0 number of milliseconds of CPU that jail processes can use per each second */
optional uint32 cgroup_cpu_ms_per_sec = 68 [default = 0];
/* Mount point for cgroups-cpu in your system */
optional string cgroup_cpu_mount = 69 [default = "/sys/fs/cgroup/cpu"];
/* Writeable directory (for the nsjail user) under cgroup_cpu_mount */
optional string cgroup_cpu_parent = 70 [default = "NSJAIL"];
/* Should the 'lo' interface be brought up (active) inside this jail? */
optional bool iface_no_lo = 68 [default = false];
optional bool iface_no_lo = 71 [default = false];
/* Parameters for the cloned MACVLAN interface inside jail */
optional string macvlan_iface = 69; /* Interface to be cloned, eg 'eth0' */
optional string macvlan_vs_ip = 70 [default = "192.168.0.2"];
optional string macvlan_vs_nm = 71 [default = "255.255.255.0"];
optional string macvlan_vs_gw = 72 [default = "192.168.0.1"];
optional string macvlan_iface = 72; /* Interface to be cloned, eg 'eth0' */
optional string macvlan_vs_ip = 73 [default = "192.168.0.2"];
optional string macvlan_vs_nm = 74 [default = "255.255.255.0"];
optional string macvlan_vs_gw = 75 [default = "192.168.0.1"];
/* 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 = 73;
optional Exe exec_bin = 76;
}

View File

@ -174,6 +174,9 @@ struct nsjconf_t {
const char* cgroup_net_cls_mount;
const char* cgroup_net_cls_parent;
unsigned int cgroup_net_cls_classid;
const char* cgroup_cpu_mount;
const char* cgroup_cpu_parent;
unsigned int cgroup_cpu_ms_per_sec;
const char* kafel_file_path;
const char* kafel_string;
struct sock_fprog seccomp_fprog;