From 99ac96511bed17f48d908db3d00a1f48579ba011 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 12 Aug 2025 04:38:45 +0900 Subject: hst/fs: interface filesystem config This allows mount points to be represented by different underlying structs. Signed-off-by: Ophestra --- internal/app/app_nixos_linux_test.go | 20 ++++++--- internal/app/container_linux.go | 87 ++++++++++++++++-------------------- internal/app/seal_linux.go | 6 +-- 3 files changed, 56 insertions(+), 57 deletions(-) (limited to 'internal') diff --git a/internal/app/app_nixos_linux_test.go b/internal/app/app_nixos_linux_test.go index 901e825a..ef587222 100644 --- a/internal/app/app_nixos_linux_test.go +++ b/internal/app/app_nixos_linux_test.go @@ -13,6 +13,9 @@ import ( ) func m(pathname string) *container.Absolute { return container.MustAbs(pathname) } +func f(c hst.FilesystemConfig) hst.FilesystemConfigJSON { + return hst.FilesystemConfigJSON{FilesystemConfig: c} +} var testCasesNixos = []sealTestCase{ { @@ -25,11 +28,18 @@ var testCasesNixos = []sealTestCase{ Container: &hst.ContainerConfig{ Userns: true, Net: true, MapRealUID: true, Env: nil, AutoEtc: true, - Filesystem: []hst.FilesystemConfig{ - {Src: m("/bin"), Must: true}, {Src: m("/usr/bin/"), Must: true}, - {Src: m("/nix/store"), Must: true}, {Src: m("/run/current-system"), Must: true}, - {Src: m("/sys/block")}, {Src: m("/sys/bus")}, {Src: m("/sys/class")}, {Src: m("/sys/dev")}, {Src: m("/sys/devices")}, - {Src: m("/run/opengl-driver"), Must: true}, {Src: m("/dev/dri"), Device: true}, + Filesystem: []hst.FilesystemConfigJSON{ + f(&hst.FSBind{Src: m("/bin")}), + f(&hst.FSBind{Src: m("/usr/bin/")}), + f(&hst.FSBind{Src: m("/nix/store")}), + f(&hst.FSBind{Src: m("/run/current-system")}), + f(&hst.FSBind{Src: m("/sys/block"), Optional: true}), + f(&hst.FSBind{Src: m("/sys/bus"), Optional: true}), + f(&hst.FSBind{Src: m("/sys/class"), Optional: true}), + f(&hst.FSBind{Src: m("/sys/dev"), Optional: true}), + f(&hst.FSBind{Src: m("/sys/devices"), Optional: true}), + f(&hst.FSBind{Src: m("/run/opengl-driver")}), + f(&hst.FSBind{Src: m("/dev/dri"), Device: true, Optional: true}), }, }, SystemBus: &dbus.Config{ diff --git a/internal/app/container_linux.go b/internal/app/container_linux.go index f93cfcc2..3f1259fd 100644 --- a/internal/app/container_linux.go +++ b/internal/app/container_linux.go @@ -6,7 +6,6 @@ import ( "io/fs" "maps" "path" - "slices" "syscall" "hakurei.app/container" @@ -126,73 +125,63 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid return nil, nil, err } } - // evaluated path, input path - hidePathSource := make([][2]string, 0, len(s.Filesystem)) + + var hidePathSourceCount int + for i, c := range s.Filesystem { + if !c.Valid() { + return nil, nil, fmt.Errorf("invalid filesystem at index %d", i) + } + c.Apply(params.Ops) + + // fs counter + hidePathSourceCount += len(c.Host()) + } // AutoRoot is a collection of many BindMountOp internally + var autoRootEntries []fs.DirEntry if s.AutoRoot != nil { if d, err := os.ReadDir(s.AutoRoot.String()); err != nil { return nil, nil, err } else { - hidePathSource = slices.Grow(hidePathSource, len(d)) - for _, ent := range d { - name := ent.Name() - if container.IsAutoRootBindable(name) { - name = path.Join(s.AutoRoot.String(), name) - srcP := [2]string{name, name} - if err = evalSymlinks(os, &srcP[0]); err != nil { - return nil, nil, err - } - hidePathSource = append(hidePathSource, srcP) - } - } + // autoroot counter + hidePathSourceCount += len(d) + autoRootEntries = d } } - for i, c := range s.Filesystem { - if c.Src == nil { - return nil, nil, fmt.Errorf("invalid filesystem at index %d", i) - } + hidePathSource := make([]*container.Absolute, 0, hidePathSourceCount) - // special filesystems - switch c.Src.String() { - case container.Nonexistent: - if c.Dst == nil { - return nil, nil, errors.New("tmpfs dst must not be nil") - } - if c.Write { - params.Tmpfs(c.Dst, hst.TmpfsSize, hst.TmpfsPerm) - } else { - params.Readonly(c.Dst, hst.TmpfsPerm) + // fs append + for _, c := range s.Filesystem { + // all entries already checked above + hidePathSource = append(hidePathSource, c.Host()...) + } + + // autoroot append + if s.AutoRoot != nil { + for _, ent := range autoRootEntries { + name := ent.Name() + if container.IsAutoRootBindable(name) { + hidePathSource = append(hidePathSource, s.AutoRoot.Append(name)) } - continue } + } - dst := c.Dst - if dst == nil { - dst = c.Src + // evaluated path, input path + hidePathSourceEval := make([][2]string, len(hidePathSource)) + for i, a := range hidePathSource { + if a == nil { + // unreachable + return nil, nil, syscall.ENOTRECOVERABLE } - p := [2]string{c.Src.String(), c.Src.String()} - if err := evalSymlinks(os, &p[0]); err != nil { + hidePathSourceEval[i] = [2]string{a.String(), a.String()} + if err := evalSymlinks(os, &hidePathSourceEval[i][0]); err != nil { return nil, nil, err } - hidePathSource = append(hidePathSource, p) - - var flags int - if c.Write { - flags |= container.BindWritable - } - if c.Device { - flags |= container.BindDevice | container.BindWritable - } - if !c.Must { - flags |= container.BindOptional - } - params.Bind(c.Src, dst, flags) } - for _, p := range hidePathSource { + for _, p := range hidePathSourceEval { for i := range hidePaths { // skip matched entries if hidePathMatch[i] { diff --git a/internal/app/seal_linux.go b/internal/app/seal_linux.go index e27fee10..961447b3 100644 --- a/internal/app/seal_linux.go +++ b/internal/app/seal_linux.go @@ -248,15 +248,15 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co // bind GPU stuff if config.Enablements&(system.EX11|system.EWayland) != 0 { - conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Src: container.AbsFHSDev.Append("dri"), Device: true}) + conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{Src: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}}) } // opportunistically bind kvm - conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Src: container.AbsFHSDev.Append("kvm"), Device: true}) + conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{Src: container.AbsFHSDev.Append("kvm"), Device: true, Optional: true}}) // hide nscd from container if present nscd := container.AbsFHSVar.Append("run/nscd") if _, err := sys.Stat(nscd.String()); !errors.Is(err, fs.ErrNotExist) { - conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Dst: nscd, Src: container.AbsNonexistent}) + conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSEphemeral{Dst: nscd}}) } config.Container = conf -- cgit v1.3.1