Skip to content

Commit

Permalink
Add cgroupv2 initialisation
Browse files Browse the repository at this point in the history
Ensure the cgroupv2 mount exists, subtree_control is not empty, and
swap is disabled.

Fix #126
Fix #102
  • Loading branch information
MarkKoz committed Dec 20, 2021
1 parent 30e7a47 commit 0a78f7f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 6 deletions.
22 changes: 16 additions & 6 deletions snekbox/nsjail.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ def __init__(self, nsjail_binary: str = NSJAIL_PATH):
self.config = self._read_config()
self.cgroup_version = utils.cgroup.get_version(self.config)

if self.cgroup_version == 2:
utils.cgroup.init_v2(self.config)

log.info(f"Assuming cgroup version {self.cgroup_version}.")

@staticmethod
Expand Down Expand Up @@ -146,12 +149,18 @@ def python3(
`py_args` are arguments to pass to the Python subprocess before the code,
which is the last argument. By default, it's "-c", which executes the code given.
"""
cgroup = utils.cgroup.create_dynamic(self.config)
cgroup = None
if self.cgroup_version == 1:
cgroup = utils.cgroup.create_dynamic(self.config)
nsjail_args = (
"--cgroup_mem_parent", cgroup,
"--cgroup_pids_parent", cgroup,
*nsjail_args,
)
else:
nsjail_args = ("--use_cgroupv2", *nsjail_args)

with NamedTemporaryFile() as nsj_log:
if self.cgroup_version == 2:
nsjail_args = (["--use_cgroupv2"]).extend(nsjail_args)

args = (
self.nsjail_binary,
"--config", NSJAIL_CFG,
Expand Down Expand Up @@ -201,7 +210,8 @@ def python3(
log.info(f"nsjail return code: {returncode}")

# Remove the dynamically created cgroups once we're done
Path(self.config.cgroup_mem_mount, cgroup).rmdir()
Path(self.config.cgroup_pids_mount, cgroup).rmdir()
if self.cgroup_version == 1:
Path(self.config.cgroup_mem_mount, cgroup).rmdir()
Path(self.config.cgroup_pids_mount, cgroup).rmdir()

return CompletedProcess(args, returncode, output, None)
30 changes: 30 additions & 0 deletions snekbox/utils/cgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,33 @@ def get_version(config: NsJailConfig) -> int:
"Falling back to the use_cgroupv2 NsJail setting."
)
return config_version


def init_v2(config: NsJailConfig) -> None:
"""Ensure cgroupv2 children have controllers enabled and memory swapping is disabled."""
cgroup_mount = Path(config.cgroupv2_mount)

# Swap has to be disabled since NsJail doesn't do it.
(cgroup_mount / "memory.swap.max").write_text("0")

# If the root's subtree_control already has some controllers enabled,
# no further action is necessary.
if (cgroup_mount / "cgroup.subtree_control").read_text().strip():
return

# Move all processes from the cgroupv2 mount to a child cgroup.
# This is necessary to be able to write to subtree_control in the parent later.
# Otherwise, a write operation would yield a "device or resource busy" error.
init_cgroup = cgroup_mount / "init"
init_cgroup.mkdir(parents=True, exist_ok=True)

procs = (cgroup_mount / "cgroup.procs").read_text().split()
for proc in procs:
(init_cgroup / "cgroup.procs").write_text(proc)

# Enable all available controllers for child cgroups.
# This also retroactively enables controllers for children that already exist,
# including the "init" child created just before.
controllers = (cgroup_mount / "cgroup.controllers").read_text().split()
for controller in controllers:
(cgroup_mount / "cgroup.subtree_control").write_text(f"+{controller}")

0 comments on commit 0a78f7f

Please sign in to comment.