From 1438096339f49bdd466f3b057c7e695aa126fc3c Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 25 Aug 2025 17:51:08 +0900 Subject: [PATCH] hst/config: handle filesystem entry targeting root This allows any fstype supported by hst to be directly mounted on sysroot. A special case in internal/app applies the matching entry early and excludes it from path hiding. Closes #5. Signed-off-by: Ophestra --- cmd/hakurei/print.go | 4 ---- cmd/hakurei/print_test.go | 31 +++++++++++++++++++++++-------- hst/config.go | 9 ++------- hst/hst.go | 9 ++++----- hst/hst_test.go | 9 +++++++-- internal/app/container_linux.go | 29 ++++++++++++++++++++--------- internal/app/seal_linux.go | 10 ++++++++-- 7 files changed, 64 insertions(+), 37 deletions(-) diff --git a/cmd/hakurei/print.go b/cmd/hakurei/print.go index d163efc..3e238d6 100644 --- a/cmd/hakurei/print.go +++ b/cmd/hakurei/print.go @@ -110,10 +110,6 @@ func printShowInstance( } t.Printf(" Flags:\t%s\n", strings.Join(flags, " ")) - if params.AutoRoot != nil { - t.Printf(" Root:\t%s (%d)\n", params.AutoRoot, params.RootFlags) - } - etc := params.Etc if etc == nil { etc = container.AbsFHSEtc diff --git a/cmd/hakurei/print_test.go b/cmd/hakurei/print_test.go index dab4b9e..b55c104 100644 --- a/cmd/hakurei/print_test.go +++ b/cmd/hakurei/print_test.go @@ -42,12 +42,12 @@ func Test_printShowInstance(t *testing.T) { Data: /var/lib/hakurei/u0/org.chromium.Chromium Hostname: localhost Flags: userns devel net abstract device tty mapuid autoetc - Root: /var/lib/hakurei/base/org.debian (2) Etc: /etc/ Path: /run/current-system/sw/bin/chromium Arguments: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland Filesystem + autoroot:w:/var/lib/hakurei/base/org.debian w+ephemeral(-rwxr-xr-x):/tmp/ w*/nix/store:/mnt-root/nix/.rw-store/upper:/mnt-root/nix/.rw-store/work:/mnt-root/nix/.ro-store */nix/store @@ -121,12 +121,12 @@ App Data: /var/lib/hakurei/u0/org.chromium.Chromium Hostname: localhost Flags: userns devel net abstract device tty mapuid autoetc - Root: /var/lib/hakurei/base/org.debian (2) Etc: /etc/ Path: /run/current-system/sw/bin/chromium Arguments: chromium --ignore-gpu-blocklist --disable-smooth-scrolling --enable-features=UseOzonePlatform --ozone-platform=wayland Filesystem + autoroot:w:/var/lib/hakurei/base/org.debian w+ephemeral(-rwxr-xr-x):/tmp/ w*/nix/store:/mnt-root/nix/.rw-store/upper:/mnt-root/nix/.rw-store/work:/mnt-root/nix/.ro-store */nix/store @@ -279,6 +279,13 @@ App "map_real_uid": true, "device": true, "filesystem": [ + { + "type": "bind", + "dst": "/", + "src": "/var/lib/hakurei/base/org.debian", + "write": true, + "autoroot": true + }, { "type": "ephemeral", "dst": "/tmp/", @@ -325,8 +332,6 @@ App "linkname": "/run/user/150" } ], - "auto_root": "/var/lib/hakurei/base/org.debian", - "root_flags": 2, "etc": "/etc/", "auto_etc": true } @@ -428,6 +433,13 @@ App "map_real_uid": true, "device": true, "filesystem": [ + { + "type": "bind", + "dst": "/", + "src": "/var/lib/hakurei/base/org.debian", + "write": true, + "autoroot": true + }, { "type": "ephemeral", "dst": "/tmp/", @@ -474,8 +486,6 @@ App "linkname": "/run/user/150" } ], - "auto_root": "/var/lib/hakurei/base/org.debian", - "root_flags": 2, "etc": "/etc/", "auto_etc": true } @@ -631,6 +641,13 @@ func Test_printPs(t *testing.T) { "map_real_uid": true, "device": true, "filesystem": [ + { + "type": "bind", + "dst": "/", + "src": "/var/lib/hakurei/base/org.debian", + "write": true, + "autoroot": true + }, { "type": "ephemeral", "dst": "/tmp/", @@ -677,8 +694,6 @@ func Test_printPs(t *testing.T) { "linkname": "/run/user/150" } ], - "auto_root": "/var/lib/hakurei/base/org.debian", - "root_flags": 2, "etc": "/etc/", "auto_etc": true } diff --git a/hst/config.go b/hst/config.go index 8226a35..e2f95d1 100644 --- a/hst/config.go +++ b/hst/config.go @@ -93,17 +93,12 @@ type ( // pass through all devices Device bool `json:"device,omitempty"` - // container mount points + // container mount points; + // if the first element targets /, it is inserted early and excluded from path hiding Filesystem []FilesystemConfigJSON `json:"filesystem"` // create symlinks inside container filesystem Link []LinkConfig `json:"symlink"` - // automatically bind mount top-level directories to container root; - // the zero value disables this behaviour - AutoRoot *container.Absolute `json:"auto_root,omitempty"` - // extra flags for AutoRoot - RootFlags int `json:"root_flags,omitempty"` - // read-only /etc directory Etc *container.Absolute `json:"etc,omitempty"` // automatically set up /etc symlinks diff --git a/hst/hst.go b/hst/hst.go index 6e77dc9..6654a4b 100644 --- a/hst/hst.go +++ b/hst/hst.go @@ -97,6 +97,7 @@ func Template() *Config { "GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT", }, Filesystem: []FilesystemConfigJSON{ + {&FSBind{container.AbsFHSRoot, container.AbsFHSVarLib.Append("hakurei/base/org.debian"), true, false, false, true}}, {&FSEphemeral{Target: container.AbsFHSTmp, Write: true, Perm: 0755}}, {&FSOverlay{ Target: container.MustAbs("/nix/store"), @@ -111,11 +112,9 @@ func Template() *Config { Target: container.MustAbs("/data/data/org.chromium.Chromium"), Write: true}}, {&FSBind{Source: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}}, }, - Link: []LinkConfig{{container.AbsFHSRunUser.Append("65534"), container.FHSRunUser + "150"}}, - AutoRoot: container.AbsFHSVarLib.Append("hakurei/base/org.debian"), - RootFlags: container.BindWritable, - Etc: container.AbsFHSEtc, - AutoEtc: true, + Link: []LinkConfig{{container.AbsFHSRunUser.Append("65534"), container.FHSRunUser + "150"}}, + Etc: container.AbsFHSEtc, + AutoEtc: true, }, } } diff --git a/hst/hst_test.go b/hst/hst_test.go index a3930f4..b8ec79c 100644 --- a/hst/hst_test.go +++ b/hst/hst_test.go @@ -102,6 +102,13 @@ func TestTemplate(t *testing.T) { "map_real_uid": true, "device": true, "filesystem": [ + { + "type": "bind", + "dst": "/", + "src": "/var/lib/hakurei/base/org.debian", + "write": true, + "autoroot": true + }, { "type": "ephemeral", "dst": "/tmp/", @@ -148,8 +155,6 @@ func TestTemplate(t *testing.T) { "linkname": "/run/user/150" } ], - "auto_root": "/var/lib/hakurei/base/org.debian", - "root_flags": 2, "etc": "/etc/", "auto_etc": true } diff --git a/internal/app/container_linux.go b/internal/app/container_linux.go index b82a6b6..33c0c72 100644 --- a/internal/app/container_linux.go +++ b/internal/app/container_linux.go @@ -74,8 +74,19 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid *gid = container.OverflowGid() } - if s.AutoRoot != nil { - params.Root(s.AutoRoot, s.RootFlags) + filesystem := s.Filesystem + var autoroot *hst.FSBind + // valid happens late, so root mount gets it here + if len(filesystem) > 0 && filesystem[0].Valid() && filesystem[0].Path().String() == container.FHSRoot { + // if the first element targets /, it is inserted early and excluded from path hiding + rootfs := filesystem[0].FilesystemConfig + filesystem = filesystem[1:] + rootfs.Apply(params.Ops) + + // autoroot requires special handling during path hiding + if b, ok := rootfs.(*hst.FSBind); ok && b.Valid() && b.AutoRoot { + autoroot = b + } } params. @@ -128,7 +139,7 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid } var hidePathSourceCount int - for i, c := range s.Filesystem { + for i, c := range filesystem { if !c.Valid() { return nil, nil, fmt.Errorf("invalid filesystem at index %d", i) } @@ -138,10 +149,10 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid hidePathSourceCount += len(c.Host()) } - // AutoRoot is a collection of many BindMountOp internally + // AutoRootOp 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 { + if autoroot != nil { + if d, err := os.ReadDir(autoroot.Source.String()); err != nil { return nil, nil, err } else { // autoroot counter @@ -153,17 +164,17 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid hidePathSource := make([]*container.Absolute, 0, hidePathSourceCount) // fs append - for _, c := range s.Filesystem { + for _, c := range filesystem { // all entries already checked above hidePathSource = append(hidePathSource, c.Host()...) } // autoroot append - if s.AutoRoot != nil { + if autoroot != nil { for _, ent := range autoRootEntries { name := ent.Name() if container.IsAutoRootBindable(name) { - hidePathSource = append(hidePathSource, s.AutoRoot.Append(name)) + hidePathSource = append(hidePathSource, autoroot.Source.Append(name)) } } } diff --git a/internal/app/seal_linux.go b/internal/app/seal_linux.go index 23d65f9..fb6f39b 100644 --- a/internal/app/seal_linux.go +++ b/internal/app/seal_linux.go @@ -244,8 +244,14 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co Tty: true, AutoEtc: true, - AutoRoot: container.AbsFHSRoot, - RootFlags: container.BindWritable, + Filesystem: []hst.FilesystemConfigJSON{ + {&hst.FSBind{ + Target: container.AbsFHSRoot, + Source: container.AbsFHSRoot, + Write: true, + AutoRoot: true, + }}, + }, } // bind GPU stuff