cmd: shim and init into separate binaries
All checks were successful
test / test (push) Successful in 19s
All checks were successful
test / test (push) Successful in 19s
This change also fixes a deadlock when shim fails to connect and complete the setup. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
69
internal/linux/interface.go
Normal file
69
internal/linux/interface.go
Normal file
@@ -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)
|
||||
}
|
||||
83
internal/linux/std.go
Normal file
83
internal/linux/std.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user