From 084cd84f36a1d608541b4aa4e1e95334395d8953 Mon Sep 17 00:00:00 2001 From: Ophestra Umiker Date: Wed, 16 Oct 2024 01:38:59 +0900 Subject: [PATCH] app: port app to use the system package This commit does away with almost all baggage left over from the Ego port. Error wrapping also got simplified. All API changes happens to be internal which means no changes to main except renaming of the BaseError type. Signed-off-by: Ophestra Umiker --- error.go | 11 +- internal/app/app.go | 2 +- internal/app/config.go | 6 +- internal/app/copy.go | 33 --- internal/app/error.go | 51 ----- internal/app/launch.machinectl.go | 11 +- internal/app/launch.sudo.go | 2 +- internal/app/seal.go | 47 ++-- internal/app/share.dbus.go | 118 +--------- internal/app/share.display.go | 21 +- internal/app/share.pulse.go | 46 ++-- internal/app/share.runtime.go | 22 +- internal/app/share.system.go | 30 +-- internal/app/start.go | 50 ++-- internal/app/system.go | 365 ++---------------------------- 15 files changed, 144 insertions(+), 671 deletions(-) delete mode 100644 internal/app/copy.go delete mode 100644 internal/app/error.go diff --git a/error.go b/error.go index ee48684..a941ac5 100644 --- a/error.go +++ b/error.go @@ -6,11 +6,12 @@ import ( "os" "git.ophivana.moe/cat/fortify/internal/app" + "git.ophivana.moe/cat/fortify/internal/fmsg" ) func logWaitError(err error) { - var e *app.BaseError - if !app.AsBaseError(err, &e) { + var e *fmsg.BaseError + if !fmsg.AsBaseError(err, &e) { fmt.Println("fortify: wait failed:", err) } else { // Wait only returns either *app.ProcessError or *app.StateStoreError wrapped in a *app.BaseError @@ -31,7 +32,7 @@ func logWaitError(err error) { // every error here is wrapped in *app.BaseError for _, ei := range errs { - var eb *app.BaseError + var eb *fmsg.BaseError if !errors.As(ei, &eb) { // unreachable fmt.Println("fortify: invalid error type returned by revert:", ei) @@ -46,9 +47,9 @@ func logWaitError(err error) { } func logBaseError(err error, message string) { - var e *app.BaseError + var e *fmsg.BaseError - if app.AsBaseError(err, &e) { + if fmsg.AsBaseError(err, &e) { fmt.Print("fortify: " + e.Message()) } else { fmt.Println(message, err) diff --git a/internal/app/app.go b/internal/app/app.go index 50d59da..a04ae74 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -40,7 +40,7 @@ func (a *app) String() string { } if a.seal != nil { - return "(sealed fortified app as uid " + a.seal.sys.Uid + ")" + return "(sealed fortified app as uid " + a.seal.sys.user.Uid + ")" } return "(unsealed fortified app)" diff --git a/internal/app/config.go b/internal/app/config.go index 3f6d1c0..72648f0 100644 --- a/internal/app/config.go +++ b/internal/app/config.go @@ -61,8 +61,8 @@ type SandboxConfig struct { Env map[string]string `json:"env"` // sandbox host filesystem access Filesystem []*FilesystemConfig `json:"filesystem"` - // tmpfs mount points to mount last - Tmpfs []string `json:"tmpfs"` + // paths to override by mounting tmpfs over them + Override []string `json:"override"` } type FilesystemConfig struct { @@ -149,7 +149,7 @@ func Template() *Config { {Src: "/data/user/0", Dst: "/data/data", Write: true, Must: true}, {Src: "/var/tmp", Write: true}, }, - Tmpfs: []string{"/var/run/nscd"}, + Override: []string{"/var/run/nscd"}, }, SystemBus: &dbus.Config{ See: nil, diff --git a/internal/app/copy.go b/internal/app/copy.go deleted file mode 100644 index bf90bfe..0000000 --- a/internal/app/copy.go +++ /dev/null @@ -1,33 +0,0 @@ -package app - -import ( - "io" - "os" -) - -func copyFile(dst, src string) error { - srcD, err := os.Open(src) - if err != nil { - return err - } - defer func() { - if srcD.Close() != nil { - // unreachable - panic("src file closed prematurely") - } - }() - - dstD, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) - if err != nil { - return err - } - defer func() { - if dstD.Close() != nil { - // unreachable - panic("dst file closed prematurely") - } - }() - - _, err = io.Copy(dstD, srcD) - return err -} diff --git a/internal/app/error.go b/internal/app/error.go deleted file mode 100644 index 7c18a89..0000000 --- a/internal/app/error.go +++ /dev/null @@ -1,51 +0,0 @@ -package app - -import ( - "fmt" - "reflect" -) - -// baseError implements a basic error container -type baseError struct { - Err error -} - -func (e *baseError) Error() string { - return e.Err.Error() -} - -func (e *baseError) Unwrap() error { - return e.Err -} - -// BaseError implements an error container with a user-facing message -type BaseError struct { - message string - baseError -} - -// Message returns a user-facing error message -func (e *BaseError) Message() string { - return e.message -} - -func wrapError(err error, a ...any) *BaseError { - return &BaseError{ - message: fmt.Sprintln(a...), - baseError: baseError{err}, - } -} - -var ( - baseErrorType = reflect.TypeFor[*BaseError]() -) - -func AsBaseError(err error, target **BaseError) bool { - v := reflect.ValueOf(err) - if !v.CanConvert(baseErrorType) { - return false - } - - *target = v.Convert(baseErrorType).Interface().(*BaseError) - return true -} diff --git a/internal/app/launch.machinectl.go b/internal/app/launch.machinectl.go index 9fb9ea0..606fd9d 100644 --- a/internal/app/launch.machinectl.go +++ b/internal/app/launch.machinectl.go @@ -4,7 +4,6 @@ import ( "os/exec" "strings" - "git.ophivana.moe/cat/fortify/internal/state" "git.ophivana.moe/cat/fortify/internal/verbose" ) @@ -12,7 +11,7 @@ func (a *app) commandBuilderMachineCtl(shimEnv string) (args []string) { args = make([]string, 0, 9+len(a.seal.sys.bwrap.SetEnv)) // shell --uid=$USER - args = append(args, "shell", "--uid="+a.seal.sys.Username) + args = append(args, "shell", "--uid="+a.seal.sys.user.Username) // --quiet if !verbose.Get() { @@ -49,14 +48,6 @@ func (a *app) commandBuilderMachineCtl(shimEnv string) (args []string) { } innerCommand.WriteString("; ") - // override message bus address if enabled - if a.seal.et.Has(state.EnableDBus) { - innerCommand.WriteString(dbusSessionBusAddress + "=" + "'" + "unix:path=" + a.seal.sys.dbusAddr[0][1] + "' ") - if a.seal.sys.dbusSystem { - innerCommand.WriteString(dbusSystemBusAddress + "=" + "'" + "unix:path=" + a.seal.sys.dbusAddr[1][1] + "' ") - } - } - // launch fortify as shim innerCommand.WriteString("exec " + a.seal.sys.executable + " shim") diff --git a/internal/app/launch.sudo.go b/internal/app/launch.sudo.go index 3e364ac..965af96 100644 --- a/internal/app/launch.sudo.go +++ b/internal/app/launch.sudo.go @@ -14,7 +14,7 @@ func (a *app) commandBuilderSudo(shimEnv string) (args []string) { args = make([]string, 0, 8) // -Hiu $USER - args = append(args, "-Hiu", a.seal.sys.Username) + args = append(args, "-Hiu", a.seal.sys.user.Username) // -A? if _, ok := os.LookupEnv(sudoAskPass); ok { diff --git a/internal/app/seal.go b/internal/app/seal.go index bf634c4..76ce8d3 100644 --- a/internal/app/seal.go +++ b/internal/app/seal.go @@ -10,7 +10,9 @@ import ( "git.ophivana.moe/cat/fortify/dbus" "git.ophivana.moe/cat/fortify/internal" + "git.ophivana.moe/cat/fortify/internal/fmsg" "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal/system" "git.ophivana.moe/cat/fortify/internal/verbose" ) @@ -29,12 +31,6 @@ var ( ErrMachineCtl = errors.New("machinectl not available") ) -type ( - SealConfigError BaseError - LauncherLookupError BaseError - SecurityError BaseError -) - // Seal seals the app launch context func (a *app) Seal(config *Config) error { a.lock.Lock() @@ -45,7 +41,8 @@ func (a *app) Seal(config *Config) error { } if config == nil { - return (*SealConfigError)(wrapError(ErrConfig, "attempted to seal app with nil config")) + return fmsg.WrapError(ErrConfig, + "attempted to seal app with nil config") } // create seal @@ -53,7 +50,8 @@ func (a *app) Seal(config *Config) error { // generate application ID if id, err := newAppID(); err != nil { - return (*SecurityError)(wrapError(err, "cannot generate application ID:", err)) + return fmsg.WrapErrorSuffix(err, + "cannot generate application ID:") } else { seal.id = id } @@ -70,32 +68,35 @@ func (a *app) Seal(config *Config) error { case "sudo": seal.launchOption = LaunchMethodSudo if sudoPath, err := exec.LookPath("sudo"); err != nil { - return (*LauncherLookupError)(wrapError(ErrSudo, "sudo not found")) + return fmsg.WrapError(ErrSudo, + "sudo not found") } else { seal.toolPath = sudoPath } case "systemd": seal.launchOption = LaunchMethodMachineCtl if !internal.SdBootedV { - return (*LauncherLookupError)(wrapError(ErrSystemd, - "system has not been booted with systemd as init system")) + return fmsg.WrapError(ErrSystemd, + "system has not been booted with systemd as init system") } if machineCtlPath, err := exec.LookPath("machinectl"); err != nil { - return (*LauncherLookupError)(wrapError(ErrMachineCtl, "machinectl not found")) + return fmsg.WrapError(ErrMachineCtl, + "machinectl not found") } else { seal.toolPath = machineCtlPath } default: - return (*SealConfigError)(wrapError(ErrLaunch, "invalid launch method")) + return fmsg.WrapError(ErrLaunch, + "invalid launch method") } // create seal system component - seal.sys = new(appSealTx) + seal.sys = new(appSealSys) // look up fortify executable path if p, err := os.Executable(); err != nil { - return (*LauncherLookupError)(wrapError(err, "cannot look up fortify executable path:", err)) + return fmsg.WrapErrorSuffix(err, "cannot look up fortify executable path:") } else { seal.sys.executable = p } @@ -103,13 +104,13 @@ func (a *app) Seal(config *Config) error { // look up user from system if u, err := user.Lookup(config.User); err != nil { if errors.As(err, new(user.UnknownUserError)) { - return (*SealConfigError)(wrapError(ErrUser, "unknown user", config.User)) + return fmsg.WrapError(ErrUser, "unknown user", config.User) } else { // unreachable panic(err) } } else { - seal.sys.User = u + seal.sys.user = u seal.sys.runtime = path.Join("/run/user", u.Uid) } @@ -163,7 +164,7 @@ func (a *app) Seal(config *Config) error { // hide nscd from sandbox if present nscd := "/var/run/nscd" if _, err := os.Stat(nscd); !errors.Is(err, os.ErrNotExist) { - conf.Tmpfs = append(conf.Tmpfs, nscd) + conf.Override = append(conf.Override, nscd) } // bind GPU stuff if config.Confinement.Enablements.Has(state.EnableX) || config.Confinement.Enablements.Has(state.EnableWayland) { @@ -172,7 +173,7 @@ func (a *app) Seal(config *Config) error { config.Confinement.Sandbox = conf } seal.sys.bwrap = config.Confinement.Sandbox.Bwrap() - seal.sys.tmpfs = config.Confinement.Sandbox.Tmpfs + seal.sys.override = config.Confinement.Sandbox.Override if seal.sys.bwrap.SetEnv == nil { seal.sys.bwrap.SetEnv = make(map[string]string) } @@ -186,14 +187,14 @@ func (a *app) Seal(config *Config) error { // open process state store // the simple store only starts holding an open file after first action // store activity begins after Start is called and must end before Wait - seal.store = state.NewSimple(seal.SystemConstants.RunDirPath, seal.sys.Uid) + seal.store = state.NewSimple(seal.SystemConstants.RunDirPath, seal.sys.user.Uid) // parse string UID - if u, err := strconv.Atoi(seal.sys.Uid); err != nil { + if u, err := strconv.Atoi(seal.sys.user.Uid); err != nil { // unreachable unless kernel bug panic("uid parse") } else { - seal.sys.uid = u + seal.sys.I = system.New(u) } // pass through enablements @@ -206,7 +207,7 @@ func (a *app) Seal(config *Config) error { // verbose log seal information verbose.Println("created application seal as user", - seal.sys.Username, "("+seal.sys.Uid+"),", + seal.sys.user.Username, "("+seal.sys.user.Uid+"),", "method:", config.Method+",", "launcher:", seal.toolPath+",", "command:", config.Command) diff --git a/internal/app/share.dbus.go b/internal/app/share.dbus.go index 912cd97..6b0ff43 100644 --- a/internal/app/share.dbus.go +++ b/internal/app/share.dbus.go @@ -1,15 +1,11 @@ package app import ( - "errors" - "fmt" - "os" "path" "git.ophivana.moe/cat/fortify/acl" "git.ophivana.moe/cat/fortify/dbus" "git.ophivana.moe/cat/fortify/internal/state" - "git.ophivana.moe/cat/fortify/internal/verbose" ) const ( @@ -17,122 +13,30 @@ const ( dbusSystemBusAddress = "DBUS_SYSTEM_BUS_ADDRESS" ) -var ( - ErrDBusConfig = errors.New("dbus config not supplied") -) - -type ( - SealDBusError BaseError - LookupDBusError BaseError - StartDBusError BaseError - CloseDBusError BaseError -) - func (seal *appSeal) shareDBus(config [2]*dbus.Config) error { if !seal.et.Has(state.EnableDBus) { return nil } - // session bus is mandatory - if config[0] == nil { - return (*SealDBusError)(wrapError(ErrDBusConfig, "attempted to seal session bus proxy with nil config")) - } - - // system bus is optional - seal.sys.dbusSystem = config[1] != nil - - // upstream address, downstream socket path - var sessionBus, systemBus [2]string - // downstream socket paths - sessionBus[1] = path.Join(seal.share, "bus") - systemBus[1] = path.Join(seal.share, "system_bus_socket") + sessionPath, systemPath := path.Join(seal.share, "bus"), path.Join(seal.share, "system_bus_socket") - // resolve upstream bus addresses - sessionBus[0], systemBus[0] = dbus.Address() - - // create proxy instance - seal.sys.dbus = dbus.New(sessionBus, systemBus) - - // seal dbus proxy - if err := seal.sys.dbus.Seal(config[0], config[1]); err != nil { - return (*SealDBusError)(wrapError(err, "cannot seal message bus proxy:", err)) + // configure dbus proxy + if err := seal.sys.ProxyDBus(config[0], config[1], sessionPath, systemPath); err != nil { + return err } - // store addresses for cleanup and logging - seal.sys.dbusAddr = &[2][2]string{sessionBus, systemBus} - // share proxy sockets sessionInner := path.Join(seal.sys.runtime, "bus") - seal.sys.setEnv(dbusSessionBusAddress, "unix:path="+sessionInner) - seal.sys.bwrap.Bind(sessionBus[1], sessionInner) - seal.sys.updatePerm(sessionBus[1], acl.Read, acl.Write) - if seal.sys.dbusSystem { + seal.sys.bwrap.SetEnv[dbusSessionBusAddress] = "unix:path=" + sessionInner + seal.sys.bwrap.Bind(sessionPath, sessionInner) + seal.sys.UpdatePerm(sessionPath, acl.Read, acl.Write) + if config[1] != nil { systemInner := "/run/dbus/system_bus_socket" - seal.sys.setEnv(dbusSystemBusAddress, "unix:path="+systemInner) - seal.sys.bwrap.Bind(systemBus[1], systemInner) - seal.sys.updatePerm(systemBus[1], acl.Read, acl.Write) + seal.sys.bwrap.SetEnv[dbusSystemBusAddress] = "unix:path=" + systemInner + seal.sys.bwrap.Bind(systemPath, systemInner) + seal.sys.UpdatePerm(systemPath, acl.Read, acl.Write) } return nil } - -func (tx *appSealTx) startDBus() error { - // ready channel passed to dbus package - ready := make(chan error, 1) - // used by waiting goroutine to notify process return - tx.dbusWait = make(chan struct{}) - - // background dbus proxy start - if err := tx.dbus.Start(ready, os.Stderr, true); err != nil { - return (*StartDBusError)(wrapError(err, "cannot start message bus proxy:", err)) - } - verbose.Println("starting message bus proxy:", tx.dbus) - verbose.Println("message bus proxy bwrap args:", tx.dbus.Bwrap()) - - // background wait for proxy instance and notify completion - go func() { - if err := tx.dbus.Wait(); err != nil { - fmt.Println("fortify: warn: message bus proxy returned error:", err) - go func() { ready <- err }() - } else { - verbose.Println("message bus proxy exit") - } - - // ensure socket removal so ephemeral directory is empty at revert - if err := os.Remove(tx.dbusAddr[0][1]); err != nil && !errors.Is(err, os.ErrNotExist) { - fmt.Println("fortify: cannot remove dangling session bus socket:", err) - } - if tx.dbusSystem { - if err := os.Remove(tx.dbusAddr[1][1]); err != nil && !errors.Is(err, os.ErrNotExist) { - fmt.Println("fortify: cannot remove dangling system bus socket:", err) - } - } - - // notify proxy completion - tx.dbusWait <- struct{}{} - }() - - // ready is not nil if the proxy process faulted - if err := <-ready; err != nil { - // note that err here is either an I/O related error or a predetermined unexpected behaviour error - return (*StartDBusError)(wrapError(err, "message bus proxy fault after start:", err)) - } - verbose.Println("message bus proxy ready") - - return nil -} - -func (tx *appSealTx) stopDBus() error { - if err := tx.dbus.Close(); err != nil { - if errors.Is(err, os.ErrClosed) { - return (*CloseDBusError)(wrapError(err, "message bus proxy already closed")) - } else { - return (*CloseDBusError)(wrapError(err, "cannot close message bus proxy:", err)) - } - } - - // block until proxy wait returns - <-tx.dbusWait - return nil -} diff --git a/internal/app/share.display.go b/internal/app/share.display.go index 86343d8..2675c01 100644 --- a/internal/app/share.display.go +++ b/internal/app/share.display.go @@ -6,6 +6,7 @@ import ( "path" "git.ophivana.moe/cat/fortify/acl" + "git.ophivana.moe/cat/fortify/internal/fmsg" "git.ophivana.moe/cat/fortify/internal/state" ) @@ -22,29 +23,28 @@ var ( ErrXDisplay = errors.New(display + " unset") ) -type ErrDisplayEnv BaseError - func (seal *appSeal) shareDisplay() error { // pass $TERM to launcher if t, ok := os.LookupEnv(term); ok { - seal.sys.setEnv(term, t) + seal.sys.bwrap.SetEnv[term] = t } // set up wayland if seal.et.Has(state.EnableWayland) { if wd, ok := os.LookupEnv(waylandDisplay); !ok { - return (*ErrDisplayEnv)(wrapError(ErrWayland, "WAYLAND_DISPLAY is not set")) + return fmsg.WrapError(ErrWayland, + "WAYLAND_DISPLAY is not set") } else if seal.wlDone == nil { // hardlink wayland socket wp := path.Join(seal.RuntimePath, wd) wpi := path.Join(seal.shareLocal, "wayland") w := path.Join(seal.sys.runtime, "wayland-0") - seal.sys.link(wp, wpi) - seal.sys.setEnv(waylandDisplay, w) + seal.sys.Link(wp, wpi) + seal.sys.bwrap.SetEnv[waylandDisplay] = w seal.sys.bwrap.Bind(wpi, w) // ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`) - seal.sys.updatePermTag(state.EnableWayland, wp, acl.Read, acl.Write, acl.Execute) + seal.sys.UpdatePermType(state.EnableWayland, wp, acl.Read, acl.Write, acl.Execute) } else { // set wayland socket path (e.g. `/run/user/%d/wayland-%d`) seal.wl = path.Join(seal.RuntimePath, wd) @@ -55,10 +55,11 @@ func (seal *appSeal) shareDisplay() error { if seal.et.Has(state.EnableX) { // discover X11 and grant user permission via the `ChangeHosts` command if d, ok := os.LookupEnv(display); !ok { - return (*ErrDisplayEnv)(wrapError(ErrXDisplay, "DISPLAY is not set")) + return fmsg.WrapError(ErrXDisplay, + "DISPLAY is not set") } else { - seal.sys.changeHosts(seal.sys.Username) - seal.sys.setEnv(display, d) + seal.sys.ChangeHosts(seal.sys.user.Username) + seal.sys.bwrap.SetEnv[display] = d seal.sys.bwrap.Bind("/tmp/.X11-unix", "/tmp/.X11-unix") } } diff --git a/internal/app/share.pulse.go b/internal/app/share.pulse.go index df26b16..0103b89 100644 --- a/internal/app/share.pulse.go +++ b/internal/app/share.pulse.go @@ -7,6 +7,7 @@ import ( "os" "path" + "git.ophivana.moe/cat/fortify/internal/fmsg" "git.ophivana.moe/cat/fortify/internal/state" ) @@ -24,11 +25,6 @@ var ( ErrPulseMode = errors.New("unexpected pulse socket mode") ) -type ( - PulseCookieAccessError BaseError - PulseSocketAccessError BaseError -) - func (seal *appSeal) sharePulse() error { if !seal.et.Has(state.EnablePulse) { return nil @@ -39,42 +35,43 @@ func (seal *appSeal) sharePulse() error { ps := path.Join(pd, "native") if _, err := os.Stat(pd); err != nil { if !errors.Is(err, fs.ErrNotExist) { - return (*PulseSocketAccessError)(wrapError(err, - fmt.Sprintf("cannot access PulseAudio directory '%s':", pd), err)) + return fmsg.WrapErrorSuffix(err, + fmt.Sprintf("cannot access PulseAudio directory %q:", pd)) } - return (*PulseSocketAccessError)(wrapError(ErrPulseSocket, - fmt.Sprintf("PulseAudio directory '%s' not found", pd))) + return fmsg.WrapError(ErrPulseSocket, + fmt.Sprintf("PulseAudio directory %q not found", pd)) } // check PulseAudio socket permission (e.g. `/run/user/%d/pulse/native`) if s, err := os.Stat(ps); err != nil { if !errors.Is(err, fs.ErrNotExist) { - return (*PulseSocketAccessError)(wrapError(err, - fmt.Sprintf("cannot access PulseAudio socket '%s':", ps), err)) + return fmsg.WrapErrorSuffix(err, + fmt.Sprintf("cannot access PulseAudio socket %q:", ps)) } - return (*PulseSocketAccessError)(wrapError(ErrPulseSocket, - fmt.Sprintf("PulseAudio directory '%s' found but socket does not exist", pd))) + return fmsg.WrapError(ErrPulseSocket, + fmt.Sprintf("PulseAudio directory %q found but socket does not exist", pd)) } else { if m := s.Mode(); m&0o006 != 0o006 { - return (*PulseSocketAccessError)(wrapError(ErrPulseMode, - fmt.Sprintf("unexpected permissions on '%s':", ps), m)) + return fmsg.WrapError(ErrPulseMode, + fmt.Sprintf("unexpected permissions on %q:", ps), m) } } // hard link pulse socket into target-executable share psi := path.Join(seal.shareLocal, "pulse") p := path.Join(seal.sys.runtime, "pulse", "native") - seal.sys.link(ps, psi) + seal.sys.Link(ps, psi) seal.sys.bwrap.Bind(psi, p) - seal.sys.setEnv(pulseServer, "unix:"+p) + seal.sys.bwrap.SetEnv[pulseServer] = "unix:" + p // publish current user's pulse cookie for target user if src, err := discoverPulseCookie(); err != nil { return err } else { dst := path.Join(seal.share, "pulse-cookie") - seal.sys.setEnv(pulseCookie, dst) - seal.sys.copyFile(dst, src) + seal.sys.bwrap.SetEnv[pulseCookie] = dst + seal.sys.CopyFile(dst, src) + seal.sys.bwrap.Bind(dst, dst) } return nil @@ -91,8 +88,8 @@ func discoverPulseCookie() (string, error) { p = path.Join(p, ".pulse-cookie") if s, err := os.Stat(p); err != nil { if !errors.Is(err, fs.ErrNotExist) { - return p, (*PulseCookieAccessError)(wrapError(err, - fmt.Sprintf("cannot access PulseAudio cookie '%s':", p), err)) + return p, fmsg.WrapErrorSuffix(err, + fmt.Sprintf("cannot access PulseAudio cookie %q:", p)) } // not found, try next method } else if !s.IsDir() { @@ -105,7 +102,8 @@ func discoverPulseCookie() (string, error) { p = path.Join(p, "pulse", "cookie") if s, err := os.Stat(p); err != nil { if !errors.Is(err, fs.ErrNotExist) { - return p, (*PulseCookieAccessError)(wrapError(err, "cannot access PulseAudio cookie", p+":", err)) + return p, fmsg.WrapErrorSuffix(err, + fmt.Sprintf("cannot access PulseAudio cookie %q:", p)) } // not found, try next method } else if !s.IsDir() { @@ -113,7 +111,7 @@ func discoverPulseCookie() (string, error) { } } - return "", (*PulseCookieAccessError)(wrapError(ErrPulseCookie, + return "", fmsg.WrapError(ErrPulseCookie, fmt.Sprintf("cannot locate PulseAudio cookie (tried $%s, $%s/pulse/cookie, $%s/.pulse-cookie)", - pulseCookie, xdgConfigHome, home))) + pulseCookie, xdgConfigHome, home)) } diff --git a/internal/app/share.runtime.go b/internal/app/share.runtime.go index ebb13aa..0c7149e 100644 --- a/internal/app/share.runtime.go +++ b/internal/app/share.runtime.go @@ -4,7 +4,7 @@ import ( "path" "git.ophivana.moe/cat/fortify/acl" - "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal/system" ) const ( @@ -20,28 +20,28 @@ func (seal *appSeal) shareRuntime() { seal.sys.bwrap.Tmpfs(seal.sys.runtime, 8*1024*1024) // point to inner runtime path `/run/user/%d` - seal.sys.setEnv(xdgRuntimeDir, seal.sys.runtime) - seal.sys.setEnv(xdgSessionClass, "user") - seal.sys.setEnv(xdgSessionType, "tty") + seal.sys.bwrap.SetEnv[xdgRuntimeDir] = seal.sys.runtime + seal.sys.bwrap.SetEnv[xdgSessionClass] = "user" + seal.sys.bwrap.SetEnv[xdgSessionType] = "tty" // ensure RunDir (e.g. `/run/user/%d/fortify`) - seal.sys.ensure(seal.RunDirPath, 0700) - seal.sys.updatePermTag(state.EnableLength, seal.RunDirPath, acl.Execute) + seal.sys.Ensure(seal.RunDirPath, 0700) + seal.sys.UpdatePermType(system.User, seal.RunDirPath, acl.Execute) // ensure runtime directory ACL (e.g. `/run/user/%d`) - seal.sys.updatePermTag(state.EnableLength, seal.RuntimePath, acl.Execute) + seal.sys.UpdatePermType(system.User, seal.RuntimePath, acl.Execute) // ensure Share (e.g. `/tmp/fortify.%d`) // acl is unnecessary as this directory is world executable - seal.sys.ensure(seal.SharePath, 0701) + seal.sys.Ensure(seal.SharePath, 0701) // ensure process-specific share (e.g. `/tmp/fortify.%d/%s`) // acl is unnecessary as this directory is world executable seal.share = path.Join(seal.SharePath, seal.id.String()) - seal.sys.ensureEphemeral(seal.share, 0701) + seal.sys.Ephemeral(system.Process, seal.share, 0701) // ensure process-specific share local to XDG_RUNTIME_DIR (e.g. `/run/user/%d/fortify/%s`) seal.shareLocal = path.Join(seal.RunDirPath, seal.id.String()) - seal.sys.ensureEphemeral(seal.shareLocal, 0700) - seal.sys.updatePerm(seal.shareLocal, acl.Execute) + seal.sys.Ephemeral(system.Process, seal.shareLocal, 0700) + seal.sys.UpdatePerm(seal.shareLocal, acl.Execute) } diff --git a/internal/app/share.system.go b/internal/app/share.system.go index e1a3e1d..e4c848b 100644 --- a/internal/app/share.system.go +++ b/internal/app/share.system.go @@ -5,7 +5,7 @@ import ( "path" "git.ophivana.moe/cat/fortify/acl" - "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal/system" ) const ( @@ -17,28 +17,28 @@ func (seal *appSeal) shareSystem() { // look up shell sh := "/bin/sh" if s, ok := os.LookupEnv(shell); ok { - seal.sys.setEnv(shell, s) + seal.sys.bwrap.SetEnv[shell] = s sh = s } // generate /etc/passwd passwdPath := path.Join(seal.share, "passwd") username := "chronos" - if seal.sys.Username != "" { - username = seal.sys.Username - seal.sys.setEnv("USER", seal.sys.Username) + if seal.sys.user.Username != "" { + username = seal.sys.user.Username + seal.sys.bwrap.SetEnv["USER"] = seal.sys.user.Username } homeDir := "/var/empty" - if seal.sys.HomeDir != "" { - homeDir = seal.sys.HomeDir - seal.sys.setEnv("HOME", seal.sys.HomeDir) + if seal.sys.user.HomeDir != "" { + homeDir = seal.sys.user.HomeDir + seal.sys.bwrap.SetEnv["HOME"] = seal.sys.user.HomeDir } passwd := username + ":x:65534:65534:Fortify:" + homeDir + ":" + sh + "\n" - seal.sys.writeFile(passwdPath, []byte(passwd)) + seal.sys.Write(passwdPath, passwd) // write /etc/group groupPath := path.Join(seal.share, "group") - seal.sys.writeFile(groupPath, []byte("fortify:x:65534:\n")) + seal.sys.Write(groupPath, "fortify:x:65534:\n") // bind /etc/passwd and /etc/group seal.sys.bwrap.Bind(passwdPath, "/etc/passwd") @@ -48,13 +48,13 @@ func (seal *appSeal) shareSystem() { func (seal *appSeal) shareTmpdirChild() string { // ensure child tmpdir parent directory (e.g. `/tmp/fortify.%d/tmpdir`) targetTmpdirParent := path.Join(seal.SharePath, "tmpdir") - seal.sys.ensure(targetTmpdirParent, 0700) - seal.sys.updatePermTag(state.EnableLength, targetTmpdirParent, acl.Execute) + seal.sys.Ensure(targetTmpdirParent, 0700) + seal.sys.UpdatePermType(system.User, targetTmpdirParent, acl.Execute) // ensure child tmpdir (e.g. `/tmp/fortify.%d/tmpdir/%d`) - targetTmpdir := path.Join(targetTmpdirParent, seal.sys.Uid) - seal.sys.ensure(targetTmpdir, 01700) - seal.sys.updatePermTag(state.EnableLength, targetTmpdir, acl.Read, acl.Write, acl.Execute) + targetTmpdir := path.Join(targetTmpdirParent, seal.sys.user.Uid) + seal.sys.Ensure(targetTmpdir, 01700) + seal.sys.UpdatePermType(system.User, targetTmpdir, acl.Read, acl.Write, acl.Execute) seal.sys.bwrap.Bind(targetTmpdir, "/tmp", false, true) // mount tmpfs on inner shared directory (e.g. `/tmp/fortify.%d`) diff --git a/internal/app/start.go b/internal/app/start.go index c496561..9e54063 100644 --- a/internal/app/start.go +++ b/internal/app/start.go @@ -8,21 +8,17 @@ import ( "path" "path/filepath" "strconv" + "strings" "time" "git.ophivana.moe/cat/fortify/helper" + "git.ophivana.moe/cat/fortify/internal/fmsg" "git.ophivana.moe/cat/fortify/internal/shim" "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal/system" "git.ophivana.moe/cat/fortify/internal/verbose" ) -type ( - // ProcessError encapsulates errors returned by starting *exec.Cmd - ProcessError BaseError - // ShimError encapsulates errors returned by shim.ServeConfig. - ShimError BaseError -) - // Start starts the fortified child func (a *app) Start() error { a.lock.Lock() @@ -41,12 +37,13 @@ func (a *app) Start() error { if s, err := exec.LookPath(n); err == nil { shimExec[i] = s } else { - return (*ProcessError)(wrapError(err, fmt.Sprintf("cannot find %q: %v", n, err))) + return fmsg.WrapErrorSuffix(err, + fmt.Sprintf("cannot find %q:", n)) } } } - if err := a.seal.sys.commit(); err != nil { + if err := a.seal.sys.Commit(); err != nil { return err } @@ -70,7 +67,7 @@ func (a *app) Start() error { a.cmd.Stderr = os.Stderr a.cmd.Dir = a.seal.RunDirPath - if wls, err := shim.ServeConfig(confSockPath, a.seal.sys.uid, &shim.Payload{ + if wls, err := shim.ServeConfig(confSockPath, a.seal.sys.UID(), &shim.Payload{ Argv: a.seal.command, Exec: shimExec, Bwrap: a.seal.sys.bwrap, @@ -78,7 +75,8 @@ func (a *app) Start() error { Verbose: verbose.Get(), }, a.seal.wl, a.seal.wlDone); err != nil { - return (*ShimError)(wrapError(err, "cannot listen on shim socket:", err)) + return fmsg.WrapErrorSuffix(err, + "cannot listen on shim socket:") } else { a.wayland = wls } @@ -86,7 +84,8 @@ func (a *app) Start() error { // start shim verbose.Println("starting shim as target user:", a.cmd) if err := a.cmd.Start(); err != nil { - return (*ProcessError)(wrapError(err, "cannot start process:", err)) + return fmsg.WrapErrorSuffix(err, + "cannot start process:") } startTime := time.Now().UTC() @@ -105,7 +104,7 @@ func (a *app) Start() error { err.Inner, err.DoErr = a.seal.store.Do(func(b state.Backend) { err.InnerErr = b.Save(&sd) }) - return err.equiv("cannot save process state:", err) + return err.equiv("cannot save process state:") } // StateStoreError is returned for a failed state save @@ -124,7 +123,7 @@ func (e *StateStoreError) equiv(a ...any) error { if e.Inner == true && e.DoErr == nil && e.InnerErr == nil && e.Err == nil { return nil } else { - return wrapError(e, a...) + return fmsg.WrapErrorSuffix(e, a...) } } @@ -203,15 +202,16 @@ func (a *app) Wait() (int, error) { } // enablements of remaining launchers - rt, tags := new(state.Enablements), new(state.Enablements) - tags.Set(state.EnableLength + 1) + rt, ec := new(state.Enablements), new(system.Criteria) + ec.Enablements = new(state.Enablements) + ec.Set(system.Process) if states, err := b.Load(); err != nil { return err } else { if l := len(states); l == 0 { // cleanup globals as the final launcher verbose.Println("no other launchers active, will clean up globals") - tags.Set(state.EnableLength) + ec.Set(system.User) } else { verbose.Printf("found %d active launchers, cleaning up without globals\n", l) } @@ -224,22 +224,22 @@ func (a *app) Wait() (int, error) { // invert accumulated enablements for cleanup for i := state.Enablement(0); i < state.EnableLength; i++ { if !rt.Has(i) { - tags.Set(i) + ec.Set(i) } } if verbose.Get() { - ct := make([]state.Enablement, 0, state.EnableLength) - for i := state.Enablement(0); i < state.EnableLength; i++ { - if tags.Has(i) { - ct = append(ct, i) + labels := make([]string, 0, state.EnableLength+1) + for i := state.Enablement(0); i < state.EnableLength+2; i++ { + if ec.Has(i) { + labels = append(labels, system.TypeString(i)) } } - if len(ct) > 0 { - verbose.Println("will revert operations tagged", ct, "as no remaining launchers hold these enablements") + if len(labels) > 0 { + verbose.Println("reverting operations labelled", strings.Join(labels, ", ")) } } - if err := a.seal.sys.revert(tags); err != nil { + if err := a.seal.sys.Revert(ec); err != nil { return err.(RevertCompoundError) } diff --git a/internal/app/system.go b/internal/app/system.go index a016293..5696647 100644 --- a/internal/app/system.go +++ b/internal/app/system.go @@ -1,19 +1,14 @@ package app import ( - "errors" - "fmt" - "io/fs" - "os" "os/user" - "git.ophivana.moe/cat/fortify/acl" "git.ophivana.moe/cat/fortify/dbus" "git.ophivana.moe/cat/fortify/helper/bwrap" "git.ophivana.moe/cat/fortify/internal" "git.ophivana.moe/cat/fortify/internal/state" + "git.ophivana.moe/cat/fortify/internal/system" "git.ophivana.moe/cat/fortify/internal/verbose" - "git.ophivana.moe/cat/fortify/xcb" ) // appSeal seals the application with child-related information @@ -48,7 +43,7 @@ type appSeal struct { // prevents sharing from happening twice shared bool // seal system-level component - sys *appSealTx + sys *appSealSys // used in various sealing operations internal.SystemConstants @@ -56,357 +51,24 @@ type appSeal struct { // protected by upstream mutex } -// appSealTx contains the system-level component of the app seal -type appSealTx struct { +// appSealSys encapsulates app seal behaviour with OS interactions +type appSealSys struct { bwrap *bwrap.Config - tmpfs []string - - // reference to D-Bus proxy instance, nil if disabled - dbus *dbus.Proxy - // notification from goroutine waiting for dbus.Proxy - dbusWait chan struct{} - // upstream address/downstream path used to initialise dbus.Proxy - dbusAddr *[2][2]string - // whether system bus proxy is enabled - dbusSystem bool - - // paths to append/strip ACLs (of target user) from - acl []*appACLEntry - // X11 ChangeHosts commands to perform - xhost []string - // paths of directories to ensure - mkdir []appEnsureEntry - // dst, data pairs of temporarily available files - files [][2]string - // dst, src pairs of temporarily shared files - tmpfiles [][2]string - // dst, src pairs of temporarily hard linked files - hardlinks [][2]string + // paths to override by mounting tmpfs over them + override []string // default formatted XDG_RUNTIME_DIR of User runtime string // sealed path to fortify executable, used by shim executable string - // target user UID as an integer - uid int // target user sealed from config - *user.User + user *user.User - // prevents commit from happening twice - complete bool - // prevents cleanup from happening twice - closed bool + *system.I // protected by upstream mutex } -type appEnsureEntry struct { - path string - perm os.FileMode - remove bool -} - -// setEnv sets an environment variable for the child process -func (tx *appSealTx) setEnv(k, v string) { - tx.bwrap.SetEnv[k] = v -} - -// ensure appends a directory ensure action -func (tx *appSealTx) ensure(path string, perm os.FileMode) { - tx.mkdir = append(tx.mkdir, appEnsureEntry{path, perm, false}) -} - -// ensureEphemeral appends a directory ensure action with removal in rollback -func (tx *appSealTx) ensureEphemeral(path string, perm os.FileMode) { - tx.mkdir = append(tx.mkdir, appEnsureEntry{path, perm, true}) -} - -// appACLEntry contains information for applying/reverting an ACL entry -type appACLEntry struct { - tag state.Enablement - path string - perms []acl.Perm -} - -func (e *appACLEntry) ts() string { - switch e.tag { - case state.EnableLength: - return "Global" - case state.EnableLength + 1: - return "Process" - default: - return e.tag.String() - } -} - -func (e *appACLEntry) String() string { - var s = []byte("---") - for _, p := range e.perms { - switch p { - case acl.Read: - s[0] = 'r' - case acl.Write: - s[1] = 'w' - case acl.Execute: - s[2] = 'x' - } - } - return string(s) -} - -// updatePerm appends an untagged acl update action -func (tx *appSealTx) updatePerm(path string, perms ...acl.Perm) { - tx.updatePermTag(state.EnableLength+1, path, perms...) -} - -// updatePermTag appends an acl update action -// Tagging with state.EnableLength sets cleanup to happen at final active launcher exit, -// while tagging with state.EnableLength+1 will unconditionally clean up on exit. -func (tx *appSealTx) updatePermTag(tag state.Enablement, path string, perms ...acl.Perm) { - tx.acl = append(tx.acl, &appACLEntry{tag, path, perms}) -} - -// changeHosts appends target username of an X11 ChangeHosts action -func (tx *appSealTx) changeHosts(username string) { - tx.xhost = append(tx.xhost, username) -} - -// writeFile appends a files action -func (tx *appSealTx) writeFile(dst string, data []byte) { - tx.files = append(tx.files, [2]string{dst, string(data)}) - tx.updatePerm(dst, acl.Read) - tx.bwrap.Bind(dst, dst) -} - -// copyFile appends a tmpfiles action -func (tx *appSealTx) copyFile(dst, src string) { - tx.tmpfiles = append(tx.tmpfiles, [2]string{dst, src}) - tx.updatePerm(dst, acl.Read) - tx.bwrap.Bind(dst, dst) -} - -// link appends a hardlink action -func (tx *appSealTx) link(oldname, newname string) { - tx.hardlinks = append(tx.hardlinks, [2]string{oldname, newname}) -} - -type ( - ChangeHostsError BaseError - EnsureDirError BaseError - TmpfileError BaseError - DBusStartError BaseError - ACLUpdateError BaseError -) - -// commit applies recorded actions -// order: xhost, mkdir, files, tmpfiles, hardlinks, dbus, acl -func (tx *appSealTx) commit() error { - if tx.complete { - panic("seal transaction committed twice") - } - tx.complete = true - - txp := &appSealTx{User: tx.User, bwrap: &bwrap.Config{SetEnv: make(map[string]string)}} - defer func() { - // rollback partial commit - if txp != nil { - // global changes (x11, ACLs) are always repeated and check for other launchers cannot happen here - // attempting cleanup here will cause other fortified processes to lose access to them - // a better (and more secure) fix is to proxy access to these resources and eliminate the ACLs altogether - tags := new(state.Enablements) - for e := state.Enablement(0); e < state.EnableLength+2; e++ { - tags.Set(e) - } - if err := txp.revert(tags); err != nil { - fmt.Println("fortify: errors returned reverting partial commit:", err) - } - } - }() - - // insert xhost entries - for _, username := range tx.xhost { - verbose.Printf("inserting XHost entry SI:localuser:%s\n", username) - if err := xcb.ChangeHosts(xcb.HostModeInsert, xcb.FamilyServerInterpreted, "localuser\x00"+username); err != nil { - return (*ChangeHostsError)(wrapError(err, - fmt.Sprintf("cannot insert XHost entry SI:localuser:%s, %s", username, err))) - } else { - // register partial commit - txp.changeHosts(username) - } - } - - // ensure directories - for _, dir := range tx.mkdir { - verbose.Println("ensuring directory mode:", dir.perm.String(), "path:", dir.path) - if err := os.Mkdir(dir.path, dir.perm); err != nil && !errors.Is(err, fs.ErrExist) { - return (*EnsureDirError)(wrapError(err, - fmt.Sprintf("cannot create directory '%s': %s", dir.path, err))) - } else { - // only ephemeral dirs require rollback - if dir.remove { - // register partial commit - txp.ensureEphemeral(dir.path, dir.perm) - } - } - } - - // write files - for _, file := range tx.files { - verbose.Println("writing", len(file[1]), "bytes of data to", file[0]) - if err := os.WriteFile(file[0], []byte(file[1]), 0600); err != nil { - return (*TmpfileError)(wrapError(err, - fmt.Sprintf("cannot write file '%s': %s", file[0], err))) - } else { - // register partial commit - txp.writeFile(file[0], make([]byte, 0)) // data not necessary for revert - } - } - - // publish tmpfiles - for _, tmpfile := range tx.tmpfiles { - verbose.Println("publishing tmpfile", tmpfile[0], "from", tmpfile[1]) - if err := copyFile(tmpfile[0], tmpfile[1]); err != nil { - return (*TmpfileError)(wrapError(err, - fmt.Sprintf("cannot publish tmpfile '%s' from '%s': %s", tmpfile[0], tmpfile[1], err))) - } else { - // register partial commit - txp.copyFile(tmpfile[0], tmpfile[1]) - } - } - - // create hardlinks - for _, link := range tx.hardlinks { - verbose.Println("creating hardlink", link[1], "from", link[0]) - if err := os.Link(link[0], link[1]); err != nil { - return (*TmpfileError)(wrapError(err, - fmt.Sprintf("cannot create hardlink '%s' from '%s': %s", link[1], link[0], err))) - } else { - // register partial commit - txp.link(link[0], link[1]) - } - } - - if tx.dbus != nil { - // start dbus proxy - verbose.Printf("session bus proxy on '%s' for upstream '%s'\n", tx.dbusAddr[0][1], tx.dbusAddr[0][0]) - if tx.dbusSystem { - verbose.Printf("system bus proxy on '%s' for upstream '%s'\n", tx.dbusAddr[1][1], tx.dbusAddr[1][0]) - } - if err := tx.startDBus(); err != nil { - return (*DBusStartError)(wrapError(err, "cannot start message bus proxy:", err)) - } else { - txp.dbus = tx.dbus - txp.dbusAddr = tx.dbusAddr - txp.dbusSystem = tx.dbusSystem - txp.dbusWait = tx.dbusWait - } - } - - // apply ACLs - for _, e := range tx.acl { - verbose.Println("applying ACL", e, "uid:", tx.Uid, "tag:", e.ts(), "path:", e.path) - if err := acl.UpdatePerm(e.path, tx.uid, e.perms...); err != nil { - return (*ACLUpdateError)(wrapError(err, - fmt.Sprintf("cannot apply ACL to '%s': %s", e.path, err))) - } else { - // register partial commit - txp.updatePermTag(e.tag, e.path, e.perms...) - } - } - - // disarm partial commit rollback - txp = nil - - // queue tmpfs at the end of tx.bwrap.Filesystem - for _, dest := range tx.tmpfs { - tx.bwrap.Tmpfs(dest, 8*1024) - } - - return nil -} - -// revert rolls back recorded actions -// order: acl, dbus, hardlinks, tmpfiles, files, mkdir, xhost -// errors are printed but not treated as fatal -func (tx *appSealTx) revert(tags *state.Enablements) error { - if tx.closed { - panic("seal transaction reverted twice") - } - tx.closed = true - - // will be slightly over-sized with ephemeral dirs - errs := make([]error, 0, len(tx.acl)+1+len(tx.tmpfiles)+len(tx.mkdir)+len(tx.xhost)) - joinError := func(err error, a ...any) { - var e error - if err != nil { - e = wrapError(err, a...) - } - errs = append(errs, e) - } - - // revert ACLs - for _, e := range tx.acl { - if tags.Has(e.tag) { - verbose.Println("stripping ACL", e, "uid:", tx.Uid, "tag:", e.ts(), "path:", e.path) - err := acl.UpdatePerm(e.path, tx.uid) - joinError(err, fmt.Sprintf("cannot strip ACL entry from '%s': %s", e.path, err)) - } else { - verbose.Println("skipping ACL", e, "uid:", tx.Uid, "tag:", e.ts(), "path:", e.path) - } - } - - if tx.dbus != nil { - // stop dbus proxy - verbose.Println("terminating message bus proxy") - err := tx.stopDBus() - joinError(err, "cannot stop message bus proxy:", err) - } - - // remove hardlinks - for _, link := range tx.hardlinks { - verbose.Println("removing hardlink", link[1]) - err := os.Remove(link[1]) - joinError(err, fmt.Sprintf("cannot remove hardlink '%s': %s", link[1], err)) - } - - // remove tmpfiles - for _, tmpfile := range tx.tmpfiles { - verbose.Println("removing tmpfile", tmpfile[0]) - err := os.Remove(tmpfile[0]) - joinError(err, fmt.Sprintf("cannot remove tmpfile '%s': %s", tmpfile[0], err)) - } - - // remove files - for _, file := range tx.files { - verbose.Println("removing file", file[0]) - err := os.Remove(file[0]) - joinError(err, fmt.Sprintf("cannot remove file '%s': %s", file[0], err)) - } - - // remove (empty) ephemeral directories - for i := len(tx.mkdir); i > 0; i-- { - dir := tx.mkdir[i-1] - if !dir.remove { - continue - } - - verbose.Println("destroying ephemeral directory mode:", dir.perm.String(), "path:", dir.path) - err := os.Remove(dir.path) - joinError(err, fmt.Sprintf("cannot remove ephemeral directory '%s': %s", dir.path, err)) - } - - if tags.Has(state.EnableX) { - // rollback xhost insertions - for _, username := range tx.xhost { - verbose.Printf("deleting XHost entry SI:localuser:%s\n", username) - err := xcb.ChangeHosts(xcb.HostModeDelete, xcb.FamilyServerInterpreted, "localuser\x00"+username) - joinError(err, "cannot remove XHost entry:", err) - } - } - - return errors.Join(errs...) -} - // shareAll calls all share methods in sequence func (seal *appSeal) shareAll(bus [2]*dbus.Config) error { if seal.shared { @@ -432,12 +94,11 @@ func (seal *appSeal) shareAll(bus [2]*dbus.Config) error { if err := seal.shareDBus(bus); err != nil { return err - } else if seal.sys.dbusAddr != nil { // set if D-Bus enabled and share successful - verbose.Println("sealed session proxy", bus[0].Args(seal.sys.dbusAddr[0])) - if bus[1] != nil { - verbose.Println("sealed system proxy", bus[1].Args(seal.sys.dbusAddr[1])) - } - verbose.Println("message bus proxy final args:", seal.sys.dbus) + } + + // queue overriding tmpfs at the end of seal.sys.bwrap.Filesystem + for _, dest := range seal.sys.override { + seal.sys.bwrap.Tmpfs(dest, 8*1024) } return nil