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 <kolyshkin@gmail.com>
This commit is contained in:
Kir Kolyshkin
2025-07-25 17:34:35 -07:00
parent 5730a141f1
commit 37b5acc2d7
12 changed files with 124 additions and 25 deletions
+5
View File
@@ -29,6 +29,11 @@ type Manager interface {
// can be used to merely create a cgroup.
Apply(pid int) error
// AddPid adds a process with a given pid to an existing cgroup.
// The subcgroup argument is either empty, or a path relative to
// a cgroup under under the manager's cgroup.
AddPid(subcgroup string, pid int) error
// GetPids returns the PIDs of all processes inside the cgroup.
GetPids() ([]int, error)
+29
View File
@@ -4,6 +4,8 @@ import (
"errors"
"fmt"
"os"
"path"
"strings"
"sync"
"golang.org/x/sys/unix"
@@ -139,6 +141,33 @@ func (m *Manager) Apply(pid int) (retErr error) {
return retErr
}
// AddPid adds a process with a given pid to an existing cgroup.
// The subcgroup argument is either empty, or a path relative to
// a cgroup under under the manager's cgroup.
func (m *Manager) AddPid(subcgroup string, pid int) (retErr error) {
m.mu.Lock()
defer m.mu.Unlock()
c := m.cgroups
for _, dir := range m.paths {
path := path.Join(dir, subcgroup)
if !strings.HasPrefix(path, dir) {
return fmt.Errorf("bad sub cgroup path: %s", subcgroup)
}
if err := cgroups.WriteCgroupProc(path, pid); err != nil {
if isIgnorableError(c.Rootless, err) && c.Path == "" {
retErr = cgroups.ErrRootless
continue
}
return err
}
}
return retErr
}
func (m *Manager) Destroy() error {
m.mu.Lock()
defer m.mu.Unlock()
+13
View File
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/opencontainers/cgroups"
@@ -83,6 +84,18 @@ func (m *Manager) Apply(pid int) error {
return nil
}
// AddPid adds a process with a given pid to an existing cgroup.
// The subcgroup argument is either empty, or a path relative to
// a cgroup under under the manager's cgroup.
func (m *Manager) AddPid(subcgroup string, pid int) error {
path := filepath.Join(m.dirPath, subcgroup)
if !strings.HasPrefix(path, m.dirPath) {
return fmt.Errorf("bad sub cgroup path: %s", subcgroup)
}
return cgroups.WriteCgroupProc(path, pid)
}
func (m *Manager) GetPids() ([]int, error) {
return cgroups.GetPids(m.dirPath)
}
+15
View File
@@ -6,6 +6,7 @@ import (
"fmt"
"math"
"os"
"path"
"strconv"
"strings"
"sync"
@@ -208,6 +209,20 @@ func stopUnit(cm *dbusConnManager, unitName string) error {
return nil
}
func addPid(cm *dbusConnManager, unitName, subcgroup string, pid int) error {
absSubcgroup := subcgroup
if !path.IsAbs(absSubcgroup) {
absSubcgroup = "/" + subcgroup
}
if absSubcgroup != path.Clean(absSubcgroup) {
return fmt.Errorf("bad sub cgroup path: %s", subcgroup)
}
return cm.retryOnDisconnect(func(c *systemdDbus.Conn) error {
return c.AttachProcessesToUnit(context.TODO(), unitName, absSubcgroup, []uint32{uint32(pid)})
})
}
func resetFailedUnit(cm *dbusConnManager, name string) error {
return cm.retryOnDisconnect(func(c *systemdDbus.Conn) error {
return c.ResetFailedUnitContext(context.TODO(), name)
+19
View File
@@ -215,6 +215,25 @@ func (m *LegacyManager) Apply(pid int) error {
return nil
}
// AddPid adds a process with a given pid to an existing cgroup.
// The subcgroup argument is either empty, or a path relative to
// a cgroup under under the manager's cgroup.
func (m *LegacyManager) AddPid(subcgroup string, pid int) error {
m.mu.Lock()
defer m.mu.Unlock()
if err := addPid(m.dbus, getUnitName(m.cgroups), subcgroup, pid); err != nil {
return err
}
// Since systemd only joins controllers it knows, use cgroupfs for the rest.
fsMgr, err := fs.NewManager(m.cgroups, m.paths)
if err != nil {
return err
}
return fsMgr.AddPid(subcgroup, pid)
}
func (m *LegacyManager) Destroy() error {
m.mu.Lock()
defer m.mu.Unlock()
+10
View File
@@ -383,6 +383,16 @@ func cgroupFilesToChown() ([]string, error) {
return filesToChown, nil
}
// AddPid adds a process with a given pid to an existing cgroup.
// The subcgroup argument is either empty, or a path relative to
// a cgroup under under the manager's cgroup.
func (m *UnifiedManager) AddPid(subcgroup string, pid int) error {
m.mu.Lock()
defer m.mu.Unlock()
return addPid(m.dbus, getUnitName(m.cgroups), subcgroup, pid)
}
func (m *UnifiedManager) Destroy() error {
m.mu.Lock()
defer m.mu.Unlock()