From 3ed90ff18f0f7e2ed1a317e2336b1c41c86462ce Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Wed, 18 Aug 2021 20:36:37 -0700 Subject: [PATCH] runc run: refuse a frozen cgroup Sometimes a container cgroup already exists but is frozen. When this happens, runc init hangs, and it's not clear what is going on. Refuse to run in a frozen cgroup; add a test case. Signed-off-by: Kir Kolyshkin --- libcontainer/factory_linux.go | 11 +++++++++ tests/integration/cgroups.bats | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go index b11d21faceb..5ef1583b5cf 100644 --- a/libcontainer/factory_linux.go +++ b/libcontainer/factory_linux.go @@ -4,6 +4,7 @@ package libcontainer import ( "encoding/json" + "errors" "fmt" "os" "path/filepath" @@ -182,6 +183,16 @@ func (l *LinuxFactory) Create(id string, config *configs.Config) (Container, err } } + // Check that cgroup is not frozen. Do it even if Exists() above returned + // false, since in cgroup v1 it only checks "devices" controller. + st, err := cm.GetFreezerState() + if err != nil { + return nil, fmt.Errorf("unable to get cgroup freezer state: %w", err) + } + if st == configs.Frozen { + return nil, errors.New("container's cgroup unexpectedly frozen") + } + if err := os.MkdirAll(containerRoot, 0o711); err != nil { return nil, err } diff --git a/tests/integration/cgroups.bats b/tests/integration/cgroups.bats index a1182aadb6d..2a98ead5628 100644 --- a/tests/integration/cgroups.bats +++ b/tests/integration/cgroups.bats @@ -322,3 +322,44 @@ function setup() { [ "$status" -ne 0 ] [[ "$output" == *"container's cgroup is not empty"* ]] } + +@test "runc run/create should refule pre-existing frozen cgroup" { + requires cgroups_freezer + if [[ "$ROOTLESS" -ne 0 ]]; then + requires rootless_cgroup + fi + + set_cgroups_path + + case $CGROUP_UNIFIED in + no) + FREEZER_DIR="${CGROUP_FREEZER_BASE_PATH}/${REL_CGROUPS_PATH}" + FREEZER="${FREEZER_DIR}/freezer.state" + STATE="FROZEN" + ;; + yes) + FREEZER_DIR="${CGROUP_PATH}" + FREEZER="${FREEZER_DIR}/cgroup.freeze" + STATE="1" + ;; + esac + + # Create and freeze the cgroup. + mkdir "$FREEZER_DIR" + echo "$STATE" >"$FREEZER" + + # Start a container. + runc run -d --console-socket "$CONSOLE_SOCKET" ct1 + [ "$status" -eq 1 ] + # A warning should be printed. + [[ "$output" == *"container's cgroup unexpectedly frozen"* ]] + + # Same check for runc create. + runc create --console-socket "$CONSOLE_SOCKET" ct2 + [ "$status" -eq 1 ] + # A warning should be printed. + [[ "$output" == *"container's cgroup unexpectedly frozen"* ]] + + # Cleanup. + rmdir "$FREEZER_DIR" +}