Repository: opencontainers/runc
Pull request #3808 (2023-04-03 22:32:25)

[1.1] cgroups: cpuset: fix byte order while parsing cpuset range to bits
Better late than never, this is a backport of #3611 to release-1.1 branch. See the original PR for details.


kolyshkin: CI failure on CS9 is unrelated; need to backport commit 4d0a60ca7f47e06815f5ba6a44a217ec13ffdbdb; CI restarted.
kolyshkin: CI failure in CS9 is being fixed by #3806

Patch:
diff --git a/libcontainer/cgroups/systemd/cpuset.go b/libcontainer/cgroups/systemd/cpuset.go
index 83d10dd7..dd474cf1 100644
--- a/libcontainer/cgroups/systemd/cpuset.go
+++ b/libcontainer/cgroups/systemd/cpuset.go
@@ -51,5 +51,10 @@ func RangeToBits(str string) ([]byte, error) {
 		// do not allow empty values
 		return nil, errors.New("empty value")
 	}
+
+	// fit cpuset parsing order in systemd
+	for l, r := 0, len(ret)-1; l < r; l, r = l+1, r-1 {
+		ret[l], ret[r] = ret[r], ret[l]
+	}
 	return ret, nil
 }


Test patch:
diff --git a/libcontainer/cgroups/systemd/cpuset_test.go b/libcontainer/cgroups/systemd/cpuset_test.go
index 3030cba9..bda31a5b 100644
--- a/libcontainer/cgroups/systemd/cpuset_test.go
+++ b/libcontainer/cgroups/systemd/cpuset_test.go
@@ -22,13 +22,13 @@ func TestRangeToBits(t *testing.T) {
 		{in: "4-7", out: []byte{0xf0}},
 		{in: "0-7", out: []byte{0xff}},
 		{in: "0-15", out: []byte{0xff, 0xff}},
-		{in: "16", out: []byte{1, 0, 0}},
-		{in: "0-3,32-33", out: []byte{3, 0, 0, 0, 0x0f}},
+		{in: "16", out: []byte{0, 0, 1}},
+		{in: "0-3,32-33", out: []byte{0x0f, 0, 0, 0, 3}},
 		// extra spaces and tabs are ok
 		{in: "1, 2, 1-2", out: []byte{6}},
 		{in: "    , 1   , 3  ,  5-7,	", out: []byte{0xea}},
 		// somewhat large values
-		{in: "128-130,1", out: []byte{7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}},
+		{in: "128-130,1", out: []byte{2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7}},
 
 		{in: "-", isErr: true},
 		{in: "1-", isErr: true},
diff --git a/tests/integration/helpers.bash b/tests/integration/helpers.bash
index 05d94f7f..b102d3f3 100644
--- a/tests/integration/helpers.bash
+++ b/tests/integration/helpers.bash
@@ -455,6 +455,13 @@ function requires() {
 				skip_me=1
 			fi
 			;;
+		more_than_8_core)
+			local cpus
+			cpus=$(grep -c '^processor' /proc/cpuinfo)
+			if [ "$cpus" -le 8 ]; then
+				skip_me=1
+			fi
+			;;
 		*)
 			fail "BUG: Invalid requires $var."
 			;;
diff --git a/tests/integration/update.bats b/tests/integration/update.bats
index 01c69152..b7a44cb7 100644
--- a/tests/integration/update.bats
+++ b/tests/integration/update.bats
@@ -559,6 +559,33 @@ EOF
 	check_systemd_value "AllowedMemoryNodes" 1
 }
 
+@test "update cpuset cpus range via v2 unified map" {
+	# This test assumes systemd >= v244
+	[ $EUID -ne 0 ] && requires rootless_cgroup
+	requires systemd cgroups_v2 more_than_8_core cgroups_cpuset
+
+	update_config ' .linux.resources.unified |= {
+				"cpuset.cpus": "0-5",
+			}'
+	runc run -d --console-socket "$CONSOLE_SOCKET" test_update
+	[ "$status" -eq 0 ]
+
+	# check that the initial value was properly set
+	check_systemd_value "AllowedCPUs" "0-5"
+
+	runc update -r - test_update <<EOF
+{
+  "unified": {
+    "cpuset.cpus": "5-8"
+  }
+}
+EOF
+	[ "$status" -eq 0 ]
+
+	# check the updated systemd unit property, the value should not be affected by byte order
+	check_systemd_value "AllowedCPUs" "5-8"
+}
+
 @test "update rt period and runtime" {
 	[[ "$ROOTLESS" -ne 0 ]] && requires rootless_cgroup
 	requires cgroups_v1 cgroups_rt no_systemd