From 9bc8532d56fc5c1f727919d21f464dff09316913 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 26 Aug 2025 03:15:32 +0900 Subject: [PATCH] container/initdev: mount tmpfs on shm for ro dev Programs expect /dev/shm to be a writable tmpfs. Signed-off-by: Ophestra --- container/container_test.go | 2 ++ container/initdev.go | 11 ++++++++--- container/initdev_test.go | 2 ++ container/mount.go | 2 ++ internal/app/app_nixos_linux_test.go | 1 + internal/app/app_pd_linux_test.go | 2 ++ internal/app/container_linux.go | 4 +++- test/sandbox/case/mapuid.nix | 3 ++- test/sandbox/case/pd.nix | 3 ++- test/sandbox/case/pdlike.nix | 3 ++- test/sandbox/case/preset.nix | 3 ++- test/sandbox/case/tty.nix | 3 ++- 12 files changed, 30 insertions(+), 9 deletions(-) diff --git a/container/container_test.go b/container/container_test.go index 5dd510e..90fba87 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -100,6 +100,7 @@ var containerTestCases = []struct { ent("/tty", "/dev/tty", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"), ent("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"), + ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore), ), 1971, 100, nil, 0, seccomp.PresetStrict}, @@ -116,6 +117,7 @@ var containerTestCases = []struct { ent("/urandom", "/dev/urandom", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/tty", "/dev/tty", "rw,nosuid", "devtmpfs", "devtmpfs", ignore), ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"), + ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore), ), 1971, 100, nil, 0, seccomp.PresetStrict}, diff --git a/container/initdev.go b/container/initdev.go index b319291..43ef524 100644 --- a/container/initdev.go +++ b/container/initdev.go @@ -72,8 +72,9 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error { } } + devShmPath := path.Join(target, "shm") devPtsPath := path.Join(target, "pts") - for _, name := range []string{path.Join(target, "shm"), devPtsPath} { + for _, name := range []string{devShmPath, devPtsPath} { if err := k.mkdir(name, state.ParentPerm); err != nil { return wrapErrSelf(err) } @@ -117,8 +118,12 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error { if d.Write { return nil } - return wrapErrSuffix(k.remount(target, MS_RDONLY), - fmt.Sprintf("cannot remount %q:", target)) + + if err := k.remount(target, MS_RDONLY); err != nil { + return wrapErrSuffix(k.remount(target, MS_RDONLY), + fmt.Sprintf("cannot remount %q:", target)) + } + return k.mountTmpfs(SourceTmpfs, devShmPath, MS_NOSUID|MS_NODEV, 0, 01777) } func (d *MountDevOp) Is(op Op) bool { diff --git a/container/initdev_test.go b/container/initdev_test.go index 9d2529c..de756d0 100644 --- a/container/initdev_test.go +++ b/container/initdev_test.go @@ -645,6 +645,7 @@ func TestMountDevOp(t *testing.T) { {"readlink", expectArgs{"/host/proc/self/fd/1"}, "/dev/pts/2", nil}, {"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil}, {"remount", expectArgs{"/sysroot/dev", uintptr(1)}, nil, nil}, + {"mountTmpfs", expectArgs{"tmpfs", "/sysroot/dev/shm", uintptr(0x6), 0, os.FileMode(01777)}, nil, nil}, }, nil}, {"success rw", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ @@ -715,6 +716,7 @@ func TestMountDevOp(t *testing.T) { {"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, nil}, {"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, nil}, {"remount", expectArgs{"/sysroot/dev", uintptr(1)}, nil, nil}, + {"mountTmpfs", expectArgs{"tmpfs", "/sysroot/dev/shm", uintptr(0x6), 0, os.FileMode(01777)}, nil, nil}, }, nil}, }) diff --git a/container/mount.go b/container/mount.go index 68011c7..f7d4af3 100644 --- a/container/mount.go +++ b/container/mount.go @@ -43,6 +43,8 @@ const ( // Note that any source value is allowed when fstype is [FstypeOverlay]. SourceOverlay = "overlay" + // SourceTmpfs is used when mounting tmpfs. + SourceTmpfs = "tmpfs" // SourceTmpfsRootfs is used when mounting the tmpfs instance backing the intermediate root. SourceTmpfsRootfs = "rootfs" // SourceTmpfsDevtmpfs is used when mounting tmpfs representing a subset of host devtmpfs. diff --git a/internal/app/app_nixos_linux_test.go b/internal/app/app_nixos_linux_test.go index fb90ee8..e2aa5a4 100644 --- a/internal/app/app_nixos_linux_test.go +++ b/internal/app/app_nixos_linux_test.go @@ -148,6 +148,7 @@ var testCasesNixos = []sealTestCase{ Etc(m("/etc/"), "8e2c76b066dabe574cf073bdb46eb5c1"). Bind(m("/var/lib/persist/module/hakurei/0/1"), m("/var/lib/persist/module/hakurei/0/1"), container.BindWritable|container.BindEnsure). Remount(m("/dev/"), syscall.MS_RDONLY). + Tmpfs(m("/dev/shm"), 0, 01777). Tmpfs(m("/run/user/"), 4096, 0755). Bind(m("/tmp/hakurei.1971/runtime/1"), m("/run/user/1971"), container.BindWritable). Bind(m("/tmp/hakurei.1971/tmpdir/1"), m("/tmp/"), container.BindWritable). diff --git a/internal/app/app_pd_linux_test.go b/internal/app/app_pd_linux_test.go index 9e4c27e..384f5a0 100644 --- a/internal/app/app_pd_linux_test.go +++ b/internal/app/app_pd_linux_test.go @@ -53,6 +53,7 @@ var testCasesPd = []sealTestCase{ Tmpfs(m("/run/user/1971"), 8192, 0755). Tmpfs(m("/run/dbus"), 8192, 0755). Remount(m("/dev/"), syscall.MS_RDONLY). + Tmpfs(m("/dev/shm"), 0, 01777). Tmpfs(m("/run/user/"), 4096, 0755). Bind(m("/tmp/hakurei.1971/runtime/0"), m("/run/user/65534"), container.BindWritable). Bind(m("/tmp/hakurei.1971/tmpdir/0"), m("/tmp/"), container.BindWritable). @@ -189,6 +190,7 @@ var testCasesPd = []sealTestCase{ Tmpfs(m("/run/user/1971"), 8192, 0755). Tmpfs(m("/run/dbus"), 8192, 0755). Remount(m("/dev/"), syscall.MS_RDONLY). + Tmpfs(m("/dev/shm"), 0, 01777). Tmpfs(m("/run/user/"), 4096, 0755). Bind(m("/tmp/hakurei.1971/runtime/9"), m("/run/user/65534"), container.BindWritable). Bind(m("/tmp/hakurei.1971/tmpdir/9"), m("/tmp/"), container.BindWritable). diff --git a/internal/app/container_linux.go b/internal/app/container_linux.go index b1c4fa4..cd423ad 100644 --- a/internal/app/container_linux.go +++ b/internal/app/container_linux.go @@ -233,7 +233,9 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid // no more ContainerConfig paths beyond this point if !s.Device { - params.Remount(container.AbsFHSDev, syscall.MS_RDONLY) + params. + Remount(container.AbsFHSDev, syscall.MS_RDONLY). + Tmpfs(container.AbsFHSDev.Append("shm"), 0, 01777) } return params, maps.Clone(s.Env), nil diff --git a/test/sandbox/case/mapuid.nix b/test/sandbox/case/mapuid.nix index 486d439..d033579 100644 --- a/test/sandbox/case/mapuid.nix +++ b/test/sandbox/case/mapuid.nix @@ -72,7 +72,7 @@ in ptmx = fs "80001ff" null null; pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null; random = fs "42001b6" null null; - shm = fs "800001ed" { } null; + shm = fs "801001ff" { } null; stderr = fs "80001ff" null null; stdin = fs "80001ff" null null; stdout = fs "80001ff" null null; @@ -256,6 +256,7 @@ in (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr") (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/var/lib/hakurei/u0/a3" "/var/lib/hakurei/u0/a3" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=1000003,gid=1000003") (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000003,gid=1000003") (ent "/tmp/hakurei.0/runtime/3" "/run/user/1000" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/tmp/hakurei.0/tmpdir/3" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") diff --git a/test/sandbox/case/pd.nix b/test/sandbox/case/pd.nix index 6bad3e7..0222892 100644 --- a/test/sandbox/case/pd.nix +++ b/test/sandbox/case/pd.nix @@ -36,7 +36,7 @@ ptmx = fs "80001ff" null null; pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null; random = fs "42001b6" null null; - shm = fs "800001ed" { } null; + shm = fs "801001ff" { } null; stderr = fs "80001ff" null null; stdin = fs "80001ff" null null; stdout = fs "80001ff" null null; @@ -185,6 +185,7 @@ (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/" "/run/user/1000" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=8k,mode=755,uid=1000000,gid=1000000") (ent "/" "/run/dbus" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=8k,mode=755,uid=1000000,gid=1000000") + (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=1000000,gid=1000000") (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000000,gid=1000000") (ent "/tmp/hakurei.0/runtime/0" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/tmp/hakurei.0/tmpdir/0" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") diff --git a/test/sandbox/case/pdlike.nix b/test/sandbox/case/pdlike.nix index 1fdc592..60dcef5 100644 --- a/test/sandbox/case/pdlike.nix +++ b/test/sandbox/case/pdlike.nix @@ -70,7 +70,7 @@ in ptmx = fs "80001ff" null null; pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null; random = fs "42001b6" null null; - shm = fs "800001ed" { } null; + shm = fs "801001ff" { } null; stderr = fs "80001ff" null null; stdin = fs "80001ff" null null; stdout = fs "80001ff" null null; @@ -251,6 +251,7 @@ in (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/var/lib/hakurei/u0/a5" "/var/lib/hakurei/u0/a5" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=1000005,gid=1000005") (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000005,gid=1000005") (ent "/tmp/hakurei.0/runtime/5" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/tmp/hakurei.0/tmpdir/5" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") diff --git a/test/sandbox/case/preset.nix b/test/sandbox/case/preset.nix index 721659f..ba1ab4c 100644 --- a/test/sandbox/case/preset.nix +++ b/test/sandbox/case/preset.nix @@ -69,7 +69,7 @@ in ptmx = fs "80001ff" null null; pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null; random = fs "42001b6" null null; - shm = fs "800001ed" { } null; + shm = fs "801001ff" { } null; stderr = fs "80001ff" null null; stdin = fs "80001ff" null null; stdout = fs "80001ff" null null; @@ -249,6 +249,7 @@ in (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/var/lib/hakurei/u0/a1" "/var/lib/hakurei/u0/a1" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=1000001,gid=1000001") (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000001,gid=1000001") (ent "/tmp/hakurei.0/runtime/1" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/tmp/hakurei.0/tmpdir/1" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") diff --git a/test/sandbox/case/tty.nix b/test/sandbox/case/tty.nix index 0aed783..f06a906 100644 --- a/test/sandbox/case/tty.nix +++ b/test/sandbox/case/tty.nix @@ -74,7 +74,7 @@ in ptmx = fs "80001ff" null null; pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null; random = fs "42001b6" null null; - shm = fs "800001ed" { } null; + shm = fs "801001ff" { } null; stderr = fs "80001ff" null null; stdin = fs "80001ff" null null; stdout = fs "80001ff" null null; @@ -261,6 +261,7 @@ in (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,uuid=on,userxattr") (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/var/lib/hakurei/u0/a2" "/var/lib/hakurei/u0/a2" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (ent "/" "/dev/shm" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,uid=1000002,gid=1000002") (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000002,gid=1000002") (ent "/tmp/hakurei.0/runtime/2" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/tmp/hakurei.0/tmpdir/2" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")