cmdline: implement affinity setting, to limit jailed process to n max cpus
This commit is contained in:
parent
dbdeba6ea4
commit
0e7393cccf
7
Makefile
7
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
|
||||
|
@ -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;
|
||||
|
1
common.h
1
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;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
84
cpu.c
Normal file
84
cpu.c
Normal file
@ -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 <sched.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
32
cpu.h
Normal file
32
cpu.h
Normal file
@ -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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
bool cpuInit(struct nsjconf_t *nsjconf);
|
||||
|
||||
#endif /* NS_CPU_H */
|
28
util.c
28
util.c
@ -24,6 +24,7 @@
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -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;
|
||||
}
|
||||
|
2
util.h
2
util.h
@ -23,6 +23,7 @@
|
||||
#define NS_UTIL_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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 */
|
||||
|
Loading…
Reference in New Issue
Block a user