diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-05-07 15:15:28 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-05-07 15:15:47 +0900 |
| commit | d4144fcf7f9217d2a2dcec21202421d5fa9d4928 (patch) | |
| tree | 42625452fcde08e61370725ae99bc9915d88ccb3 /container/container_test.go | |
| parent | bad66facbc1b555d8883534c27ada586fc15df9c (diff) | |
container: optionally map uid/gid 0 as init
Unfortunately required to work around flawed APIs like binfmt_misc.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container/container_test.go')
| -rw-r--r-- | container/container_test.go | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/container/container_test.go b/container/container_test.go index 48b6e8a4..787720a8 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -409,8 +409,11 @@ var containerTestCases = []struct { func TestContainer(t *testing.T) { t.Parallel() + var suffix string +runTests: for i, tc := range containerTestCases { - t.Run(tc.name, func(t *testing.T) { + _suffix := suffix + t.Run(tc.name+_suffix, func(t *testing.T) { t.Parallel() wantOps, wantOpsCtx := tc.ops(t) @@ -434,6 +437,8 @@ func TestContainer(t *testing.T) { c.SeccompDisable = !tc.filter c.RetainSession = tc.session c.HostNet = tc.net + c.InitAsRoot = _suffix != "" + c.Env = append(c.Env, "HAKUREI_TEST_SUFFIX="+_suffix) if info.CanDegrade { if _, err := landlock.GetABI(); err != nil { if !errors.Is(err, syscall.ENOSYS) { @@ -443,6 +448,9 @@ func TestContainer(t *testing.T) { t.Log("Landlock LSM is unavailable, enabling HostAbstract") } } + if c.InitAsRoot { + c.SeccompPresets &= ^std.PresetDenyNS + } c. Readonly(check.MustAbs(pathReadonly), 0755). @@ -511,6 +519,11 @@ func TestContainer(t *testing.T) { } }) } + + if suffix == "" { + suffix = " as root" + goto runTests + } } func ent(root, target, vfsOptstr, fsType, source, fsOptstr string) *vfs.MountInfoEntry { @@ -589,9 +602,9 @@ func testContainerCancel( } func TestForward(t *testing.T) { - testContainerCancel(t, func(c *container.Container) { - c.ForwardCancel = true - }, func(ps *os.ProcessState, waitErr error) { + t.Parallel() + + f := func(ps *os.ProcessState, waitErr error) { var exitError *exec.ExitError if !errors.As(waitErr, &exitError) { if m, ok := container.InternalMessageFromError(waitErr); ok { @@ -602,11 +615,26 @@ func TestForward(t *testing.T) { if code := exitError.ExitCode(); code != blockExitCodeInterrupt { t.Errorf("ExitCode: %d, want %d", code, blockExitCodeInterrupt) } + } + t.Run("direct", func(t *testing.T) { + t.Parallel() + testContainerCancel(t, func(c *container.Container) { + c.ForwardCancel = true + }, f) + }) + t.Run("as root", func(t *testing.T) { + testContainerCancel(t, func(c *container.Container) { + c.ForwardCancel = true + c.InitAsRoot = true + c.Proc(fhs.AbsProc) + }, f) }) } func TestCancel(t *testing.T) { - testContainerCancel(t, nil, func(ps *os.ProcessState, waitErr error) { + t.Parallel() + + f := func(ps *os.ProcessState, waitErr error) { wantErr := context.Canceled if !reflect.DeepEqual(waitErr, wantErr) { if m, ok := container.InternalMessageFromError(waitErr); ok { @@ -619,6 +647,16 @@ func TestCancel(t *testing.T) { } else if code := ps.ExitCode(); code != 0 { t.Errorf("ExitCode: %d, want %d", code, 0) } + } + t.Run("direct", func(t *testing.T) { + t.Parallel() + testContainerCancel(t, nil, f) + }) + t.Run("as root", func(t *testing.T) { + testContainerCancel(t, func(c *container.Container) { + c.InitAsRoot = true + c.Proc(fhs.AbsProc) + }, f) }) } @@ -655,6 +693,8 @@ func init() { }) c.Command("container", command.UsageInternal, func(args []string) error { + asRoot := os.Getenv("HAKUREI_TEST_SUFFIX") == " as root" + if len(args) != 1 { return syscall.EINVAL } @@ -672,11 +712,19 @@ func init() { return fmt.Errorf("gid: %d, want %d", gid, tc.gid) } + // no attack surface increase during as root due to no_new_privs + var wantBounding uintptr = 1 + asRootNot := " not" + if !asRoot { + wantBounding = 0 + asRootNot = "" + } + const ( PR_CAP_AMBIENT = 0x2f PR_CAP_AMBIENT_IS_SET = 0x1 ) - for i := range container.LastCap(nil) { + for i := range container.LastCap(nil) + 1 { r, _, errno := syscall.Syscall( syscall.SYS_PRCTL, PR_CAP_AMBIENT, @@ -687,7 +735,7 @@ func init() { return os.NewSyscallError("prctl", errno) } if r != 0 { - return fmt.Errorf("capability %d is set", i) + return fmt.Errorf("capability %d in ambient set", i) } r, _, errno = syscall.Syscall( @@ -699,8 +747,8 @@ func init() { if errno != 0 { return os.NewSyscallError("prctl", errno) } - if r != 0 { - return fmt.Errorf("capability %d in set", i) + if r != wantBounding { + return fmt.Errorf("capability %d%s in bounding set", i, asRootNot) } } |
