From 38245559dca0833dc078b982d59490eee53e168c Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 3 Aug 2025 19:18:53 +0900 Subject: container/ops: mount dev readonly There is usually no good reason to write to /dev. This however doesn't work in internal/app because FilesystemConfig supplied by ContainerConfig might add entries to /dev, so internal/app follows DevWritable with Remount instead. Signed-off-by: Ophestra --- container/container_test.go | 4 ++-- container/ops.go | 21 +++++++++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'container') diff --git a/container/container_test.go b/container/container_test.go index 861a4dbd..2db2c08e 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -74,7 +74,7 @@ var containerTestCases = []struct { new(container.Ops). Dev("/dev", true), []*vfs.MountInfoEntry{ - ent("/", "/dev", "rw,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore), + ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore), ent("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), @@ -90,7 +90,7 @@ var containerTestCases = []struct { new(container.Ops). Dev("/dev", false), []*vfs.MountInfoEntry{ - ent("/", "/dev", "rw,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore), + ent("/", "/dev", "ro,nosuid,nodev,relatime", "tmpfs", "devtmpfs", ignore), ent("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), diff --git a/container/ops.go b/container/ops.go index d64235fc..e3eb45f8 100644 --- a/container/ops.go +++ b/container/ops.go @@ -181,13 +181,21 @@ func init() { gob.Register(new(MountDevOp)) } // Dev appends an [Op] that mounts a subset of host /dev. func (f *Ops) Dev(dest string, mqueue bool) *Ops { - *f = append(*f, &MountDevOp{dest, mqueue}) + *f = append(*f, &MountDevOp{dest, mqueue, false}) + return f +} + +// DevWritable appends an [Op] that mounts a writable subset of host /dev. +// There is usually no good reason to write to /dev, so this should always be followed by a [RemountOp]. +func (f *Ops) DevWritable(dest string, mqueue bool) *Ops { + *f = append(*f, &MountDevOp{dest, mqueue, true}) return f } type MountDevOp struct { Target string Mqueue bool + Write bool } func (d *MountDevOp) early(*Params) error { return nil } @@ -271,11 +279,16 @@ func (d *MountDevOp) apply(params *Params) error { if err := os.Mkdir(mqueueTarget, params.ParentPerm); err != nil { return wrapErrSelf(err) } - return wrapErrSuffix(Mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString), - "cannot mount mqueue:") + if err := Mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil { + return wrapErrSuffix(err, "cannot mount mqueue:") + } } - return nil + if d.Write { + return nil + } + return wrapErrSuffix(hostProc.remount(target, MS_RDONLY), + fmt.Sprintf("cannot remount %q:", target)) } func (d *MountDevOp) Is(op Op) bool { vd, ok := op.(*MountDevOp); return ok && *d == *vd } -- cgit v1.3.1