mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-09-18 23:52:39 +02:00
121 lines
3.3 KiB
Go
121 lines
3.3 KiB
Go
//go:build linux
|
|
|
|
package processguard
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestCgroupContainsSetsidAndAppliesLimits(t *testing.T) {
|
|
opts := testOptions()
|
|
if opts.CgroupRoot == "" {
|
|
t.Skip("set CSAI_TEST_CGROUP_ROOT to a delegated cgroup v2 root")
|
|
}
|
|
opts.Mode = "required"
|
|
opts.CPUQuotaMicros = 50000
|
|
id := testID()
|
|
g, err := NewWithOptions(id, opts)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer closeTestGroup(t, g)
|
|
file := filepath.Join(t.TempDir(), "escaped")
|
|
cmd, err := startTestCommand(g, fmt.Sprintf("setsid sh -c 'echo $$ > %s; exec sleep 300' </dev/null >/dev/null 2>&1 &", file))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
reaped := make(chan struct{})
|
|
go func() { _ = cmd.Wait(); close(reaped) }()
|
|
pid := readPID(t, file)
|
|
<-reaped // The launching shell is gone; the cgroup must still own setsid descendants.
|
|
root := filepath.Join(opts.CgroupRoot, "task-"+id)
|
|
for name, want := range map[string]string{"pids.max": "64", "memory.max": "268435456", "cpu.max": "50000 100000"} {
|
|
data, err := os.ReadFile(filepath.Join(root, name))
|
|
if err != nil || strings.TrimSpace(string(data)) != want {
|
|
t.Fatalf("%s=%s err=%v", name, data, err)
|
|
}
|
|
}
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
if err = g.Close(ctx); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
<-reaped
|
|
waitGone(t, pid)
|
|
if _, err = os.Stat(root); !os.IsNotExist(err) {
|
|
t.Fatalf("cgroup retained after cleanup: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCgroupStartupDelegationAndRecovery(t *testing.T) {
|
|
opts := testOptions()
|
|
if opts.CgroupRoot == "" {
|
|
t.Skip("requires delegated cgroup fixture")
|
|
}
|
|
before, err := os.ReadFile("/proc/self/cgroup")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
original := ""
|
|
for _, line := range strings.Split(string(before), "\n") {
|
|
if strings.HasPrefix(line, "0::") {
|
|
original = filepath.Join("/sys/fs/cgroup", strings.TrimPrefix(line, "0::"))
|
|
}
|
|
}
|
|
root := filepath.Join(opts.CgroupRoot, "startup-fixture")
|
|
if err = os.Mkdir(root, 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err = os.WriteFile(filepath.Join(root, "cgroup.procs"), []byte(fmt.Sprint(os.Getpid())), 0600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() {
|
|
_ = os.WriteFile(filepath.Join(original, "cgroup.procs"), []byte(fmt.Sprint(os.Getpid())), 0600)
|
|
if rootLock != nil {
|
|
_ = rootLock.Close()
|
|
rootLock = nil
|
|
}
|
|
_ = removeCgroupTree(root)
|
|
}()
|
|
stale := filepath.Join(root, "task-"+testID())
|
|
if err = os.Mkdir(stale, 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dir, err := os.Open(stale)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer dir.Close()
|
|
cmd := exec.Command("sh", "-c", "exec sleep 300")
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{UseCgroupFD: true, CgroupFD: int(dir.Fd()), Setsid: true}
|
|
if err = cmd.Start(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
reaped := make(chan struct{})
|
|
go func() { _ = cmd.Wait(); close(reaped) }()
|
|
opts.CgroupRoot = root
|
|
opts.Mode = "required"
|
|
if err = configurePlatform(&opts); err != nil {
|
|
_ = cmd.Process.Kill()
|
|
<-reaped
|
|
t.Fatal(err)
|
|
}
|
|
<-reaped
|
|
waitGone(t, cmd.Process.Pid)
|
|
if _, err = os.Stat(stale); !os.IsNotExist(err) {
|
|
t.Fatalf("stale task cgroup was not removed: %v", err)
|
|
}
|
|
data, err := os.ReadFile(filepath.Join(root, "cgroup.subtree_control"))
|
|
if err != nil || !strings.Contains(string(data), "memory") {
|
|
t.Fatalf("delegation not enabled: %s %v", data, err)
|
|
}
|
|
}
|