From 4cf694d2b31c7aa5c66cbb83d7d54c1a6cb1b4aa Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 26 Aug 2025 02:15:00 +0900 Subject: [PATCH] hst: use hsu userid for share path suffix The privileged user is identifier to hakurei through its hsu userid. Using the kernel uid here makes little sense and is a leftover design choice from before hsu was implemented. Closes #7. Signed-off-by: Ophestra --- cmd/hpkg/test/test.py | 2 +- hst/hst.go | 6 ++++-- internal/sys/interface.go | 25 +++++++++++++++++-------- internal/sys/std.go | 20 ++++++++++++++------ test/sandbox/case/device.nix | 4 ++-- test/sandbox/case/mapuid.nix | 4 ++-- test/sandbox/case/pd.nix | 4 ++-- test/sandbox/case/pdlike.nix | 4 ++-- test/sandbox/case/preset.nix | 4 ++-- test/sandbox/case/tty.nix | 4 ++-- test/sandbox/test.py | 2 +- test/test.py | 8 ++++---- 12 files changed, 53 insertions(+), 34 deletions(-) diff --git a/cmd/hpkg/test/test.py b/cmd/hpkg/test/test.py index 5a199ac..d491def 100644 --- a/cmd/hpkg/test/test.py +++ b/cmd/hpkg/test/test.py @@ -90,7 +90,7 @@ machine.wait_for_file("/tmp/hpkg-install-ok") swaymsg("exec hpkg -v start org.codeberg.dnkl.foot") wait_for_window("hakurei@machine-foot") machine.send_chars("clear; wayland-info && touch /tmp/success-client\n") -machine.wait_for_file("/tmp/hakurei.1000/tmpdir/2/success-client") +machine.wait_for_file("/tmp/hakurei.0/tmpdir/2/success-client") collect_state_ui("app_wayland") check_state("foot", {"wayland": True, "dbus": True, "pulse": True}) # Verify acl on XDG_RUNTIME_DIR: diff --git a/hst/hst.go b/hst/hst.go index 6549450..d9c1168 100644 --- a/hst/hst.go +++ b/hst/hst.go @@ -12,16 +12,18 @@ import ( type Paths struct { // temporary directory returned by [os.TempDir] (usually `/tmp`) TempDir *container.Absolute `json:"temp_dir"` - // path to shared directory (usually `/tmp/hakurei.%d`) + // path to shared directory (usually `/tmp/hakurei.%d`, [Info.User]) SharePath *container.Absolute `json:"share_path"` - // XDG_RUNTIME_DIR value (usually `/run/user/%d`) + // XDG_RUNTIME_DIR value (usually `/run/user/%d`, uid) RuntimePath *container.Absolute `json:"runtime_path"` // application runtime directory (usually `/run/user/%d/hakurei`) RunDirPath *container.Absolute `json:"run_dir_path"` } type Info struct { + // User is the userid according to hsu. User int `json:"user"` + Paths } diff --git a/internal/sys/interface.go b/internal/sys/interface.go index 5dbe18e..ed765ec 100644 --- a/internal/sys/interface.go +++ b/internal/sys/interface.go @@ -22,9 +22,9 @@ type State interface { LookupEnv(key string) (string, bool) // TempDir provides [os.TempDir]. TempDir() string - // LookPath provides [exec.LookPath]. + // LookPath provides exec.LookPath. LookPath(file string) (string, error) - // MustExecutable provides [proc.MustExecutable]. + // MustExecutable provides [container.MustExecutable]. MustExecutable() string // LookupGroup provides [user.LookupGroup]. LookupGroup(name string) (*user.Group, error) @@ -32,9 +32,9 @@ type State interface { ReadDir(name string) ([]fs.DirEntry, error) // Stat provides [os.Stat]. Stat(name string) (fs.FileInfo, error) - // Open provides [os.Open] + // Open provides [os.Open]. Open(name string) (fs.File, error) - // EvalSymlinks provides [filepath.EvalSymlinks] + // EvalSymlinks provides filepath.EvalSymlinks. EvalSymlinks(path string) (string, error) // Exit provides [os.Exit]. Exit(code int) @@ -45,19 +45,28 @@ type State interface { // Paths returns a populated [hst.Paths] struct. Paths() hst.Paths // Uid invokes hsu and returns target uid. - // Any errors returned by Uid is already wrapped [fmsg.BaseError]. - Uid(aid int) (int, error) + // Any errors returned by Uid is already wrapped [hlog.BaseError]. + Uid(identity int) (int, error) +} + +// GetUserID obtains user id from hsu by querying uid of identity 0. +func GetUserID(os State) (int, error) { + if uid, err := os.Uid(0); err != nil { + return -1, err + } else { + return (uid / 10000) - 100, nil + } } // CopyPaths is a generic implementation of [hst.Paths]. -func CopyPaths(os State, v *hst.Paths) { +func CopyPaths(os State, v *hst.Paths, userid int) { if tempDir, err := container.NewAbs(os.TempDir()); err != nil { log.Fatalf("invalid TMPDIR: %v", err) } else { v.TempDir = tempDir } - v.SharePath = v.TempDir.Append("hakurei." + strconv.Itoa(os.Getuid())) + v.SharePath = v.TempDir.Append("hakurei." + strconv.Itoa(userid)) hlog.Verbosef("process share directory at %q", v.SharePath) r, _ := os.LookupEnv(xdgRuntimeDir) diff --git a/internal/sys/std.go b/internal/sys/std.go index 89fdd28..828cbc4 100644 --- a/internal/sys/std.go +++ b/internal/sys/std.go @@ -49,11 +49,19 @@ func (s *Std) Printf(format string, v ...any) { hlog.Verbosef(form const xdgRuntimeDir = "XDG_RUNTIME_DIR" func (s *Std) Paths() hst.Paths { - s.pathsOnce.Do(func() { CopyPaths(s, &s.paths) }) + s.pathsOnce.Do(func() { + if userid, err := GetUserID(s); err != nil { + hlog.PrintBaseError(err, "cannot obtain user id from hsu:") + hlog.BeforeExit() + s.Exit(1) + } else { + CopyPaths(s, &s.paths, userid) + } + }) return s.paths } -func (s *Std) Uid(aid int) (int, error) { +func (s *Std) Uid(identity int) (int, error) { s.uidOnce.Do(func() { s.uidCopy = make(map[int]struct { uid int @@ -63,7 +71,7 @@ func (s *Std) Uid(aid int) (int, error) { { s.uidMu.RLock() - u, ok := s.uidCopy[aid] + u, ok := s.uidCopy[identity] s.uidMu.RUnlock() if ok { return u.uid, u.err @@ -77,7 +85,7 @@ func (s *Std) Uid(aid int) (int, error) { uid int err error }{} - defer func() { s.uidCopy[aid] = u }() + defer func() { s.uidCopy[identity] = u }() u.uid = -1 hsuPath := internal.MustHsuPath() @@ -85,7 +93,7 @@ func (s *Std) Uid(aid int) (int, error) { cmd := exec.Command(hsuPath) cmd.Path = hsuPath cmd.Stderr = os.Stderr // pass through fatal messages - cmd.Env = []string{"HAKUREI_APP_ID=" + strconv.Itoa(aid)} + cmd.Env = []string{"HAKUREI_APP_ID=" + strconv.Itoa(identity)} cmd.Dir = container.FHSRoot var ( p []byte @@ -95,7 +103,7 @@ func (s *Std) Uid(aid int) (int, error) { if p, u.err = cmd.Output(); u.err == nil { u.uid, u.err = strconv.Atoi(string(p)) if u.err != nil { - u.err = hlog.WrapErrSuffix(u.err, "cannot parse uid from hsu:") + u.err = hlog.WrapErr(u.err, "invalid uid string from hsu") } } else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 { u.err = hlog.WrapErr(syscall.EACCES, "") // hsu prints to stderr in this case diff --git a/test/sandbox/case/device.nix b/test/sandbox/case/device.nix index 5d607d9..831b6ab 100644 --- a/test/sandbox/case/device.nix +++ b/test/sandbox/case/device.nix @@ -230,8 +230,8 @@ in (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/var/lib/hakurei/u0/a4" "/var/lib/hakurei/u0/a4" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000004,gid=1000004") - (ent "/tmp/hakurei.1000/runtime/4" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") - (ent "/tmp/hakurei.1000/tmpdir/4" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (ent "/tmp/hakurei.0/runtime/4" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (ent "/tmp/hakurei.0/tmpdir/4" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000004,gid=1000004") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000004,gid=1000004") (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") diff --git a/test/sandbox/case/mapuid.nix b/test/sandbox/case/mapuid.nix index c18bf79..486d439 100644 --- a/test/sandbox/case/mapuid.nix +++ b/test/sandbox/case/mapuid.nix @@ -257,8 +257,8 @@ in (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 "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000003,gid=1000003") - (ent "/tmp/hakurei.1000/runtime/3" "/run/user/1000" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") - (ent "/tmp/hakurei.1000/tmpdir/3" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (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") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000003,gid=1000003") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000003,gid=1000003") (ent ignore "/run/user/1000/wayland-0" "ro,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 14b62b4..6bad3e7 100644 --- a/test/sandbox/case/pd.nix +++ b/test/sandbox/case/pd.nix @@ -186,8 +186,8 @@ (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 "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000000,gid=1000000") - (ent "/tmp/hakurei.1000/runtime/0" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") - (ent "/tmp/hakurei.1000/tmpdir/0" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (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") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000000,gid=1000000") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000000,gid=1000000") ]; diff --git a/test/sandbox/case/pdlike.nix b/test/sandbox/case/pdlike.nix index c87ab46..1fdc592 100644 --- a/test/sandbox/case/pdlike.nix +++ b/test/sandbox/case/pdlike.nix @@ -252,8 +252,8 @@ in (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 "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000005,gid=1000005") - (ent "/tmp/hakurei.1000/runtime/5" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") - (ent "/tmp/hakurei.1000/tmpdir/5" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (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") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000005,gid=1000005") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000005,gid=1000005") (ent ignore "/run/user/65534/wayland-0" "ro,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 d8f6879..721659f 100644 --- a/test/sandbox/case/preset.nix +++ b/test/sandbox/case/preset.nix @@ -250,8 +250,8 @@ in (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 "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000001,gid=1000001") - (ent "/tmp/hakurei.1000/runtime/1" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") - (ent "/tmp/hakurei.1000/tmpdir/1" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (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") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000001,gid=1000001") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000001,gid=1000001") (ent ignore "/run/user/65534/wayland-0" "ro,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 15b60ad..0aed783 100644 --- a/test/sandbox/case/tty.nix +++ b/test/sandbox/case/tty.nix @@ -262,8 +262,8 @@ in (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 "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "ephemeral" "rw,size=4k,mode=755,uid=1000002,gid=1000002") - (ent "/tmp/hakurei.1000/runtime/2" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") - (ent "/tmp/hakurei.1000/tmpdir/2" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") + (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") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002") (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") diff --git a/test/sandbox/test.py b/test/sandbox/test.py index 6ae3e14..5997b89 100644 --- a/test/sandbox/test.py +++ b/test/sandbox/test.py @@ -60,7 +60,7 @@ check_offset = 0 def check_sandbox(name): global check_offset swaymsg(f"exec script /dev/null -E always -qec check-sandbox-{name}") - machine.wait_for_file(f"/tmp/hakurei.1000/tmpdir/{check_offset}/sandbox-ok", timeout=15) + machine.wait_for_file(f"/tmp/hakurei.0/tmpdir/{check_offset}/sandbox-ok", timeout=15) check_filter(check_offset, name, "hakurei-test") check_offset += 1 diff --git a/test/test.py b/test/test.py index c02766c..9625353 100644 --- a/test/test.py +++ b/test/test.py @@ -113,12 +113,12 @@ def aid(offset): def tmpdir_path(offset, name): - return f"/tmp/hakurei.1000/tmpdir/{aid(offset)}/{name}" + return f"/tmp/hakurei.0/tmpdir/{aid(offset)}/{name}" # Start hakurei permissive defaults outside Wayland session: print(machine.succeed("sudo -u alice -i hakurei -v run -a 0 touch /tmp/pd-bare-ok")) -machine.wait_for_file("/tmp/hakurei.1000/tmpdir/0/pd-bare-ok", timeout=5) +machine.wait_for_file("/tmp/hakurei.0/tmpdir/0/pd-bare-ok", timeout=5) # Verify silent output permissive defaults: output = machine.succeed("sudo -u alice -i hakurei run -a 0 true &>/dev/stdout") @@ -131,8 +131,8 @@ def silent_output_interrupt(flags): wait_for_window("alice@machine") # aid 0 does not have home-manager machine.send_chars(f"exec hakurei run {flags}-a 0 sh -c 'export PATH=/run/current-system/sw/bin:$PATH && touch /tmp/pd-silent-ready && sleep infinity' &>/tmp/pd-silent\n") - machine.wait_for_file("/tmp/hakurei.1000/tmpdir/0/pd-silent-ready", timeout=15) - machine.succeed("rm /tmp/hakurei.1000/tmpdir/0/pd-silent-ready") + machine.wait_for_file("/tmp/hakurei.0/tmpdir/0/pd-silent-ready", timeout=15) + machine.succeed("rm /tmp/hakurei.0/tmpdir/0/pd-silent-ready") machine.send_key("ctrl-c") machine.wait_until_fails("pgrep foot", timeout=5) machine.wait_until_fails(f"pgrep -u alice -f 'hakurei run {flags}-a 0 '", timeout=5)