aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/app
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-10-16 01:38:59 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-10-16 01:38:59 +0900
commit084cd84f36a1d608541b4aa4e1e95334395d8953 (patch)
treeb48fac0d902627411036630d42edc1ca45057dd1 /internal/app
parent430f1a5b4e4e2b164297391390e3a0cbe2ad2eb2 (diff)
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 <cat@ophivana.moe>
Diffstat (limited to 'internal/app')
-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