container/ops: mount dev readonly
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m2s
Test / Hakurei (push) Successful in 2m57s
Test / Sandbox (race detector) (push) Successful in 3m53s
Test / Hpkg (push) Successful in 3m53s
Test / Hakurei (race detector) (push) Successful in 4m37s
Test / Flake checks (push) Successful in 1m18s

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>
This commit is contained in:
Ophestra 2025-08-03 19:18:53 +09:00
parent 7b416d47dc
commit 38245559dc
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
10 changed files with 36 additions and 15 deletions

View File

@ -74,7 +74,7 @@ var containerTestCases = []struct {
new(container.Ops). new(container.Ops).
Dev("/dev", true), Dev("/dev", true),
[]*vfs.MountInfoEntry{ []*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("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
@ -90,7 +90,7 @@ var containerTestCases = []struct {
new(container.Ops). new(container.Ops).
Dev("/dev", false), Dev("/dev", false),
[]*vfs.MountInfoEntry{ []*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("/null", "/dev/null", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/zero", "/dev/zero", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),
ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/full", "/dev/full", "rw,nosuid", "devtmpfs", "devtmpfs", ignore),

View File

@ -181,13 +181,21 @@ func init() { gob.Register(new(MountDevOp)) }
// Dev appends an [Op] that mounts a subset of host /dev. // Dev appends an [Op] that mounts a subset of host /dev.
func (f *Ops) Dev(dest string, mqueue bool) *Ops { 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 return f
} }
type MountDevOp struct { type MountDevOp struct {
Target string Target string
Mqueue bool Mqueue bool
Write bool
} }
func (d *MountDevOp) early(*Params) error { return nil } 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 { if err := os.Mkdir(mqueueTarget, params.ParentPerm); err != nil {
return wrapErrSelf(err) return wrapErrSelf(err)
} }
return wrapErrSuffix(Mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString), if err := Mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil {
"cannot mount mqueue:") 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 } func (d *MountDevOp) Is(op Op) bool { vd, ok := op.(*MountDevOp); return ok && *d == *vd }

View File

@ -118,7 +118,7 @@ var testCasesNixos = []sealTestCase{
Ops: new(container.Ops). Ops: new(container.Ops).
Proc("/proc"). Proc("/proc").
Tmpfs(hst.Tmp, 4096, 0755). Tmpfs(hst.Tmp, 4096, 0755).
Dev("/dev", true). DevWritable("/dev", true).
Bind("/bin", "/bin", 0). Bind("/bin", "/bin", 0).
Bind("/usr/bin", "/usr/bin", 0). Bind("/usr/bin", "/usr/bin", 0).
Bind("/nix/store", "/nix/store", 0). Bind("/nix/store", "/nix/store", 0).
@ -131,6 +131,7 @@ var testCasesNixos = []sealTestCase{
Bind("/run/opengl-driver", "/run/opengl-driver", 0). Bind("/run/opengl-driver", "/run/opengl-driver", 0).
Bind("/dev/dri", "/dev/dri", container.BindDevice|container.BindWritable|container.BindOptional). Bind("/dev/dri", "/dev/dri", container.BindDevice|container.BindWritable|container.BindOptional).
Etc("/etc", "8e2c76b066dabe574cf073bdb46eb5c1"). Etc("/etc", "8e2c76b066dabe574cf073bdb46eb5c1").
Remount("/dev", syscall.MS_RDONLY).
Tmpfs("/run/user", 4096, 0755). Tmpfs("/run/user", 4096, 0755).
Bind("/tmp/hakurei.1971/runtime/1", "/run/user/1971", container.BindWritable). Bind("/tmp/hakurei.1971/runtime/1", "/run/user/1971", container.BindWritable).
Bind("/tmp/hakurei.1971/tmpdir/1", "/tmp", container.BindWritable). Bind("/tmp/hakurei.1971/tmpdir/1", "/tmp", container.BindWritable).

View File

@ -46,12 +46,13 @@ var testCasesPd = []sealTestCase{
Root("/", "4a450b6596d7bc15bd01780eb9a607ac", container.BindWritable). Root("/", "4a450b6596d7bc15bd01780eb9a607ac", container.BindWritable).
Proc("/proc"). Proc("/proc").
Tmpfs(hst.Tmp, 4096, 0755). Tmpfs(hst.Tmp, 4096, 0755).
Dev("/dev", true). DevWritable("/dev", true).
Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional). Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional).
Readonly("/var/run/nscd", 0755). Readonly("/var/run/nscd", 0755).
Tmpfs("/run/user/1971", 8192, 0755). Tmpfs("/run/user/1971", 8192, 0755).
Tmpfs("/run/dbus", 8192, 0755). Tmpfs("/run/dbus", 8192, 0755).
Etc("/etc", "4a450b6596d7bc15bd01780eb9a607ac"). Etc("/etc", "4a450b6596d7bc15bd01780eb9a607ac").
Remount("/dev", syscall.MS_RDONLY).
Tmpfs("/run/user", 4096, 0755). Tmpfs("/run/user", 4096, 0755).
Bind("/tmp/hakurei.1971/runtime/0", "/run/user/65534", container.BindWritable). Bind("/tmp/hakurei.1971/runtime/0", "/run/user/65534", container.BindWritable).
Bind("/tmp/hakurei.1971/tmpdir/0", "/tmp", container.BindWritable). Bind("/tmp/hakurei.1971/tmpdir/0", "/tmp", container.BindWritable).
@ -180,13 +181,14 @@ var testCasesPd = []sealTestCase{
Root("/", "ebf083d1b175911782d413369b64ce7c", container.BindWritable). Root("/", "ebf083d1b175911782d413369b64ce7c", container.BindWritable).
Proc("/proc"). Proc("/proc").
Tmpfs(hst.Tmp, 4096, 0755). Tmpfs(hst.Tmp, 4096, 0755).
Dev("/dev", true). DevWritable("/dev", true).
Bind("/dev/dri", "/dev/dri", container.BindWritable|container.BindDevice|container.BindOptional). Bind("/dev/dri", "/dev/dri", container.BindWritable|container.BindDevice|container.BindOptional).
Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional). Bind("/dev/kvm", "/dev/kvm", container.BindWritable|container.BindDevice|container.BindOptional).
Readonly("/var/run/nscd", 0755). Readonly("/var/run/nscd", 0755).
Tmpfs("/run/user/1971", 8192, 0755). Tmpfs("/run/user/1971", 8192, 0755).
Tmpfs("/run/dbus", 8192, 0755). Tmpfs("/run/dbus", 8192, 0755).
Etc("/etc", "ebf083d1b175911782d413369b64ce7c"). Etc("/etc", "ebf083d1b175911782d413369b64ce7c").
Remount("/dev", syscall.MS_RDONLY).
Tmpfs("/run/user", 4096, 0755). Tmpfs("/run/user", 4096, 0755).
Bind("/tmp/hakurei.1971/runtime/9", "/run/user/65534", container.BindWritable). Bind("/tmp/hakurei.1971/runtime/9", "/run/user/65534", container.BindWritable).
Bind("/tmp/hakurei.1971/tmpdir/9", "/tmp", container.BindWritable). Bind("/tmp/hakurei.1971/tmpdir/9", "/tmp", container.BindWritable).

View File

@ -85,7 +85,7 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
Tmpfs(hst.Tmp, 1<<12, 0755) Tmpfs(hst.Tmp, 1<<12, 0755)
if !s.Device { if !s.Device {
params.Dev("/dev", true) params.DevWritable("/dev", true)
} else { } else {
params.Bind("/dev", "/dev", container.BindWritable|container.BindDevice) params.Bind("/dev", "/dev", container.BindWritable|container.BindDevice)
} }
@ -239,6 +239,11 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
params.Etc(etcPath, prefix) params.Etc(etcPath, prefix)
} }
// no more ContainerConfig paths beyond this point
if !s.Device {
params.Remount("/dev", syscall.MS_RDONLY)
}
return params, maps.Clone(s.Env), nil return params, maps.Clone(s.Env), nil
} }

View File

@ -229,7 +229,7 @@ in
(ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000003,gid=1000003") (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000003,gid=1000003")
(ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw") (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
(ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000003,gid=1000003") (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000003,gid=1000003")
(ent "/" "/dev" "rw,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000003,gid=1000003") (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000003,gid=1000003")
(ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)

View File

@ -170,7 +170,7 @@
(ent "/var" "/var" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/var" "/var" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
(ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw") (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
(ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000000,gid=1000000") (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000000,gid=1000000")
(ent "/" "/dev" "rw,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000000,gid=1000000") (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000000,gid=1000000")
(ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)

View File

@ -229,7 +229,7 @@ in
(ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000005,gid=1000005") (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000005,gid=1000005")
(ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw") (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
(ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000005,gid=1000005") (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000005,gid=1000005")
(ent "/" "/dev" "rw,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000005,gid=1000005") (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000005,gid=1000005")
(ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)

View File

@ -228,7 +228,7 @@ in
(ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000001,gid=1000001") (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000001,gid=1000001")
(ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw") (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
(ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000001,gid=1000001") (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000001,gid=1000001")
(ent "/" "/dev" "rw,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000001,gid=1000001") (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000001,gid=1000001")
(ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)

View File

@ -230,7 +230,7 @@ in
(ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002") (ent "/sysroot" "/" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002")
(ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw") (ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
(ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000002,gid=1000002") (ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000002,gid=1000002")
(ent "/" "/dev" "rw,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000002,gid=1000002") (ent "/" "/dev" "ro,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000002,gid=1000002")
(ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
(ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)