diff options
| author | Ophestra Umiker <cat@ophivana.moe> | 2024-11-02 03:03:44 +0900 |
|---|---|---|
| committer | Ophestra Umiker <cat@ophivana.moe> | 2024-11-02 03:13:57 +0900 |
| commit | 584732f80ab91afb349720cfb8e9979ed2ba173e (patch) | |
| tree | 8ef6ab9f8c9d3b8197682a53fb2c4a7b2ce8da55 /internal/linux | |
| parent | 4b7b899bb35fb4ea218dabe49a674f4d2f80e7f8 (diff) | |
cmd: shim and init into separate binaries
This change also fixes a deadlock when shim fails to connect and complete the setup.
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/linux')
| -rw-r--r-- | internal/linux/interface.go | 69 | ||||
| -rw-r--r-- | internal/linux/std.go | 83 |
2 files changed, 152 insertions, 0 deletions
diff --git a/internal/linux/interface.go b/internal/linux/interface.go new file mode 100644 index 00000000..cf984a32 --- /dev/null +++ b/internal/linux/interface.go @@ -0,0 +1,69 @@ +package linux + +import ( + "io/fs" + "os/user" + "path" + "strconv" + + "git.ophivana.moe/security/fortify/internal/fmsg" +) + +// System provides safe access to operating system resources. +type System interface { + // Geteuid provides [os.Geteuid]. + Geteuid() int + // LookupEnv provides [os.LookupEnv]. + LookupEnv(key string) (string, bool) + // TempDir provides [os.TempDir]. + TempDir() string + // LookPath provides [exec.LookPath]. + LookPath(file string) (string, error) + // Executable provides [os.Executable]. + Executable() (string, error) + // Lookup provides [user.Lookup]. + Lookup(username string) (*user.User, error) + // ReadDir provides [os.ReadDir]. + ReadDir(name string) ([]fs.DirEntry, error) + // Stat provides [os.Stat]. + Stat(name string) (fs.FileInfo, error) + // Open provides [os.Open] + Open(name string) (fs.File, error) + // Exit provides [os.Exit]. + Exit(code int) + + // FshimPath returns an absolute path to the fshim binary. + FshimPath() string + // Paths returns a populated [Paths] struct. + Paths() Paths + // SdBooted implements https://www.freedesktop.org/software/systemd/man/sd_booted.html + SdBooted() bool +} + +// Paths contains environment dependent paths used by fortify. +type Paths struct { + // path to shared directory e.g. /tmp/fortify.%d + SharePath string `json:"share_path"` + // XDG_RUNTIME_DIR value e.g. /run/user/%d + RuntimePath string `json:"runtime_path"` + // application runtime directory e.g. /run/user/%d/fortify + RunDirPath string `json:"run_dir_path"` +} + +// CopyPaths is a generic implementation of [System.Paths]. +func CopyPaths(os System, v *Paths) { + v.SharePath = path.Join(os.TempDir(), "fortify."+strconv.Itoa(os.Geteuid())) + + fmsg.VPrintf("process share directory at %q", v.SharePath) + + if r, ok := os.LookupEnv(xdgRuntimeDir); !ok || r == "" || !path.IsAbs(r) { + // fall back to path in share since fortify has no hard XDG dependency + v.RunDirPath = path.Join(v.SharePath, "run") + v.RuntimePath = path.Join(v.RunDirPath, "compat") + } else { + v.RuntimePath = r + v.RunDirPath = path.Join(v.RuntimePath, "fortify") + } + + fmsg.VPrintf("runtime directory at %q", v.RunDirPath) +} diff --git a/internal/linux/std.go b/internal/linux/std.go new file mode 100644 index 00000000..704ba162 --- /dev/null +++ b/internal/linux/std.go @@ -0,0 +1,83 @@ +package linux + +import ( + "errors" + "io/fs" + "os" + "os/exec" + "os/user" + "sync" + + "git.ophivana.moe/security/fortify/internal" + "git.ophivana.moe/security/fortify/internal/fmsg" +) + +// Std implements System using the standard library. +type Std struct { + paths Paths + pathsOnce sync.Once + + sdBooted bool + sdBootedOnce sync.Once + + fshim string + fshimOnce sync.Once +} + +func (s *Std) Geteuid() int { return os.Geteuid() } +func (s *Std) LookupEnv(key string) (string, bool) { return os.LookupEnv(key) } +func (s *Std) TempDir() string { return os.TempDir() } +func (s *Std) LookPath(file string) (string, error) { return exec.LookPath(file) } +func (s *Std) Executable() (string, error) { return os.Executable() } +func (s *Std) Lookup(username string) (*user.User, error) { return user.Lookup(username) } +func (s *Std) ReadDir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) } +func (s *Std) Stat(name string) (fs.FileInfo, error) { return os.Stat(name) } +func (s *Std) Open(name string) (fs.File, error) { return os.Open(name) } +func (s *Std) Exit(code int) { fmsg.Exit(code) } + +const xdgRuntimeDir = "XDG_RUNTIME_DIR" + +func (s *Std) FshimPath() string { + s.fshimOnce.Do(func() { + p, ok := internal.Path(internal.Fshim) + if !ok { + fmsg.Fatal("invalid fshim path, this copy of fortify is not compiled correctly") + } + s.fshim = p + }) + + return s.fshim +} + +func (s *Std) Paths() Paths { + s.pathsOnce.Do(func() { CopyPaths(s, &s.paths) }) + return s.paths +} + +func (s *Std) SdBooted() bool { + s.sdBootedOnce.Do(func() { s.sdBooted = copySdBooted() }) + return s.sdBooted +} + +const systemdCheckPath = "/run/systemd/system" + +func copySdBooted() bool { + if v, err := sdBooted(); err != nil { + fmsg.Println("cannot read systemd marker:", err) + return false + } else { + return v + } +} + +func sdBooted() (bool, error) { + _, err := os.Stat(systemdCheckPath) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + err = nil + } + return false, err + } + + return true, nil +} |
