cgroup&container: add ability to utilize cgroup fd with clone3

#13
This commit is contained in:
criyle 2025-02-20 20:29:20 +00:00
parent f15b953065
commit d32acd7591
7 changed files with 47 additions and 2 deletions

View File

@ -35,6 +35,7 @@ var (
timeLimit, realTimeLimit, memoryLimit, outputLimit, stackLimit uint64
inputFileName, outputFileName, errorFileName, workPath, runt string
useCGroupFd bool
pType, result string
args []string
)
@ -65,6 +66,7 @@ func main() {
flag.Var(&addRawReadable, "add-readable-raw", "Add a readable file (don't transform to its real path)")
flag.Var(&addRawWritable, "add-writable-raw", "Add a writable file (don't transform to its real path)")
flag.BoolVar(&useCGroup, "cgroup", false, "Use cgroup to colloct resource usage")
flag.BoolVar(&useCGroupFd, "cgroupfd", false, "Use cgroup FD to clone3 (cgroup v2 & kernel > 5.7)")
flag.BoolVar(&memfile, "memfd", false, "Use memfd as exec file")
flag.StringVar(&runt, "runner", "ptrace", "Runner for the program (ptrace, ns, container)")
flag.BoolVar(&cred, "cred", false, "Generate credential for containers (uid=10000)")
@ -145,6 +147,8 @@ func start() (*runner.Result, error) {
var (
r runner.Runner
cg cgroup.Cgroup
cgDir *os.File
cgroupFd uintptr
err error
execFile uintptr
rt runner.Result
@ -206,6 +210,18 @@ func start() (*runner.Result, error) {
if err = cg.SetMemoryLimit(memoryLimit << 20); err != nil {
return nil, err
}
debug("cgroup:", cg)
if useCGroupFd {
debug("use cgroup fd")
if t != cgroup.TypeV2 {
return nil, fmt.Errorf("use cgroup fd cannot be enabled without cgroup v2")
}
if cgDir, err = cg.Open(); err != nil {
return nil, err
}
defer cgDir.Close()
cgroupFd = cgDir.Fd()
}
}
syncFunc := func(pid int) error {
@ -332,7 +348,8 @@ func start() (*runner.Result, error) {
RLimits: rlims.PrepareRLimit(),
Seccomp: filter,
SyncFunc: syncFunc,
SyncAfterExec: cg == nil,
CgroupFD: cgroupFd,
SyncAfterExec: cg == nil || cgDir != nil,
},
}
} else if runt == "ns" {

View File

@ -14,6 +14,7 @@ func (c *containerServer) handleExecve(cmd *execCmd, msg unixsocket.Msg) error {
var (
files []uintptr
execFile uintptr
cgroupFd uintptr
cred *syscall.Credential
)
if cmd == nil {
@ -35,6 +36,14 @@ func (c *containerServer) handleExecve(cmd *execCmd, msg unixsocket.Msg) error {
execFile = files[0]
files = files[1:]
}
// if cgroupFd, then the cgroupFd follows
if cmd.FdCgroup {
if len(files) == 0 {
return c.sendErrorReply("handle: expected cgroup fd")
}
cgroupFd = files[0]
files = files[1:]
}
var env []string
env = append(env, c.defaultEnv...)
@ -99,8 +108,9 @@ func (c *containerServer) handleExecve(cmd *execCmd, msg unixsocket.Msg) error {
Credential: cred,
CTTY: cmd.CTTY,
Seccomp: seccomp,
CgroupFd: cgroupFd,
UnshareCgroupAfterSync: c.UnshareCgroup,
UnshareCgroupAfterSync: c.UnshareCgroup && !cmd.SyncAfter,
}
// starts the runner, error is handled same as wait4 to make communication equal
pid, err := r.Start()

View File

@ -25,6 +25,9 @@ type ExecveParam struct {
// ExecFile specifies file descriptor for executable file using fexecve
ExecFile uintptr
// CgroupFD specifies file descriptor for cgroup V2
CgroupFD uintptr
// RLimits specifies POSIX Resource limit through setrlimit
RLimits []rlimit.RLimit
@ -54,6 +57,9 @@ func (c *container) Execve(ctx context.Context, param ExecveParam) runner.Result
if param.ExecFile > 0 {
files = append(files, int(param.ExecFile))
}
if param.CgroupFD > 0 {
files = append(files, int(param.CgroupFD))
}
files = append(files, uintptrSliceToInt(param.Files)...)
msg := unixsocket.Msg{
Fds: files,

View File

@ -41,6 +41,7 @@ type execCmd struct {
RLimits []rlimit.RLimit // execve posix rlimit
Seccomp seccomp.Filter // seccomp filter
FdExec bool // if use fexecve (fd[0] as exec)
FdCgroup bool // if use cgroupFd
CTTY bool // if set CTTY
SyncAfter bool // if sync function calls after execve returns
}

View File

@ -56,6 +56,9 @@ type Cgroup interface {
// Random creates a sub-cgroup based on the existing one but the name is randomly generated
Random(string) (Cgroup, error)
// Open opens the cgroup directory on V2 (used for clone3)
Open() (*os.File, error)
}
// DetectedCgroupType defines the current cgroup type of the system

View File

@ -26,6 +26,10 @@ type V1 struct {
existing bool
}
func (c *V1) Open() (*os.File, error) {
return nil, ErrNotInitialized
}
func (c *V1) String() string {
names := make([]string, 0, numberOfControllers)
for _, v := range []struct {

View File

@ -21,6 +21,10 @@ type V2 struct {
var _ Cgroup = &V2{}
func (c *V2) Open() (*os.File, error) {
return os.OpenFile(c.path, 0, dirPerm)
}
func (c *V2) String() string {
ct, _ := getAvailableControllerV2path(path.Join(c.path, cgroupControllers))
return "v2(" + c.path + ")" + ct.String()