From 0e7393cccfbf42fd003cd9f25c12c58b22ed9d99 Mon Sep 17 00:00:00 2001 From: Robert Swiecki Date: Mon, 19 Jun 2017 17:01:50 +0200 Subject: [PATCH] cmdline: implement affinity setting, to limit jailed process to n max cpus --- Makefile | 7 +++-- cmdline.c | 5 ++++ common.h | 1 + contain.c | 9 ++++++ cpu.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ cpu.h | 32 +++++++++++++++++++++ util.c | 28 +++++++++++++++++++ util.h | 2 ++ 8 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 cpu.c create mode 100644 cpu.h diff --git a/Makefile b/Makefile index 67a1992..437e755 100644 --- a/Makefile +++ b/Makefile @@ -28,11 +28,11 @@ CFLAGS += -O2 -c -std=gnu11 \ -Wall -Wextra -Werror \ -Ikafel/include -LDFLAGS += -Wl,-z,now -Wl,-z,relro -pie -Wl,-z,noexecstack +LDFLAGS += -Wl,-z,now -Wl,-z,relro -pie -Wl,-z,noexecstack -lpthread BIN = nsjail LIBS = kafel/libkafel.a -SRCS = nsjail.c cmdline.c config.c contain.c log.c cgroup.c mount.c net.c pid.c sandbox.c subproc.c user.c util.c uts.c +SRCS = nsjail.c cmdline.c config.c contain.c log.c cgroup.c mount.c net.c pid.c sandbox.c subproc.c user.c util.c uts.c cpu.c OBJS = $(SRCS:.c=.o) ifdef DEBUG @@ -139,7 +139,7 @@ indent: nsjail.o: nsjail.h common.h cmdline.h log.h net.h subproc.h cmdline.o: cmdline.h common.h config.h log.h mount.h util.h user.h config.o: common.h config.h log.h mount.h user.h util.h -contain.o: contain.h common.h cgroup.h log.h mount.h net.h pid.h user.h +contain.o: contain.h common.h cgroup.h cpu.h log.h mount.h net.h pid.h user.h contain.o: util.h uts.h log.o: log.h common.h cgroup.o: cgroup.h common.h log.h util.h @@ -152,3 +152,4 @@ subproc.o: util.h user.o: user.h common.h log.h subproc.h util.h util.o: util.h common.h log.h uts.o: uts.h common.h log.h +cpu.o: cpu.h common.h log.h util.h diff --git a/cmdline.c b/cmdline.c index 4f61380..ff14f32 100644 --- a/cmdline.c +++ b/cmdline.c @@ -79,6 +79,7 @@ struct custom_option custom_opts[] = { {{"log", required_argument, NULL, 'l'}, "Log file (default: use log_fd)"}, {{"log_fd", required_argument, NULL, 'L'}, "Log FD (default: 2)"}, {{"time_limit", required_argument, NULL, 't'}, "Maximum time that a jail can exist, in seconds (default: 600)"}, + {{"max_cpu_num", required_argument, NULL, 0x508}, "Maximum number of CPUs a single jailed process can use (default: 0 'no limit')"}, {{"daemon", no_argument, NULL, 'd'}, "Daemonize after start"}, {{"verbose", no_argument, NULL, 'v'}, "Verbose output"}, {{"quiet", no_argument, NULL, 'q'}, "Only output warning and more important messages"}, @@ -314,6 +315,7 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) .loglevel = INFO, .daemonize = false, .tlimit = 0, + .max_cpu_num = 0, .keep_caps = false, .disable_no_new_privs = false, .rl_as = 512 * (1024 * 1024), @@ -535,6 +537,9 @@ bool cmdlineParse(int argc, char *argv[], struct nsjconf_t * nsjconf) case 0x0507: nsjconf->disable_no_new_privs = true; break; + case 0x0508: + nsjconf->max_cpu_num = strtoul(optarg, NULL, 0); + break; case 0x0601: nsjconf->is_root_rw = true; break; diff --git a/common.h b/common.h index f848a7c..1e8c8d2 100644 --- a/common.h +++ b/common.h @@ -124,6 +124,7 @@ struct nsjconf_t { enum llevel_t loglevel; bool daemonize; time_t tlimit; + size_t max_cpu_num; bool keep_env; bool keep_caps; bool disable_no_new_privs; diff --git a/contain.c b/contain.c index 2e51a6a..938fd18 100644 --- a/contain.c +++ b/contain.c @@ -43,6 +43,7 @@ #include #include "cgroup.h" +#include "cpu.h" #include "log.h" #include "mount.h" #include "net.h" @@ -168,6 +169,11 @@ static bool containInitMountNs(struct nsjconf_t *nsjconf) return mountInitNs(nsjconf); } +static bool containCPU(struct nsjconf_t *nsjconf) +{ + return cpuInit(nsjconf); +} + static bool containSetLimits(struct nsjconf_t *nsjconf) { struct rlimit64 rl; @@ -351,6 +357,9 @@ bool containSetupFD(struct nsjconf_t * nsjconf, int fd_in, int fd_out, int fd_er bool containContain(struct nsjconf_t * nsjconf) { + if (containCPU(nsjconf) == false) { + return false; + } if (containUserNs(nsjconf) == false) { return false; } diff --git a/cpu.c b/cpu.c new file mode 100644 index 0000000..ba3f417 --- /dev/null +++ b/cpu.c @@ -0,0 +1,84 @@ +/* + + nsjail - CLONE_NEWUTS routines + ----------------------------------------- + + 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 "cpu.h" + +#include +#include +#include + +#include "log.h" +#include "util.h" + +static void cpuSetRandomCpu(cpu_set_t * mask, size_t mask_size, size_t cpu_num) +{ + if ((size_t) CPU_COUNT_S(mask_size, mask) >= cpu_num) { + LOG_F + ("Number of CPUs in the mask '%d' is bigger than number of available CPUs '%zu'", + CPU_COUNT(mask), cpu_num); + } + + for (;;) { + uint64_t n = utilRnd64() % cpu_num; + if (!CPU_ISSET_S(n, mask_size, mask)) { + CPU_SET_S(n, mask_size, mask); + break; + } + } +} + +bool cpuInit(struct nsjconf_t *nsjconf) +{ + long all_cpus = sysconf(_SC_NPROCESSORS_ONLN); + if (all_cpus < 0) { + PLOG_W("sysconf(_SC_NPROCESSORS_ONLN) returned %ld", all_cpus); + return false; + } + if (nsjconf->max_cpu_num >= (size_t) all_cpus) { + LOG_D("Requested number of CPUs '%zu' is bigger that CPUs online '%ld'", + nsjconf->max_cpu_num, all_cpus); + return true; + } + if (nsjconf->max_cpu_num == 0) { + LOG_D("No max_cpu_num limit set"); + return true; + } + + cpu_set_t *mask = CPU_ALLOC(all_cpus); + if (mask == NULL) { + PLOG_W("Failure allocating cpu_set_t for %ld CPUs", all_cpus); + return false; + } + + size_t mask_size = CPU_ALLOC_SIZE(all_cpus); + CPU_ZERO_S(mask_size, mask); + + for (size_t i = 0; i < nsjconf->max_cpu_num; i++) { + cpuSetRandomCpu(mask, mask_size, all_cpus); + } + + if (sched_setaffinity(0, mask_size, mask) == -1) { + PLOG_W("sched_setaffinity(max_cpu_num=%zu) failed", nsjconf->max_cpu_num); + return false; + } + + return true; +} diff --git a/cpu.h b/cpu.h new file mode 100644 index 0000000..fb59171 --- /dev/null +++ b/cpu.h @@ -0,0 +1,32 @@ +/* + + nsjail - CPU affinity + ----------------------------------------- + + 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. + +*/ + +#ifndef NS_CPU_H +#define NS_CPU_H + +#include +#include + +#include "common.h" + +bool cpuInit(struct nsjconf_t *nsjconf); + +#endif /* NS_CPU_H */ diff --git a/util.c b/util.c index 0132d7c..37b9e86 100644 --- a/util.c +++ b/util.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -213,3 +214,30 @@ bool utilIsANumber(const char *s) } return true; } + +static __thread pthread_once_t rndThreadOnce = PTHREAD_ONCE_INIT; +static __thread uint64_t rndX; + +/* MMIX LCG PRNG */ +static const uint64_t a = 6364136223846793005ULL; +static const uint64_t c = 1442695040888963407ULL; + +static void utilRndInitThread(void) +{ + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + if (fd == -1) { + PLOG_F("Couldn't open /dev/urandom for reading"); + } + if (utilReadFromFd(fd, (uint8_t *) & rndX, sizeof(rndX)) != sizeof(rndX)) { + PLOG_F("Couldn't read '%zu' bytes from /dev/urandom", sizeof(rndX)); + close(fd); + } + close(fd); +} + +uint64_t utilRnd64(void) +{ + pthread_once(&rndThreadOnce, utilRndInitThread); + rndX = a * rndX + c; + return rndX; +} diff --git a/util.h b/util.h index 2015f21..e65ab40 100644 --- a/util.h +++ b/util.h @@ -23,6 +23,7 @@ #define NS_UTIL_H #include +#include #include #include "common.h" @@ -38,5 +39,6 @@ bool utilWriteBufToFile(const char *filename, const void *buf, size_t len, int o bool utilCreateDirRecursively(const char *dir); int utilSSnPrintf(char *str, size_t size, const char *format, ...); bool utilIsANumber(const char *s); +uint64_t utilRnd64(void); #endif /* NS_UTIL_H */