Skip to content

Commit 37b5acc

Browse files
committed
libct: use manager.AddPid to add exec to cgroup
The main benefit here is when we are using a systemd cgroup driver, we actually ask systemd to add a PID, rather than doing it ourselves. This way, we can add rootless exec PID to a cgroup. This requires newer opencontainers/cgroups and coreos/go-systemd. Signed-off-by: Kir Kolyshkin <[email protected]>
1 parent 5730a14 commit 37b5acc

File tree

12 files changed

+124
-25
lines changed

12 files changed

+124
-25
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ 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.4
17+
github.com/opencontainers/cgroups v0.0.5
1818
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0
1919
github.com/opencontainers/selinux v1.12.0
2020
github.com/seccomp/libseccomp-golang v0.11.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g
4444
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
4545
github.com/mrunalp/fileutils v0.5.1 h1:F+S7ZlNKnrwHfSwdlgNSkKo67ReVf8o9fel6C3dkm/Q=
4646
github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
47-
github.com/opencontainers/cgroups v0.0.4 h1:XVj8P/IHVms/j+7eh8ggdkTLAxjz84ZzuFyGoE28DR4=
48-
github.com/opencontainers/cgroups v0.0.4/go.mod h1:s8lktyhlGUqM7OSRL5P7eAW6Wb+kWPNvt4qvVfzA5vs=
47+
github.com/opencontainers/cgroups v0.0.5 h1:DRITAqcOnY0uSBzIpt1RYWLjh5DPDiqUs4fY6Y0ktls=
48+
github.com/opencontainers/cgroups v0.0.5/go.mod h1:oWVzJsKK0gG9SCRBfTpnn16WcGEqDI8PAcpMGbqWxcs=
4949
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0 h1:RLn0YfUWkiqPGtgUANvJrcjIkCHGRl3jcz/c557M28M=
5050
github.com/opencontainers/runtime-spec v1.2.2-0.20250818071321-383cadbf08c0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
5151
github.com/opencontainers/selinux v1.12.0 h1:6n5JV4Cf+4y0KNXW48TLj5DwfXpvWlxXplUkdTrmPb8=

libcontainer/container_linux_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ func (m *mockCgroupManager) Apply(pid int) error {
3232
return nil
3333
}
3434

35+
func (m *mockCgroupManager) AddPid(_ string, _ int) error {
36+
return nil
37+
}
38+
3539
func (m *mockCgroupManager) Set(_ *cgroups.Resources) error {
3640
return nil
3741
}

libcontainer/process_linux.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,18 @@ func (p *setnsProcess) setFinalCPUAffinity() error {
247247
}
248248

249249
func (p *setnsProcess) addIntoCgroupV1() error {
250+
if sub, ok := p.process.SubCgroupPaths[""]; ok || len(p.process.SubCgroupPaths) == 0 {
251+
// Either same sub-cgroup for all paths, or no sub-cgroup.
252+
err := p.manager.AddPid(sub, p.pid())
253+
if err != nil && !p.rootlessCgroups {
254+
return fmt.Errorf("error adding pid %d to cgroups: %w", p.pid(), err)
255+
}
256+
return nil
257+
}
258+
259+
// Per-controller sub-cgroup paths. Not supported by AddPid (or systemd),
260+
// so we have to calculate and check all sub-cgroup paths, and write
261+
// directly to cgroupfs.
250262
paths := maps.Clone(p.manager.GetPaths())
251263
for ctrl, sub := range p.process.SubCgroupPaths {
252264
base, ok := paths[ctrl]
@@ -255,7 +267,7 @@ func (p *setnsProcess) addIntoCgroupV1() error {
255267
}
256268
cgPath := path.Join(base, sub)
257269
if !strings.HasPrefix(cgPath, base) {
258-
return fmt.Errorf("%s is not a sub cgroup path", sub)
270+
return fmt.Errorf("bad sub cgroup path: %s", sub)
259271
}
260272
paths[ctrl] = cgPath
261273
}
@@ -270,18 +282,10 @@ func (p *setnsProcess) addIntoCgroupV1() error {
270282
}
271283

272284
func (p *setnsProcess) addIntoCgroupV2() error {
273-
base := p.manager.Path("")
274-
sub := ""
275-
if p.process.SubCgroupPaths != nil {
276-
sub = p.process.SubCgroupPaths[""]
277-
}
278-
cgPath := path.Join(base, sub)
279-
if !strings.HasPrefix(cgPath, base) {
280-
return fmt.Errorf("%s is not a sub cgroup path", sub)
281-
}
282-
283-
if err := cgroups.WriteCgroupProc(cgPath, p.pid()); err != nil && !p.rootlessCgroups {
284-
// On cgroup v2 + nesting + domain controllers, WriteCgroupProc may fail with EBUSY.
285+
sub := p.process.SubCgroupPaths[""]
286+
err := p.manager.AddPid(sub, p.pid())
287+
if err != nil && !p.rootlessCgroups {
288+
// On cgroup v2 + nesting + domain controllers, adding to initial cgroup may fail with EBUSY.
285289
// https://github.com/opencontainers/runc/issues/2356#issuecomment-621277643
286290
// Try to join the cgroup of InitProcessPid, unless sub-cgroup is explicitly set.
287291
if p.initProcessPid != 0 && sub == "" {
@@ -290,8 +294,8 @@ func (p *setnsProcess) addIntoCgroupV2() error {
290294
if initCgErr == nil {
291295
if initCgPath, ok := initCg[""]; ok {
292296
initCgDirpath := filepath.Join(fs2.UnifiedMountpoint, initCgPath)
293-
logrus.Debugf("adding pid %d to cgroup %s failed (%v), attempting to join %s",
294-
p.pid(), cgPath, err, initCgDirpath)
297+
logrus.Debugf("adding pid %d to cgroup failed (%v), attempting to join %s",
298+
p.pid(), err, initCgDirpath)
295299
// NOTE: initCgDirPath is not guaranteed to exist because we didn't pause the container.
296300
err = cgroups.WriteCgroupProc(initCgDirpath, p.pid())
297301
}

tests/integration/exec.bats

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,17 @@ function check_exec_debug() {
226226
# Check we can't join parent cgroup.
227227
runc exec --cgroup ".." test_busybox cat /proc/self/cgroup
228228
[ "$status" -ne 0 ]
229-
[[ "$output" == *" .. is not a sub cgroup path"* ]]
229+
[[ "$output" == *"bad sub cgroup path"* ]]
230230

231231
# Check we can't join non-existing subcgroup.
232232
runc exec --cgroup nonexistent test_busybox cat /proc/self/cgroup
233233
[ "$status" -ne 0 ]
234-
[[ "$output" == *" adding pid "*"/nonexistent/cgroup.procs: no such file "* ]]
234+
[[ "$output" == *" adding pid "*"o such file or directory"* ]]
235235

236236
# Check we can't join non-existing subcgroup (for a particular controller).
237237
runc exec --cgroup cpu:nonexistent test_busybox cat /proc/self/cgroup
238238
[ "$status" -ne 0 ]
239-
[[ "$output" == *" adding pid "*"/nonexistent/cgroup.procs: no such file "* ]]
239+
[[ "$output" == *" adding pid "*"o such file or directory"* ]]
240240

241241
# Check we can't specify non-existent controller.
242242
runc exec --cgroup whaaat:/ test_busybox true
@@ -277,12 +277,12 @@ function check_exec_debug() {
277277
# Check we can't join parent cgroup.
278278
runc exec --cgroup ".." test_busybox cat /proc/self/cgroup
279279
[ "$status" -ne 0 ]
280-
[[ "$output" == *" .. is not a sub cgroup path"* ]]
280+
[[ "$output" == *"bad sub cgroup path"* ]]
281281

282282
# Check we can't join non-existing subcgroup.
283283
runc exec --cgroup nonexistent test_busybox cat /proc/self/cgroup
284284
[ "$status" -ne 0 ]
285-
[[ "$output" == *" adding pid "*"/nonexistent/cgroup.procs: no such file "* ]]
285+
[[ "$output" == *" adding pid "*"o such file or directory"* ]]
286286

287287
# Check we can join top-level cgroup (implicit).
288288
runc exec test_busybox grep '^0::/$' /proc/self/cgroup
@@ -318,7 +318,7 @@ function check_exec_debug() {
318318
# Check that --cgroup / disables the init cgroup fallback.
319319
runc exec --cgroup / test_busybox true
320320
[ "$status" -ne 0 ]
321-
[[ "$output" == *" adding pid "*" to cgroups"*"/cgroup.procs: device or resource busy"* ]]
321+
[[ "$output" == *" adding pid "*" to cgroups"*"evice or resource busy"* ]]
322322

323323
# Check that explicit --cgroup foobar works.
324324
runc exec --cgroup foobar test_busybox grep '^0::/foobar$' /proc/self/cgroup

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

Lines changed: 5 additions & 0 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/fs.go

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

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

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

vendor/github.com/opencontainers/cgroups/systemd/common.go

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

vendor/github.com/opencontainers/cgroups/systemd/v1.go

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

0 commit comments

Comments
 (0)