aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal
diff options
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/app/app.go2
-rw-r--r--internal/app/config.go6
-rw-r--r--internal/app/copy.go33
-rw-r--r--internal/app/error.go51
-rw-r--r--internal/app/launch.machinectl.go11
-rw-r--r--internal/app/launch.sudo.go2
-rw-r--r--internal/app/seal.go47
-rw-r--r--internal/app/share.dbus.go118
-rw-r--r--internal/app/share.display.go21
-rw-r--r--internal/app/share.pulse.go46
-rw-r--r--internal/app/share.runtime.go22
-rw-r--r--internal/app/share.system.go30
-rw-r--r--internal/app/start.go50
-rw-r--r--internal/app/system.go365
14 files changed, 138 insertions, 666 deletions
diff --git a/internal/app/app.go b/internal/app/app.go
index 50d59da9..a04ae74b 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 3f6d1c0f..72648f0c 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 bf90bfea..00000000
--- 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 7c18a89e..00000000
--- 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 9fb9ea0b..606fd9d5 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 3e364ace..965af963 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 bf634c40..76ce8d39 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 912cd97b..6b0ff43c 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")
-
- // resolve upstream bus addresses
- sessionBus[0], systemBus[0] = dbus.Address()
+ sessionPath, systemPath := path.Join(seal.share, "bus"), path.Join(seal.share, "system_bus_socket")
- // 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)
- }
-
- 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))
- }
+ seal.sys.bwrap.SetEnv[dbusSystemBusAddress] = "unix:path=" + systemInner
+ seal.sys.bwrap.Bind(systemPath, systemInner)
+ seal.sys.UpdatePerm(systemPath, acl.Read, acl.Write)
}
- // block until proxy wait returns
- <-tx.dbusWait
return nil
}
diff --git a/internal/app/share.display.go b/internal/app/share.display.go
index 86343d8b..2675c01b 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 df26b16c..0103b895 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 ebb13aa6..0c7149ed 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 e1a3e1de..e4c848bb 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 c496561c..9e54063a 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 a0162939..56966479 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