aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-08-01 23:48:02 +0900
committerOphestra <cat@gensokyo.uk>2025-08-01 23:48:02 +0900
commitc5d24979f5d6095116d66beb544aa382816183f9 (patch)
treea150559abaea01bf9b103be234e85e04e1a04c7c
parent1dc780bca737610196ed58644b3ba61edc8acc48 (diff)
container/ops: expose remount as Op
This is useful for building a filesystem hierarchy then remounting it readonly. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--container/container_test.go22
-rw-r--r--container/ops.go26
2 files changed, 42 insertions, 6 deletions
diff --git a/container/container_test.go b/container/container_test.go
index bc4999e5..62eeacfc 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 1fd4963c..7456ed38 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].