diff --git a/container/container_test.go b/container/container_test.go index bc4999e..62eeacf 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -38,6 +38,7 @@ var containerTestCases = []struct { filter bool session bool net bool + ro bool ops *container.Ops mnt []*vfs.MountInfoEntry @@ -48,26 +49,26 @@ var containerTestCases = []struct { flags seccomp.ExportFlag presets seccomp.FilterPreset }{ - {"minimal", true, false, false, + {"minimal", true, false, false, true, new(container.Ops), nil, 1000, 100, nil, 0, seccomp.PresetStrict}, - {"allow", true, true, true, + {"allow", true, true, true, false, new(container.Ops), nil, 1000, 100, nil, 0, seccomp.PresetExt | seccomp.PresetDenyDevel}, - {"no filter", false, true, true, + {"no filter", false, true, true, true, new(container.Ops), nil, 1000, 100, nil, 0, seccomp.PresetExt}, - {"custom rules", true, true, true, + {"custom rules", true, true, true, false, new(container.Ops), nil, 1, 31, []seccomp.NativeRule{{seccomp.ScmpSyscall(syscall.SYS_SETUID), seccomp.ScmpErrno(syscall.EPERM), nil}}, 0, seccomp.PresetExt}, - {"tmpfs", true, false, false, + {"tmpfs", true, false, false, true, new(container.Ops). Tmpfs(hst.Tmp, 0, 0755), []*vfs.MountInfoEntry{ ent("/", hst.Tmp, "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", ignore), }, 9, 9, nil, 0, seccomp.PresetStrict}, - {"dev", true, true /* go test output is not a tty */, false, + {"dev", true, true /* go test output is not a tty */, false, false, new(container.Ops). Dev("/dev"). Mqueue("/dev/mqueue"), @@ -178,6 +179,10 @@ func TestContainer(t *testing.T) { } c.Place(pathWantMnt, want.Bytes()) + if tc.ro { + c.Remount("/", syscall.MS_RDONLY) + } + if err := c.Start(); err != nil { hlog.PrintBaseError(err, "start:") t.Fatalf("cannot start container: %v", err) @@ -330,6 +335,11 @@ func init() { return fmt.Errorf("cannot close expected mount points: %v", err) } + if tc.ro && len(mnt) > 0 { + // Remount("/", syscall.MS_RDONLY) + mnt[0].VfsOptstr = "ro,nosuid,nodev" + } + var d *vfs.MountInfoDecoder if f, err := os.Open("/proc/self/mountinfo"); err != nil { return fmt.Errorf("cannot open mountinfo: %v", err) diff --git a/container/ops.go b/container/ops.go index 1fd4963..7456ed3 100644 --- a/container/ops.go +++ b/container/ops.go @@ -33,6 +33,32 @@ type ( // Grow grows the slice Ops points to using [slices.Grow]. func (f *Ops) Grow(n int) { *f = slices.Grow(*f, n) } +func init() { gob.Register(new(RemountOp)) } + +// Remount appends an [Op] that applies [RemountOp.Flags] on container path [RemountOp.Target]. +func (f *Ops) Remount(target string, flags uintptr) *Ops { + *f = append(*f, &RemountOp{target, flags}) + return f +} + +type RemountOp struct { + Target string + Flags uintptr +} + +func (*RemountOp) early(*Params) error { return nil } +func (r *RemountOp) apply(*Params) error { + if !path.IsAbs(r.Target) { + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", r.Target)) + } + return wrapErrSuffix(hostProc.remount(toSysroot(r.Target), r.Flags), + fmt.Sprintf("cannot remount %q:", r.Target)) +} + +func (r *RemountOp) Is(op Op) bool { vr, ok := op.(*RemountOp); return ok && *r == *vr } +func (*RemountOp) prefix() string { return "remounting" } +func (r *RemountOp) String() string { return fmt.Sprintf("%q flags %#x", r.Target, r.Flags) } + func init() { gob.Register(new(BindMountOp)) } // Bind appends an [Op] that bind mounts host path [BindMountOp.Source] on container path [BindMountOp.Target].