2016-06-19 18:47:28 +08:00
|
|
|
/*
|
|
|
|
|
|
|
|
nsjail - cgroup namespacing
|
|
|
|
-----------------------------------------
|
|
|
|
|
|
|
|
Copyright 2014 Google Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cgroup.h"
|
|
|
|
|
2016-06-19 21:50:25 +08:00
|
|
|
#include <errno.h>
|
2016-06-19 19:54:36 +08:00
|
|
|
#include <fcntl.h>
|
2017-10-18 20:27:34 +08:00
|
|
|
#include <limits.h>
|
2016-06-19 19:54:36 +08:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
#include "log.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
static bool cgroupInitNsFromParentMem(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-10-09 05:00:45 +08:00
|
|
|
if (nsjconf->cgroup_mem_max == (size_t)0) {
|
2016-06-19 19:54:36 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-06-19 20:58:18 +08:00
|
|
|
char mem_cgroup_path[PATH_MAX];
|
2016-06-19 21:50:25 +08:00
|
|
|
snprintf(mem_cgroup_path, sizeof(mem_cgroup_path), "%s/%s/NSJAIL.%d",
|
2017-10-09 05:00:45 +08:00
|
|
|
nsjconf->cgroup_mem_mount, nsjconf->cgroup_mem_parent, (int)pid);
|
2016-06-19 21:50:25 +08:00
|
|
|
LOG_D("Create '%s' for PID=%d", mem_cgroup_path, (int)pid);
|
|
|
|
if (mkdir(mem_cgroup_path, 0700) == -1 && errno != EEXIST) {
|
2016-06-19 20:58:18 +08:00
|
|
|
PLOG_E("mkdir('%s', 0711) failed", mem_cgroup_path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:54:36 +08:00
|
|
|
char fname[PATH_MAX];
|
2017-10-25 21:57:17 +08:00
|
|
|
char mem_max_str[512];
|
|
|
|
snprintf(mem_max_str, sizeof(mem_max_str), "%zu", nsjconf->cgroup_mem_max);
|
|
|
|
snprintf(fname, sizeof(fname), "%s/memory.limit_in_bytes", mem_cgroup_path);
|
|
|
|
LOG_D("Setting '%s' to '%s'", fname, mem_max_str);
|
|
|
|
if (!utilWriteBufToFile(fname, mem_max_str, strlen(mem_max_str), O_WRONLY | O_CLOEXEC)) {
|
|
|
|
LOG_E("Could not update memory cgroup max limit");
|
|
|
|
return false;
|
2016-06-19 19:54:36 +08:00
|
|
|
}
|
|
|
|
|
2016-06-20 00:40:16 +08:00
|
|
|
/*
|
|
|
|
* Use OOM-killer instead of making processes hang/sleep
|
|
|
|
*/
|
2016-06-19 22:39:41 +08:00
|
|
|
snprintf(fname, sizeof(fname), "%s/memory.oom_control", mem_cgroup_path);
|
2016-06-21 03:54:05 +08:00
|
|
|
LOG_D("Writting '0' '%s'", fname);
|
2017-10-19 20:56:45 +08:00
|
|
|
if (!utilWriteBufToFile(fname, "0", strlen("0"), O_WRONLY | O_CLOEXEC)) {
|
2016-06-19 22:39:41 +08:00
|
|
|
LOG_E("Could not update memory cgroup oom control");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-06-19 19:54:36 +08:00
|
|
|
char pid_str[512];
|
2016-06-19 21:50:25 +08:00
|
|
|
snprintf(pid_str, sizeof(pid_str), "%d", (int)pid);
|
2016-06-19 20:58:18 +08:00
|
|
|
snprintf(fname, sizeof(fname), "%s/tasks", mem_cgroup_path);
|
2016-06-19 22:41:26 +08:00
|
|
|
LOG_D("Adding PID='%s' to '%s'", pid_str, fname);
|
2017-10-19 20:56:45 +08:00
|
|
|
if (!utilWriteBufToFile(fname, pid_str, strlen(pid_str), O_WRONLY | O_CLOEXEC)) {
|
2016-06-19 19:54:36 +08:00
|
|
|
LOG_E("Could not update memory cgroup task list");
|
2016-06-19 18:47:28 +08:00
|
|
|
return false;
|
|
|
|
}
|
2016-06-19 19:54:36 +08:00
|
|
|
|
2016-06-19 21:50:25 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
static bool cgroupInitNsFromParentPids(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-10-25 21:50:24 +08:00
|
|
|
if (nsjconf->cgroup_pids_max == 0U) {
|
2017-04-20 23:48:20 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
char pids_cgroup_path[PATH_MAX];
|
|
|
|
snprintf(pids_cgroup_path, sizeof(pids_cgroup_path), "%s/%s/NSJAIL.%d",
|
2017-10-09 05:00:45 +08:00
|
|
|
nsjconf->cgroup_pids_mount, nsjconf->cgroup_pids_parent, (int)pid);
|
2017-04-20 23:48:20 +08:00
|
|
|
LOG_D("Create '%s' for PID=%d", pids_cgroup_path, (int)pid);
|
|
|
|
if (mkdir(pids_cgroup_path, 0700) == -1 && errno != EEXIST) {
|
|
|
|
PLOG_E("mkdir('%s', 0711) failed", pids_cgroup_path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
char fname[PATH_MAX];
|
2017-10-25 21:57:17 +08:00
|
|
|
char pids_max_str[512];
|
|
|
|
snprintf(pids_max_str, sizeof(pids_max_str), "%u", nsjconf->cgroup_pids_max);
|
|
|
|
snprintf(fname, sizeof(fname), "%s/pids.max", pids_cgroup_path);
|
|
|
|
LOG_D("Setting '%s' to '%s'", fname, pids_max_str);
|
|
|
|
if (!utilWriteBufToFile(fname, pids_max_str, strlen(pids_max_str), O_WRONLY | O_CLOEXEC)) {
|
|
|
|
LOG_E("Could not update pids cgroup max limit");
|
|
|
|
return false;
|
2017-04-20 23:48:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
char pid_str[512];
|
|
|
|
snprintf(pid_str, sizeof(pid_str), "%d", (int)pid);
|
|
|
|
snprintf(fname, sizeof(fname), "%s/tasks", pids_cgroup_path);
|
|
|
|
LOG_D("Adding PID='%s' to '%s'", pid_str, fname);
|
2017-10-19 20:56:45 +08:00
|
|
|
if (!utilWriteBufToFile(fname, pid_str, strlen(pid_str), O_WRONLY | O_CLOEXEC)) {
|
2017-04-20 23:48:20 +08:00
|
|
|
LOG_E("Could not update pids cgroup task list");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
static bool cgroupInitNsFromParentNetCls(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-10-25 21:50:24 +08:00
|
|
|
if (nsjconf->cgroup_net_cls_classid == 0U) {
|
2017-10-25 16:15:03 +08:00
|
|
|
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];
|
2017-10-25 21:57:17 +08:00
|
|
|
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;
|
2017-10-25 16:15:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
bool cgroupInitNsFromParent(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-04-20 23:48:20 +08:00
|
|
|
if (cgroupInitNsFromParentMem(nsjconf, pid) == false) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (cgroupInitNsFromParentPids(nsjconf, pid) == false) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-10-25 16:15:03 +08:00
|
|
|
if (cgroupInitNsFromParentNetCls(nsjconf, pid) == false) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-20 23:48:20 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
void cgroupFinishFromParentMem(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-10-09 05:00:45 +08:00
|
|
|
if (nsjconf->cgroup_mem_max == (size_t)0) {
|
2016-06-19 21:50:25 +08:00
|
|
|
return;
|
2016-06-19 20:25:41 +08:00
|
|
|
}
|
2016-06-19 21:50:25 +08:00
|
|
|
char mem_cgroup_path[PATH_MAX];
|
|
|
|
snprintf(mem_cgroup_path, sizeof(mem_cgroup_path), "%s/%s/NSJAIL.%d",
|
2017-10-09 05:00:45 +08:00
|
|
|
nsjconf->cgroup_mem_mount, nsjconf->cgroup_mem_parent, (int)pid);
|
2016-06-19 21:50:25 +08:00
|
|
|
LOG_D("Remove '%s'", mem_cgroup_path);
|
|
|
|
if (rmdir(mem_cgroup_path) == -1) {
|
|
|
|
PLOG_W("rmdir('%s') failed", mem_cgroup_path);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
void cgroupFinishFromParentPids(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-10-25 21:51:06 +08:00
|
|
|
if (nsjconf->cgroup_pids_max == 0U) {
|
2017-04-20 23:48:20 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
char pids_cgroup_path[PATH_MAX];
|
|
|
|
snprintf(pids_cgroup_path, sizeof(pids_cgroup_path), "%s/%s/NSJAIL.%d",
|
2017-10-09 05:00:45 +08:00
|
|
|
nsjconf->cgroup_pids_mount, nsjconf->cgroup_pids_parent, (int)pid);
|
2017-04-20 23:48:20 +08:00
|
|
|
LOG_D("Remove '%s'", pids_cgroup_path);
|
|
|
|
if (rmdir(pids_cgroup_path) == -1) {
|
|
|
|
PLOG_W("rmdir('%s') failed", pids_cgroup_path);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
void cgroupFinishFromParentNetCls(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-10-25 21:51:06 +08:00
|
|
|
if (nsjconf->cgroup_net_cls_classid == 0U) {
|
2017-10-25 16:15:03 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-10-26 06:26:02 +08:00
|
|
|
void cgroupFinishFromParent(struct nsjconf_t* nsjconf, pid_t pid) {
|
2017-04-20 23:48:20 +08:00
|
|
|
cgroupFinishFromParentMem(nsjconf, pid);
|
|
|
|
cgroupFinishFromParentPids(nsjconf, pid);
|
2017-10-25 16:15:03 +08:00
|
|
|
cgroupFinishFromParentNetCls(nsjconf, pid);
|
2017-04-20 23:48:20 +08:00
|
|
|
}
|
|
|
|
|
2017-10-17 21:22:23 +08:00
|
|
|
bool cgroupInitNs(void) { return true; }
|