From 5c21086f8976cd74bf11e011b1370cee012943e2 Mon Sep 17 00:00:00 2001 From: Robert Swiecki Date: Sun, 22 Mar 2026 21:21:18 +0100 Subject: [PATCH] oom_score_adj + simpler pasta port forwarding config --- cmdline.cc | 4 + config.proto | 140 ++++++++++++++-------------- configs/bash-with-fake-geteuid.cfg | 1 - configs/bash-with-fake-geteuid.json | 3 +- net.cc | 4 +- subproc.cc | 8 ++ tests/port-mappings.cfg | 1 - 7 files changed, 85 insertions(+), 76 deletions(-) diff --git a/cmdline.cc b/cmdline.cc index 5a2fdfa..9e56327 100644 --- a/cmdline.cc +++ b/cmdline.cc @@ -173,6 +173,7 @@ static const struct custom_option custom_opts[] = { { { "disable_tsc", no_argument, nullptr, 0x707 }, "Disable rdtsc and rdtscp instructions. WARNING: To make it effective, you also need to forbid `prctl(PR_SET_TSC, PR_TSC_ENABLE, ...)` in seccomp rules! (x86 and x86_64 only). Dynamic binaries produced by GCC seem to rely on RDTSC, but static ones should work." }, { { "forward_signals", no_argument, nullptr, 0x708 }, "Forward fatal signals to the child process instead of always using SIGKILL." }, { { "use_pasta", no_argument, nullptr, 0x709 }, "Use pasta (user-mode networking) to provide networking connectivity" }, + { { "oom_score_adj", required_argument, nullptr, 0x800 }, "OOM score adjustment for the sandbox (-1000 to 1000) (default: not set)" }, }; // clang-format on @@ -974,6 +975,9 @@ std::unique_ptr parseArgs(int argc, char* argv[]) { case 0x903: nsj->njc.set_nice_level((int)strtol(optarg, NULL, 0)); break; + case 0x800: + nsj->njc.set_oom_score_adj((int32_t)strtol(optarg, NULL, 0)); + break; default: cmdlineUsage(argv[0]); return nullptr; diff --git a/config.proto b/config.proto index b414ef9..182d05b 100644 --- a/config.proto +++ b/config.proto @@ -149,127 +149,129 @@ message NsJailConfig { * forbid `prctl(PR_SET_TSC, PR_TSC_ENABLE, ...)` in seccomp rules! (x86 and x86_64 only). * Dynamic binaries produced by GCC seem to rely on RDTSC, but static ones should work. */ optional bool disable_tsc = 28 [default = false]; + /* OOM score adjustment for the sandbox (-1000 to 1000) */ + optional int32 oom_score_adj = 29; /* Various rlimits, the rlimit_as/rlimit_core/... are used only if rlimit_as_type/rlimit_core_type/... are set to RLimit::VALUE */ - optional uint64 rlimit_as = 29 [default = 4096]; /* In MiB */ - optional RLimit rlimit_as_type = 30 [default = VALUE]; - optional uint64 rlimit_core = 31 [default = 0]; /* In MiB */ - optional RLimit rlimit_core_type = 32 [default = VALUE]; - optional uint64 rlimit_cpu = 33 [default = 600]; /* In seconds */ - optional RLimit rlimit_cpu_type = 34 [default = VALUE]; - optional uint64 rlimit_fsize = 35 [default = 1]; /* In MiB */ - optional RLimit rlimit_fsize_type = 36 [default = VALUE]; - optional uint64 rlimit_nofile = 37 [default = 32]; - optional RLimit rlimit_nofile_type = 38 [default = VALUE]; + optional uint64 rlimit_as = 30 [default = 4096]; /* In MiB */ + optional RLimit rlimit_as_type = 31 [default = VALUE]; + optional uint64 rlimit_core = 32 [default = 0]; /* In MiB */ + optional RLimit rlimit_core_type = 33 [default = VALUE]; + optional uint64 rlimit_cpu = 34 [default = 600]; /* In seconds */ + optional RLimit rlimit_cpu_type = 35 [default = VALUE]; + optional uint64 rlimit_fsize = 36 [default = 1]; /* In MiB */ + optional RLimit rlimit_fsize_type = 37 [default = VALUE]; + optional uint64 rlimit_nofile = 38 [default = 32]; + optional RLimit rlimit_nofile_type = 39 [default = VALUE]; /* RLIMIT_NPROC is system-wide - tricky to use; use the soft limit value by * default here */ - optional uint64 rlimit_nproc = 39 [default = 1024]; - optional RLimit rlimit_nproc_type = 40 [default = SOFT]; + optional uint64 rlimit_nproc = 40 [default = 1024]; + optional RLimit rlimit_nproc_type = 41 [default = SOFT]; /* In MiB, use the soft limit value by default */ - optional uint64 rlimit_stack = 41 [default = 8]; - optional RLimit rlimit_stack_type = 42 [default = SOFT]; + optional uint64 rlimit_stack = 42 [default = 8]; + optional RLimit rlimit_stack_type = 43 [default = SOFT]; /* In KB, use the soft limit value by default */ - optional uint64 rlimit_memlock = 43 [default = 64]; - optional RLimit rlimit_memlock_type = 44 [default = SOFT]; - optional uint64 rlimit_rtprio = 45 [default = 0]; - optional RLimit rlimit_rtprio_type = 46 [default = SOFT]; - optional uint64 rlimit_msgqueue = 47 [default = 1024]; /* In bytes */ - optional RLimit rlimit_msgqueue_type = 48 [default = SOFT]; + optional uint64 rlimit_memlock = 44 [default = 64]; + optional RLimit rlimit_memlock_type = 45 [default = SOFT]; + optional uint64 rlimit_rtprio = 46 [default = 0]; + optional RLimit rlimit_rtprio_type = 47 [default = SOFT]; + optional uint64 rlimit_msgqueue = 48 [default = 1024]; /* In bytes */ + optional RLimit rlimit_msgqueue_type = 49 [default = SOFT]; /* Disable all rlimits, default to limits set by parent */ - optional bool disable_rl = 49 [default = false]; + optional bool disable_rl = 50 [default = false]; /* See 'man personality' for more */ - optional bool persona_addr_compat_layout = 50 [default = false]; - optional bool persona_mmap_page_zero = 51 [default = false]; - optional bool persona_read_implies_exec = 52 [default = false]; - optional bool persona_addr_limit_3gb = 53 [default = false]; - optional bool persona_addr_no_randomize = 54 [default = false]; + optional bool persona_addr_compat_layout = 51 [default = false]; + optional bool persona_mmap_page_zero = 52 [default = false]; + optional bool persona_read_implies_exec = 53 [default = false]; + optional bool persona_addr_limit_3gb = 54 [default = false]; + optional bool persona_addr_no_randomize = 55 [default = false]; /* Which name-spaces should be used? */ - optional bool clone_newnet = 55 [default = true]; - optional bool clone_newuser = 56 [default = true]; - optional bool clone_newns = 57 [default = true]; - optional bool clone_newpid = 58 [default = true]; - optional bool clone_newipc = 59 [default = true]; - optional bool clone_newuts = 60 [default = true]; + optional bool clone_newnet = 56 [default = true]; + optional bool clone_newuser = 57 [default = true]; + optional bool clone_newns = 58 [default = true]; + optional bool clone_newpid = 59 [default = true]; + optional bool clone_newipc = 60 [default = true]; + optional bool clone_newuts = 61 [default = true]; /* Disable for kernel versions < 4.6 as it's not supported there */ - optional bool clone_newcgroup = 61 [default = true]; + optional bool clone_newcgroup = 62 [default = true]; /* Supported with kernel versions >= 5.3 */ - optional bool clone_newtime = 62 [default = false]; + optional bool clone_newtime = 63 [default = false]; /* Mappings for UIDs and GIDs. See the description for 'msg IdMap' for more */ - repeated IdMap uidmap = 63; - repeated IdMap gidmap = 64; + repeated IdMap uidmap = 64; + repeated IdMap gidmap = 65; /* Should /proc be mounted (R/O)? This can also be added in the 'mount' section below */ - optional bool mount_proc = 65 [default = false]; + optional bool mount_proc = 66 [default = false]; /* Mount points inside the jail. See the description for 'msg MountPt' for more */ - repeated MountPt mount = 66; + repeated MountPt mount = 67; /* Kafel seccomp-bpf policy file or a string: Homepage of the project: https://github.com/google/kafel */ - optional string seccomp_policy_file = 67; - repeated string seccomp_string = 68; + optional string seccomp_policy_file = 68; + repeated string seccomp_string = 69; /* Setting it to true makes audit write seccomp logs to dmesg */ - optional bool seccomp_log = 69 [default = false]; + optional bool seccomp_log = 70 [default = false]; /* If > 0, maximum cumulative size of RAM used inside any jail */ - optional uint64 cgroup_mem_max = 70 [default = 0]; /* In bytes */ + optional uint64 cgroup_mem_max = 71 [default = 0]; /* In bytes */ /* If > 0, maximum cumulative size of RAM + swap used inside any jail */ - optional uint64 cgroup_mem_memsw_max = 71 [default = 0]; /* In bytes */ + optional uint64 cgroup_mem_memsw_max = 72 [default = 0]; /* In bytes */ /* If >= 0, maximum cumulative size of swap used inside any jail */ - optional int64 cgroup_mem_swap_max = 72 [default = -1]; /* In bytes */ + optional int64 cgroup_mem_swap_max = 73 [default = -1]; /* In bytes */ /* Mount point for cgroups-memory in your system */ - optional string cgroup_mem_mount = 73 [default = "/sys/fs/cgroup/memory"]; + optional string cgroup_mem_mount = 74 [default = "/sys/fs/cgroup/memory"]; /* Writeable directory (for the nsjail user) under cgroup_mem_mount */ - optional string cgroup_mem_parent = 74 [default = "NSJAIL"]; + optional string cgroup_mem_parent = 75 [default = "NSJAIL"]; /* If > 0, maximum number of PIDs (threads/processes) inside jail */ - optional uint64 cgroup_pids_max = 75 [default = 0]; + optional uint64 cgroup_pids_max = 76 [default = 0]; /* Mount point for cgroups-pids in your system */ - optional string cgroup_pids_mount = 76 [default = "/sys/fs/cgroup/pids"]; + optional string cgroup_pids_mount = 77 [default = "/sys/fs/cgroup/pids"]; /* Writeable directory (for the nsjail user) under cgroup_pids_mount */ - optional string cgroup_pids_parent = 77 [default = "NSJAIL"]; + optional string cgroup_pids_parent = 78 [default = "NSJAIL"]; /* If > 0, Class identifier of network packets inside jail */ - optional uint32 cgroup_net_cls_classid = 78 [default = 0]; + optional uint32 cgroup_net_cls_classid = 79 [default = 0]; /* Mount point for cgroups-net-cls in your system */ - optional string cgroup_net_cls_mount = 79 [default = "/sys/fs/cgroup/net_cls"]; + optional string cgroup_net_cls_mount = 80 [default = "/sys/fs/cgroup/net_cls"]; /* Writeable directory (for the nsjail user) under cgroup_net_mount */ - optional string cgroup_net_cls_parent = 80 [default = "NSJAIL"]; + optional string cgroup_net_cls_parent = 81 [default = "NSJAIL"]; /* If > 0, number of milliseconds of CPU time per second that jailed processes can use */ - optional uint32 cgroup_cpu_ms_per_sec = 81 [default = 0]; + optional uint32 cgroup_cpu_ms_per_sec = 82 [default = 0]; /* Mount point for cgroups-cpu in your system */ - optional string cgroup_cpu_mount = 82 [default = "/sys/fs/cgroup/cpu"]; + optional string cgroup_cpu_mount = 83 [default = "/sys/fs/cgroup/cpu"]; /* Writeable directory (for the nsjail user) under cgroup_cpu_mount */ - optional string cgroup_cpu_parent = 83 [default = "NSJAIL"]; + optional string cgroup_cpu_parent = 84 [default = "NSJAIL"]; /* Mount point for cgroup v2 in your system */ - optional string cgroupv2_mount = 84 [default = "/sys/fs/cgroup"]; + optional string cgroupv2_mount = 85 [default = "/sys/fs/cgroup"]; /* Use cgroup v2 */ - optional bool use_cgroupv2 = 85 [default = false]; + optional bool use_cgroupv2 = 86 [default = false]; /* Check whether cgroupv2 is available, and use it if available. */ - optional bool detect_cgroupv2 = 86 [default = false]; + optional bool detect_cgroupv2 = 87 [default = false]; /* Should the 'lo' interface be brought up (active) inside this jail? */ - optional bool iface_no_lo = 87 [default = false]; + optional bool iface_no_lo = 88 [default = false]; /* Put this interface inside the jail */ - repeated string iface_own = 88; + repeated string iface_own = 89; /* Parameters for the cloned MACVLAN interface inside jail */ - optional string macvlan_iface = 89; /* Interface to be cloned, eg 'eth0' */ - optional string macvlan_vs_ip = 90 [default = "192.168.0.2"]; - optional string macvlan_vs_nm = 91 [default = "255.255.255.0"]; - optional string macvlan_vs_gw = 92 [default = "192.168.0.1"]; - optional string macvlan_vs_ma = 93 [default = ""]; - optional string macvlan_vs_mo = 94 [default = "private"]; + optional string macvlan_iface = 90; /* Interface to be cloned, eg 'eth0' */ + optional string macvlan_vs_ip = 91 [default = "192.168.0.2"]; + optional string macvlan_vs_nm = 92 [default = "255.255.255.0"]; + optional string macvlan_vs_gw = 93 [default = "192.168.0.1"]; + optional string macvlan_vs_ma = 94 [default = ""]; + optional string macvlan_vs_mo = 95 [default = "private"]; message UserNet { /* Enable User-Mode NAT (via pasta) */ @@ -307,8 +309,6 @@ message NsJailConfig { /* Enable IPv6 Router Advertisements in pasta */ optional bool enable_ip6_ra = 17 [default = false]; - /* Port mapping, doesn't require network interfaces/NAT */ - optional bool port_map = 20 [default = false]; /* Configure TCP port forwarding from host to namespace */ optional string tcp_map_in = 21 [default = "none"]; /* Configure UDP port forwarding from host to namespace */ @@ -318,9 +318,9 @@ message NsJailConfig { /* Configure UDP port forwarding from namespace to host */ optional string udp_map_out = 24 [default = "none"]; } - optional UserNet user_net = 95; + optional UserNet user_net = 96; /* 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 = 96; + optional Exe exec_bin = 97; } diff --git a/configs/bash-with-fake-geteuid.cfg b/configs/bash-with-fake-geteuid.cfg index 50a4186..58d1937 100644 --- a/configs/bash-with-fake-geteuid.cfg +++ b/configs/bash-with-fake-geteuid.cfg @@ -63,7 +63,6 @@ clone_newcgroup: true user_net { nat: true - port_map: true } uidmap { diff --git a/configs/bash-with-fake-geteuid.json b/configs/bash-with-fake-geteuid.json index 58c046b..c1f66d6 100644 --- a/configs/bash-with-fake-geteuid.json +++ b/configs/bash-with-fake-geteuid.json @@ -59,8 +59,7 @@ "cloneNewuts": true, "cloneNewcgroup": true, "userNet": { - "nat": true, - "portMap": true + "nat": true }, "uidmap": [ { diff --git a/net.cc b/net.cc index 1e7a925..68799bf 100644 --- a/net.cc +++ b/net.cc @@ -305,7 +305,7 @@ static void pastaProcess(nsj_t* nsj, int pid, int err_pipe) { argv.push_back(nsj->njc.user_net().udp_map_out().c_str()); } - if (nsj->njc.user_net().port_map() && !(nsj->njc.user_net().nat())) { + if (!(nsj->njc.user_net().nat())) { argv.push_back("--splice-only"); } @@ -397,7 +397,7 @@ static bool spawnPasta(nsj_t* nsj, int pid) { } bool initParent(nsj_t* nsj, int pid) { - if (nsj->njc.user_net().nat() || nsj->njc.user_net().port_map()) { + if (nsj->njc.has_user_net()) { if (!nsj->njc.clone_newnet()) { LOG_E("Support for User-Mode Networking requested (pasta) but CLONE_NEWNET " "is not enabled"); diff --git a/subproc.cc b/subproc.cc index 024a076..a9bf717 100644 --- a/subproc.cc +++ b/subproc.cc @@ -161,6 +161,14 @@ static const std::string concatArgs(const std::vector& argv) { } static void newProc(nsj_t* nsj, int netfd, int fd_in, int fd_out, int fd_err, int pipefd) { + if (nsj->njc.has_oom_score_adj()) { + std::string score = std::to_string(nsj->njc.oom_score_adj()); + if (!util::writeBufToFile( + "/proc/self/oom_score_adj", score.c_str(), score.length(), O_WRONLY)) { + LOG_W("Couldn't set /proc/self/oom_score_adj to '%s'", score.c_str()); + } + } + if (!contain::setupFD(nsj, fd_in, fd_out, fd_err)) { return; } diff --git a/tests/port-mappings.cfg b/tests/port-mappings.cfg index 7fac251..f9da708 100644 --- a/tests/port-mappings.cfg +++ b/tests/port-mappings.cfg @@ -23,7 +23,6 @@ envar: "PS1=[\\H:\\t:\\s-\\V:\\w]\\$ " skip_setsid: true user_net { - port_map: true tcp_map_in: "8888" udp_map_in: "8888" tcp_map_out: "2222:22"