Skip to content

Commit 996278a

Browse files
authored
Merge pull request #4949 from cyphar/pids-limit-0
runtime-spec: update pids.limit handling to match new guidance
2 parents eec1f7e + 8ab2458 commit 996278a

File tree

20 files changed

+316
-62
lines changed

20 files changed

+316
-62
lines changed

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
- The deprecated `libcontainer/userns` package has been removed; use
1111
`github.com/moby/sys/userns` instead.
1212

13+
### Breaking ###
14+
- The handling of `pids.limit` has been updated to match the newer guidance
15+
from the OCI runtime specification. In particular, now a maximum limit value
16+
of `0` will be treated as an actual limit (due to limitations with systemd,
17+
it will be treated the same as a limit value of `1`). We only expect users
18+
that explicitly set `pids.limit` to `0` will see a behaviour change.
19+
(opencontainers/cgroups#48, #4949)
20+
21+
### Fixed ###
22+
- cgroups: provide iocost statistics for cgroupv2. (opencontainers/cgroups#43)
23+
- cgroups: retry DBus connection when it fails with EAGAIN.
24+
(opencontainers/cgroups#45)
25+
- cgroups: improve `cpuacct.usage_all` resilience when parsing data from
26+
patched kernels (such as the Tencent kernels). (opencontainers/cgroups#46,
27+
opencontainers/cgroups#50)
28+
1329
## [1.4.0-rc.1] - 2025-09-05
1430

1531
> おめェもボスになったんだろぉ?

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ require (
1414
github.com/moby/sys/user v0.4.0
1515
github.com/moby/sys/userns v0.1.0
1616
github.com/mrunalp/fileutils v0.5.1
17-
github.com/opencontainers/cgroups v0.0.5
18-
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0
17+
github.com/opencontainers/cgroups v0.0.6
18+
github.com/opencontainers/runtime-spec v1.3.0
1919
github.com/opencontainers/selinux v1.13.0
2020
github.com/seccomp/libseccomp-golang v0.11.1
2121
github.com/sirupsen/logrus v1.9.3

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g
4646
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
4747
github.com/mrunalp/fileutils v0.5.1 h1:F+S7ZlNKnrwHfSwdlgNSkKo67ReVf8o9fel6C3dkm/Q=
4848
github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
49-
github.com/opencontainers/cgroups v0.0.5 h1:DRITAqcOnY0uSBzIpt1RYWLjh5DPDiqUs4fY6Y0ktls=
50-
github.com/opencontainers/cgroups v0.0.5/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs=
51-
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0 h1:RLn0YfUWkiqPGtgUANvJrcjIkCHGRl3jcz/c557M28M=
52-
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
49+
github.com/opencontainers/cgroups v0.0.6 h1:tfZFWTIIGaUUFImTyuTg+Mr5x8XRiSdZESgEBW7UxuI=
50+
github.com/opencontainers/cgroups v0.0.6/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs=
51+
github.com/opencontainers/runtime-spec v1.3.0 h1:YZupQUdctfhpZy3TM39nN9Ika5CBWT5diQ8ibYCRkxg=
52+
github.com/opencontainers/runtime-spec v1.3.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
5353
github.com/opencontainers/selinux v1.13.0 h1:Zza88GWezyT7RLql12URvoxsbLfjFx988+LGaWfbL84=
5454
github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s=
5555
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

libcontainer/integration/exec_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -526,20 +526,22 @@ func TestPidsSystemd(t *testing.T) {
526526
testPids(t, true)
527527
}
528528

529+
func mkPtr[T any](v T) *T { return &v }
530+
529531
func testPids(t *testing.T, systemd bool) {
530532
if testing.Short() {
531533
return
532534
}
533535

534536
config := newTemplateConfig(t, &tParam{systemd: systemd})
535-
config.Cgroups.Resources.PidsLimit = -1
537+
config.Cgroups.Resources.PidsLimit = mkPtr[int64](-1)
536538

537539
// Running multiple processes, expecting it to succeed with no pids limit.
538540
runContainerOk(t, config, "/bin/sh", "-c", "/bin/true | /bin/true | /bin/true | /bin/true")
539541

540542
// Enforce a permissive limit. This needs to be fairly hand-wavey due to the
541543
// issues with running Go binaries with pids restrictions (see below).
542-
config.Cgroups.Resources.PidsLimit = 64
544+
config.Cgroups.Resources.PidsLimit = mkPtr[int64](64)
543545
runContainerOk(t, config, "/bin/sh", "-c", `
544546
/bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | bin/true | /bin/true |
545547
/bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | bin/true | /bin/true |
@@ -548,7 +550,7 @@ func testPids(t *testing.T, systemd bool) {
548550

549551
// Enforce a restrictive limit. 64 * /bin/true + 1 * shell should cause
550552
// this to fail reliably.
551-
config.Cgroups.Resources.PidsLimit = 64
553+
config.Cgroups.Resources.PidsLimit = mkPtr[int64](64)
552554
out, _, err := runContainer(t, config, "/bin/sh", "-c", `
553555
/bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | bin/true | /bin/true |
554556
/bin/true | /bin/true | /bin/true | /bin/true | /bin/true | /bin/true | bin/true | /bin/true |

man/runc-update.8.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ stdin. If this option is used, all other options are ignored.
8585
(i.e. use unlimited swap).
8686

8787
**--pids-limit** _num_
88-
: Set the maximum number of processes allowed in the container.
88+
: Set the maximum number of processes allowed in the container. Use **-1** to
89+
unset the limit.
8990

9091
**--l3-cache-schema** _value_
9192
: Set the value for Intel RDT/CAT L3 cache schema.

tests/integration/cgroups.bats

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,37 @@ convert_hugetlb_size() {
324324
done
325325
}
326326

327+
# https://github.com/opencontainers/runc/issues/4014.
328+
@test "runc run (pids.limit=0 means 1)" {
329+
[ $EUID -ne 0 ] && requires rootless_cgroup
330+
requires cgroups_pids
331+
332+
set_cgroups_path
333+
update_config '.linux.resources.pids.limit = 0'
334+
335+
runc run -d --console-socket "$CONSOLE_SOCKET" test_pids
336+
[ "$status" -eq 0 ]
337+
# systemd doesn't support TasksMax=0 so runc will silently remap it to 1
338+
# (for consistency, we do this for systemd *and* cgroupfs).
339+
check_cgroup_value "pids.max" "1"
340+
check_systemd_value "TasksMax" "1"
341+
}
342+
343+
# https://github.com/opencontainers/runc/issues/4014.
344+
@test "runc run (pids.limit=-1 means unlimited)" {
345+
[ $EUID -ne 0 ] && requires rootless_cgroup
346+
requires cgroups_pids
347+
348+
set_cgroups_path
349+
update_config '.linux.resources.pids.limit = -1'
350+
351+
runc run -d --console-socket "$CONSOLE_SOCKET" test_pids
352+
[ "$status" -eq 0 ]
353+
check_cgroup_value "pids.max" "max"
354+
# systemd < v227 shows UINT64_MAX instead of "infinity".
355+
check_systemd_value "TasksMax" "infinity" "18446744073709551615"
356+
}
357+
327358
@test "runc run (cgroup v2 resources.unified only)" {
328359
requires root cgroups_v2
329360

tests/integration/update.bats

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,37 @@ EOF
327327
check_cpu_shares 100
328328
}
329329

330+
@test "update pids.limit" {
331+
[ $EUID -ne 0 ] && requires rootless_cgroup
332+
requires cgroups_pids
333+
334+
runc run -d --console-socket "$CONSOLE_SOCKET" test_update
335+
[ "$status" -eq 0 ]
336+
337+
check_cgroup_value "pids.max" 20
338+
check_systemd_value "TasksMax" 20
339+
340+
runc update test_update --pids-limit 12345
341+
[ "$status" -eq 0 ]
342+
343+
check_cgroup_value "pids.max" "12345"
344+
check_systemd_value "TasksMax" "12345"
345+
346+
runc update test_update --pids-limit -1
347+
[ "$status" -eq 0 ]
348+
349+
check_cgroup_value "pids.max" "max"
350+
# systemd < v227 shows UINT64_MAX instead of "infinity".
351+
check_systemd_value "TasksMax" "infinity" "18446744073709551615"
352+
353+
runc update test_update --pids-limit 0
354+
[ "$status" -eq 0 ]
355+
356+
# systemd doesn't support TasksMax=0 so runc will silently remap it to 1.
357+
check_cgroup_value "pids.max" "1"
358+
check_systemd_value "TasksMax" "1"
359+
}
360+
330361
@test "cpu burst" {
331362
[ $EUID -ne 0 ] && requires rootless_cgroup
332363
requires cgroups_cpu_burst

update.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@ import (
1717
"github.com/urfave/cli"
1818
)
1919

20-
func i64Ptr(i int64) *int64 { return &i }
21-
func u64Ptr(i uint64) *uint64 { return &i }
22-
func u16Ptr(i uint16) *uint16 { return &i }
23-
func boolPtr(b bool) *bool { return &b }
20+
func mkPtr[T any](v T) *T { return &v }
2421

2522
var updateCommand = cli.Command{
2623
Name: "update",
@@ -147,9 +144,9 @@ other options are ignored.
147144
}
148145

149146
r := specs.LinuxResources{
150-
// nil and u64Ptr(0) are not interchangeable
147+
// nil and mkPtr(0) are not interchangeable
151148
Memory: &specs.LinuxMemory{
152-
CheckBeforeUpdate: boolPtr(false), // constant
149+
CheckBeforeUpdate: mkPtr(false), // constant
153150
},
154151
CPU: &specs.LinuxCPU{},
155152
BlockIO: &specs.LinuxBlockIO{},
@@ -179,7 +176,7 @@ other options are ignored.
179176
}
180177
} else {
181178
if val := context.Int("blkio-weight"); val != 0 {
182-
r.BlockIO.Weight = u16Ptr(uint16(val))
179+
r.BlockIO.Weight = mkPtr(uint16(val))
183180
}
184181
if val := context.String("cpuset-cpus"); val != "" {
185182
r.CPU.Cpus = val
@@ -192,7 +189,7 @@ other options are ignored.
192189
if err != nil {
193190
return fmt.Errorf("invalid value for cpu-idle: %w", err)
194191
}
195-
r.CPU.Idle = i64Ptr(idle)
192+
r.CPU.Idle = mkPtr(idle)
196193
}
197194

198195
for _, pair := range []struct {
@@ -252,17 +249,19 @@ other options are ignored.
252249
}
253250
}
254251

255-
r.Pids.Limit = int64(context.Int("pids-limit"))
252+
if context.IsSet("pids-limit") {
253+
r.Pids.Limit = mkPtr(int64(context.Int("pids-limit")))
254+
}
256255
}
257256

258257
// Fix up values
259258
if r.Memory.Limit != nil && *r.Memory.Limit == -1 && r.Memory.Swap == nil {
260259
// To avoid error "unable to set swap limit without memory limit"
261-
r.Memory.Swap = i64Ptr(0)
260+
r.Memory.Swap = mkPtr[int64](0)
262261
}
263262
if r.CPU.Idle != nil && r.CPU.Shares == nil {
264263
// To avoid error "failed to write \"4\": write /sys/fs/cgroup/runc-cgroups-integration-test/test-cgroup-7341/cpu.weight: invalid argument"
265-
r.CPU.Shares = u64Ptr(0)
264+
r.CPU.Shares = mkPtr[uint64](0)
266265
}
267266

268267
if (r.Memory.Kernel != nil) || (r.Memory.KernelTCP != nil) { //nolint:staticcheck // Ignore SA1019. Need to keep deprecated package for compatibility.

vendor/github.com/opencontainers/cgroups/config_linux.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/opencontainers/cgroups/fs/cpuacct.go

Lines changed: 8 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)