aboutsummaryrefslogtreecommitdiffhomepage
path: root/container
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-08-03 19:18:53 +0900
committerOphestra <cat@gensokyo.uk>2025-08-03 19:18:53 +0900
commit38245559dca0833dc078b982d59490eee53e168c (patch)
treeffe415b5db8fd21b3a75600428f167eeef018591 /container
parent7b416d47dcb830aab5daa432cf79af5f8bbacaef (diff)
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 <cat@gensokyo.uk>
Diffstat (limited to 'container')
-rw-r--r--container/container_test.go4
-rw-r--r--container/ops.go21
2 files changed, 19 insertions, 6 deletions
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 }