aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2024-12-28 11:12:35 +0900
committerOphestra <cat@gensokyo.uk>2024-12-28 11:12:35 +0900
commit0107620d8c174dcf9237c16d4b4b7b2f6955a214 (patch)
tree3b082eafad73eaa971a59baf762260c89917831b /internal
parentfc26659ea11fea8f41fc2551d6d39d30fe3a49e7 (diff)
app: merge share methods
This significantly increases readability and makes order of ops more obvious. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal')
-rw-r--r--internal/app/seal.go2
-rw-r--r--internal/app/share.dbus.go44
-rw-r--r--internal/app/share.display.go81
-rw-r--r--internal/app/share.go335
-rw-r--r--internal/app/share.pulse.go119
-rw-r--r--internal/app/share.runtime.go39
-rw-r--r--internal/app/share.system.go74
-rw-r--r--internal/app/system.go36
8 files changed, 336 insertions, 394 deletions
diff --git a/internal/app/seal.go b/internal/app/seal.go
index f3dbfbd0..87e62b36 100644
--- a/internal/app/seal.go
+++ b/internal/app/seal.go
@@ -229,7 +229,7 @@ func (a *app) Seal(config *fst.Config) error {
seal.et = config.Confinement.Enablements
// this method calls all share methods in sequence
- if err := seal.shareAll([2]*dbus.Config{config.Confinement.SessionBus, config.Confinement.SystemBus}, a.os); err != nil {
+ if err := seal.setupShares([2]*dbus.Config{config.Confinement.SessionBus, config.Confinement.SystemBus}, a.os); err != nil {
return err
}
diff --git a/internal/app/share.dbus.go b/internal/app/share.dbus.go
deleted file mode 100644
index 4fd947d7..00000000
--- a/internal/app/share.dbus.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package app
-
-import (
- "path"
-
- "git.gensokyo.uk/security/fortify/acl"
- "git.gensokyo.uk/security/fortify/dbus"
- "git.gensokyo.uk/security/fortify/internal/system"
-)
-
-const (
- dbusSessionBusAddress = "DBUS_SESSION_BUS_ADDRESS"
- dbusSystemBusAddress = "DBUS_SYSTEM_BUS_ADDRESS"
-)
-
-func (seal *appSeal) shareDBus(config [2]*dbus.Config) error {
- if !seal.et.Has(system.EDBus) {
- return nil
- }
-
- // downstream socket paths
- sessionPath, systemPath := path.Join(seal.share, "bus"), path.Join(seal.share, "system_bus_socket")
-
- // configure dbus proxy
- if f, err := seal.sys.ProxyDBus(config[0], config[1], sessionPath, systemPath); err != nil {
- return err
- } else {
- seal.dbusMsg = f
- }
-
- // share proxy sockets
- sessionInner := path.Join(seal.sys.runtime, "bus")
- 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.bwrap.SetEnv[dbusSystemBusAddress] = "unix:path=" + systemInner
- seal.sys.bwrap.Bind(systemPath, systemInner)
- seal.sys.UpdatePerm(systemPath, acl.Read, acl.Write)
- }
-
- return nil
-}
diff --git a/internal/app/share.display.go b/internal/app/share.display.go
deleted file mode 100644
index f09efe61..00000000
--- a/internal/app/share.display.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package app
-
-import (
- "errors"
- "path"
-
- "git.gensokyo.uk/security/fortify/acl"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
- "git.gensokyo.uk/security/fortify/internal/linux"
- "git.gensokyo.uk/security/fortify/internal/system"
-)
-
-const (
- term = "TERM"
- display = "DISPLAY"
-
- // https://manpages.debian.org/experimental/libwayland-doc/wl_display_connect.3.en.html
- waylandDisplay = "WAYLAND_DISPLAY"
-)
-
-var (
- ErrWayland = errors.New(waylandDisplay + " unset")
- ErrXDisplay = errors.New(display + " unset")
-)
-
-func (seal *appSeal) shareDisplay(os linux.System) error {
- // pass $TERM to launcher
- if t, ok := os.LookupEnv(term); ok {
- seal.sys.bwrap.SetEnv[term] = t
- }
-
- // set up wayland
- if seal.et.Has(system.EWayland) {
- var wp string
- if wd, ok := os.LookupEnv(waylandDisplay); !ok {
- return fmsg.WrapError(ErrWayland,
- "WAYLAND_DISPLAY is not set")
- } else {
- wp = path.Join(seal.RuntimePath, wd)
- }
-
- w := path.Join(seal.sys.runtime, "wayland-0")
- seal.sys.bwrap.SetEnv[waylandDisplay] = w
-
- if seal.directWayland {
- // hardlink wayland socket
- wpi := path.Join(seal.shareLocal, "wayland")
- seal.sys.Link(wp, wpi)
- seal.sys.bwrap.Bind(wpi, w)
-
- // ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`)
- seal.sys.UpdatePermType(system.EWayland, wp, acl.Read, acl.Write, acl.Execute)
- } else {
- wc := path.Join(seal.SharePath, "wayland")
- wt := path.Join(wc, seal.id)
- seal.sys.Ensure(wc, 0711)
- appID := seal.fid
- if appID == "" {
- // use instance ID in case app id is not set
- appID = "moe.ophivana.fortify." + seal.id
- }
- seal.sys.Wayland(wt, wp, appID, seal.id)
- seal.sys.bwrap.Bind(wt, w)
- }
- }
-
- // set up X11
- if seal.et.Has(system.EX11) {
- // discover X11 and grant user permission via the `ChangeHosts` command
- if d, ok := os.LookupEnv(display); !ok {
- return fmsg.WrapError(ErrXDisplay,
- "DISPLAY is not set")
- } else {
- seal.sys.ChangeHosts("#" + seal.sys.user.us)
- seal.sys.bwrap.SetEnv[display] = d
- seal.sys.bwrap.Bind("/tmp/.X11-unix", "/tmp/.X11-unix")
- }
- }
-
- return nil
-}
diff --git a/internal/app/share.go b/internal/app/share.go
new file mode 100644
index 00000000..dea55a87
--- /dev/null
+++ b/internal/app/share.go
@@ -0,0 +1,335 @@
+package app
+
+import (
+ "errors"
+ "fmt"
+ "io/fs"
+ "path"
+
+ "git.gensokyo.uk/security/fortify/acl"
+ "git.gensokyo.uk/security/fortify/dbus"
+ "git.gensokyo.uk/security/fortify/fst"
+ "git.gensokyo.uk/security/fortify/internal/fmsg"
+ "git.gensokyo.uk/security/fortify/internal/linux"
+ "git.gensokyo.uk/security/fortify/internal/system"
+)
+
+const (
+ home = "HOME"
+ shell = "SHELL"
+
+ xdgConfigHome = "XDG_CONFIG_HOME"
+ xdgRuntimeDir = "XDG_RUNTIME_DIR"
+ xdgSessionClass = "XDG_SESSION_CLASS"
+ xdgSessionType = "XDG_SESSION_TYPE"
+
+ term = "TERM"
+ display = "DISPLAY"
+
+ // https://manpages.debian.org/experimental/libwayland-doc/wl_display_connect.3.en.html
+ waylandDisplay = "WAYLAND_DISPLAY"
+
+ pulseServer = "PULSE_SERVER"
+ pulseCookie = "PULSE_COOKIE"
+
+ dbusSessionBusAddress = "DBUS_SESSION_BUS_ADDRESS"
+ dbusSystemBusAddress = "DBUS_SYSTEM_BUS_ADDRESS"
+)
+
+var (
+ ErrWayland = errors.New(waylandDisplay + " unset")
+ ErrXDisplay = errors.New(display + " unset")
+
+ ErrPulseCookie = errors.New("pulse cookie not present")
+ ErrPulseSocket = errors.New("pulse socket not present")
+ ErrPulseMode = errors.New("unexpected pulse socket mode")
+)
+
+func (seal *appSeal) setupShares(bus [2]*dbus.Config, os linux.System) error {
+ if seal.shared {
+ panic("seal shared twice")
+ }
+ seal.shared = true
+
+ /*
+ Tmpdir-based share directory
+ */
+
+ // ensure Share (e.g. `/tmp/fortify.%d`)
+ // acl is unnecessary as this directory is world executable
+ seal.sys.Ensure(seal.SharePath, 0711)
+
+ // 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)
+ seal.sys.Ephemeral(system.Process, seal.share, 0711)
+
+ // ensure child tmpdir parent directory (e.g. `/tmp/fortify.%d/tmpdir`)
+ targetTmpdirParent := path.Join(seal.SharePath, "tmpdir")
+ 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.user.as)
+ 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)
+
+ /*
+ XDG runtime directory
+ */
+
+ // mount tmpfs on inner runtime (e.g. `/run/user/%d`)
+ seal.sys.bwrap.Tmpfs("/run/user", 1*1024*1024)
+ seal.sys.bwrap.Tmpfs(seal.sys.runtime, 8*1024*1024)
+
+ // point to inner runtime path `/run/user/%d`
+ 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.UpdatePermType(system.User, seal.RunDirPath, acl.Execute)
+
+ // ensure runtime directory ACL (e.g. `/run/user/%d`)
+ seal.sys.Ensure(seal.RuntimePath, 0700) // ensure this dir in case XDG_RUNTIME_DIR is unset
+ seal.sys.UpdatePermType(system.User, seal.RuntimePath, acl.Execute)
+
+ // ensure process-specific share local to XDG_RUNTIME_DIR (e.g. `/run/user/%d/fortify/%s`)
+ seal.shareLocal = path.Join(seal.RunDirPath, seal.id)
+ seal.sys.Ephemeral(system.Process, seal.shareLocal, 0700)
+ seal.sys.UpdatePerm(seal.shareLocal, acl.Execute)
+
+ /*
+ Inner passwd database
+ */
+
+ // look up shell
+ sh := "/bin/sh"
+ if s, ok := os.LookupEnv(shell); ok {
+ seal.sys.bwrap.SetEnv[shell] = s
+ sh = s
+ }
+
+ // generate /etc/passwd
+ passwdPath := path.Join(seal.share, "passwd")
+ username := "chronos"
+ if seal.sys.user.username != "" {
+ username = seal.sys.user.username
+ }
+ homeDir := "/var/empty"
+ if seal.sys.user.home != "" {
+ homeDir = seal.sys.user.home
+ }
+
+ // bind home directory
+ seal.sys.bwrap.Bind(seal.sys.user.data, homeDir, false, true)
+ seal.sys.bwrap.Chdir = homeDir
+
+ seal.sys.bwrap.SetEnv["USER"] = username
+ seal.sys.bwrap.SetEnv["HOME"] = homeDir
+
+ passwd := username + ":x:" + seal.sys.mappedIDString + ":" + seal.sys.mappedIDString + ":Fortify:" + homeDir + ":" + sh + "\n"
+ seal.sys.Write(passwdPath, passwd)
+
+ // write /etc/group
+ groupPath := path.Join(seal.share, "group")
+ seal.sys.Write(groupPath, "fortify:x:"+seal.sys.mappedIDString+":\n")
+
+ // bind /etc/passwd and /etc/group
+ seal.sys.bwrap.Bind(passwdPath, "/etc/passwd")
+ seal.sys.bwrap.Bind(groupPath, "/etc/group")
+
+ /*
+ Display servers
+ */
+
+ // pass $TERM to launcher
+ if t, ok := os.LookupEnv(term); ok {
+ seal.sys.bwrap.SetEnv[term] = t
+ }
+
+ // set up wayland
+ if seal.et.Has(system.EWayland) {
+ var wp string
+ if wd, ok := os.LookupEnv(waylandDisplay); !ok {
+ return fmsg.WrapError(ErrWayland,
+ "WAYLAND_DISPLAY is not set")
+ } else {
+ wp = path.Join(seal.RuntimePath, wd)
+ }
+
+ w := path.Join(seal.sys.runtime, "wayland-0")
+ seal.sys.bwrap.SetEnv[waylandDisplay] = w
+
+ if !seal.directWayland { // set up security-context-v1
+ wc := path.Join(seal.SharePath, "wayland")
+ wt := path.Join(wc, seal.id)
+ seal.sys.Ensure(wc, 0711)
+ appID := seal.fid
+ if appID == "" {
+ // use instance ID in case app id is not set
+ appID = "moe.ophivana.fortify." + seal.id
+ }
+ seal.sys.Wayland(wt, wp, appID, seal.id)
+ seal.sys.bwrap.Bind(wt, w)
+ } else { // bind mount wayland socket (insecure)
+ // hardlink wayland socket
+ wpi := path.Join(seal.shareLocal, "wayland")
+ seal.sys.Link(wp, wpi)
+ seal.sys.bwrap.Bind(wpi, w)
+
+ // ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`)
+ seal.sys.UpdatePermType(system.EWayland, wp, acl.Read, acl.Write, acl.Execute)
+ }
+ }
+
+ // set up X11
+ if seal.et.Has(system.EX11) {
+ // discover X11 and grant user permission via the `ChangeHosts` command
+ if d, ok := os.LookupEnv(display); !ok {
+ return fmsg.WrapError(ErrXDisplay,
+ "DISPLAY is not set")
+ } else {
+ seal.sys.ChangeHosts("#" + seal.sys.user.us)
+ seal.sys.bwrap.SetEnv[display] = d
+ seal.sys.bwrap.Bind("/tmp/.X11-unix", "/tmp/.X11-unix")
+ }
+ }
+
+ /*
+ PulseAudio server and authentication
+ */
+
+ if seal.et.Has(system.EPulse) {
+ // check PulseAudio directory presence (e.g. `/run/user/%d/pulse`)
+ pd := path.Join(seal.RuntimePath, "pulse")
+ ps := path.Join(pd, "native")
+ if _, err := os.Stat(pd); err != nil {
+ if !errors.Is(err, fs.ErrNotExist) {
+ return fmsg.WrapErrorSuffix(err,
+ fmt.Sprintf("cannot access PulseAudio directory %q:", 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 fmsg.WrapErrorSuffix(err,
+ fmt.Sprintf("cannot access PulseAudio socket %q:", ps))
+ }
+ 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 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.bwrap.Bind(psi, p)
+ seal.sys.bwrap.SetEnv[pulseServer] = "unix:" + p
+
+ // publish current user's pulse cookie for target user
+ if src, err := discoverPulseCookie(os); err != nil {
+ // not fatal
+ fmsg.VPrintln(err.(*fmsg.BaseError).Message())
+ } else {
+ dst := path.Join(seal.share, "pulse-cookie")
+ innerDst := fst.Tmp + "/pulse-cookie"
+ seal.sys.bwrap.SetEnv[pulseCookie] = innerDst
+ seal.sys.CopyFile(dst, src)
+ seal.sys.bwrap.Bind(dst, innerDst)
+ }
+ }
+
+ /*
+ D-Bus proxy
+ */
+
+ if seal.et.Has(system.EDBus) {
+ // ensure dbus session bus defaults
+ if bus[0] == nil {
+ bus[0] = dbus.NewConfig(seal.fid, true, true)
+ }
+
+ // downstream socket paths
+ sessionPath, systemPath := path.Join(seal.share, "bus"), path.Join(seal.share, "system_bus_socket")
+
+ // configure dbus proxy
+ if f, err := seal.sys.ProxyDBus(bus[0], bus[1], sessionPath, systemPath); err != nil {
+ return err
+ } else {
+ seal.dbusMsg = f
+ }
+
+ // share proxy sockets
+ sessionInner := path.Join(seal.sys.runtime, "bus")
+ seal.sys.bwrap.SetEnv[dbusSessionBusAddress] = "unix:path=" + sessionInner
+ seal.sys.bwrap.Bind(sessionPath, sessionInner)
+ seal.sys.UpdatePerm(sessionPath, acl.Read, acl.Write)
+ if bus[1] != nil {
+ systemInner := "/run/dbus/system_bus_socket"
+ seal.sys.bwrap.SetEnv[dbusSystemBusAddress] = "unix:path=" + systemInner
+ seal.sys.bwrap.Bind(systemPath, systemInner)
+ seal.sys.UpdatePerm(systemPath, acl.Read, acl.Write)
+ }
+ }
+
+ /*
+ Miscellaneous
+ */
+
+ // 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
+}
+
+// discoverPulseCookie attempts various standard methods to discover the current user's PulseAudio authentication cookie
+func discoverPulseCookie(os linux.System) (string, error) {
+ if p, ok := os.LookupEnv(pulseCookie); ok {
+ return p, nil
+ }
+
+ // dotfile $HOME/.pulse-cookie
+ if p, ok := os.LookupEnv(home); ok {
+ p = path.Join(p, ".pulse-cookie")
+ if s, err := os.Stat(p); err != nil {
+ if !errors.Is(err, fs.ErrNotExist) {
+ return p, fmsg.WrapErrorSuffix(err,
+ fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
+ }
+ // not found, try next method
+ } else if !s.IsDir() {
+ return p, nil
+ }
+ }
+
+ // $XDG_CONFIG_HOME/pulse/cookie
+ if p, ok := os.LookupEnv(xdgConfigHome); ok {
+ p = path.Join(p, "pulse", "cookie")
+ if s, err := os.Stat(p); err != nil {
+ if !errors.Is(err, fs.ErrNotExist) {
+ return p, fmsg.WrapErrorSuffix(err,
+ fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
+ }
+ // not found, try next method
+ } else if !s.IsDir() {
+ return p, nil
+ }
+ }
+
+ return "", fmsg.WrapError(ErrPulseCookie,
+ fmt.Sprintf("cannot locate PulseAudio cookie (tried $%s, $%s/pulse/cookie, $%s/.pulse-cookie)",
+ pulseCookie, xdgConfigHome, home))
+}
diff --git a/internal/app/share.pulse.go b/internal/app/share.pulse.go
deleted file mode 100644
index 7d4b3542..00000000
--- a/internal/app/share.pulse.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package app
-
-import (
- "errors"
- "fmt"
- "io/fs"
- "path"
-
- "git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
- "git.gensokyo.uk/security/fortify/internal/linux"
- "git.gensokyo.uk/security/fortify/internal/system"
-)
-
-const (
- pulseServer = "PULSE_SERVER"
- pulseCookie = "PULSE_COOKIE"
-
- home = "HOME"
- xdgConfigHome = "XDG_CONFIG_HOME"
-)
-
-var (
- ErrPulseCookie = errors.New("pulse cookie not present")
- ErrPulseSocket = errors.New("pulse socket not present")
- ErrPulseMode = errors.New("unexpected pulse socket mode")
-)
-
-func (seal *appSeal) sharePulse(os linux.System) error {
- if !seal.et.Has(system.EPulse) {
- return nil
- }
-
- // check PulseAudio directory presence (e.g. `/run/user/%d/pulse`)
- pd := path.Join(seal.RuntimePath, "pulse")
- ps := path.Join(pd, "native")
- if _, err := os.Stat(pd); err != nil {
- if !errors.Is(err, fs.ErrNotExist) {
- return fmsg.WrapErrorSuffix(err,
- fmt.Sprintf("cannot access PulseAudio directory %q:", 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 fmsg.WrapErrorSuffix(err,
- fmt.Sprintf("cannot access PulseAudio socket %q:", ps))
- }
- 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 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.bwrap.Bind(psi, p)
- seal.sys.bwrap.SetEnv[pulseServer] = "unix:" + p
-
- // publish current user's pulse cookie for target user
- if src, err := discoverPulseCookie(os); err != nil {
- fmsg.VPrintln(err.(*fmsg.BaseError).Message())
- } else {
- dst := path.Join(seal.share, "pulse-cookie")
- innerDst := fst.Tmp + "/pulse-cookie"
- seal.sys.bwrap.SetEnv[pulseCookie] = innerDst
- seal.sys.CopyFile(dst, src)
- seal.sys.bwrap.Bind(dst, innerDst)
- }
-
- return nil
-}
-
-// discoverPulseCookie attempts various standard methods to discover the current user's PulseAudio authentication cookie
-func discoverPulseCookie(os linux.System) (string, error) {
- if p, ok := os.LookupEnv(pulseCookie); ok {
- return p, nil
- }
-
- // dotfile $HOME/.pulse-cookie
- if p, ok := os.LookupEnv(home); ok {
- p = path.Join(p, ".pulse-cookie")
- if s, err := os.Stat(p); err != nil {
- if !errors.Is(err, fs.ErrNotExist) {
- return p, fmsg.WrapErrorSuffix(err,
- fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
- }
- // not found, try next method
- } else if !s.IsDir() {
- return p, nil
- }
- }
-
- // $XDG_CONFIG_HOME/pulse/cookie
- if p, ok := os.LookupEnv(xdgConfigHome); ok {
- p = path.Join(p, "pulse", "cookie")
- if s, err := os.Stat(p); err != nil {
- if !errors.Is(err, fs.ErrNotExist) {
- return p, fmsg.WrapErrorSuffix(err,
- fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
- }
- // not found, try next method
- } else if !s.IsDir() {
- return p, nil
- }
- }
-
- return "", fmsg.WrapError(ErrPulseCookie,
- fmt.Sprintf("cannot locate PulseAudio cookie (tried $%s, $%s/pulse/cookie, $%s/.pulse-cookie)",
- pulseCookie, xdgConfigHome, home))
-}
diff --git a/internal/app/share.runtime.go b/internal/app/share.runtime.go
deleted file mode 100644
index 720c47fc..00000000
--- a/internal/app/share.runtime.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package app
-
-import (
- "path"
-
- "git.gensokyo.uk/security/fortify/acl"
- "git.gensokyo.uk/security/fortify/internal/system"
-)
-
-const (
- xdgRuntimeDir = "XDG_RUNTIME_DIR"
- xdgSessionClass = "XDG_SESSION_CLASS"
- xdgSessionType = "XDG_SESSION_TYPE"
-)
-
-// shareRuntime queues actions for sharing/ensuring the runtime and share directories
-func (seal *appSeal) shareRuntime() {
- // mount tmpfs on inner runtime (e.g. `/run/user/%d`)
- seal.sys.bwrap.Tmpfs("/run/user", 1*1024*1024)
- seal.sys.bwrap.Tmpfs(seal.sys.runtime, 8*1024*1024)
-
- // point to inner runtime path `/run/user/%d`
- 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.UpdatePermType(system.User, seal.RunDirPath, acl.Execute)
-
- // ensure runtime directory ACL (e.g. `/run/user/%d`)
- seal.sys.Ensure(seal.RuntimePath, 0700) // ensure this dir in case XDG_RUNTIME_DIR is unset
- seal.sys.UpdatePermType(system.User, seal.RuntimePath, acl.Execute)
-
- // ensure process-specific share local to XDG_RUNTIME_DIR (e.g. `/run/user/%d/fortify/%s`)
- seal.shareLocal = path.Join(seal.RunDirPath, seal.id)
- 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
deleted file mode 100644
index 2e65ac69..00000000
--- a/internal/app/share.system.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package app
-
-import (
- "path"
-
- "git.gensokyo.uk/security/fortify/acl"
- "git.gensokyo.uk/security/fortify/internal/linux"
- "git.gensokyo.uk/security/fortify/internal/system"
-)
-
-const (
- shell = "SHELL"
-)
-
-// shareSystem queues various system-related actions
-func (seal *appSeal) shareSystem() {
- // ensure Share (e.g. `/tmp/fortify.%d`)
- // acl is unnecessary as this directory is world executable
- seal.sys.Ensure(seal.SharePath, 0711)
-
- // 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)
- seal.sys.Ephemeral(system.Process, seal.share, 0711)
-
- // ensure child tmpdir parent directory (e.g. `/tmp/fortify.%d/tmpdir`)
- targetTmpdirParent := path.Join(seal.SharePath, "tmpdir")
- 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.user.as)
- 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)
-}
-
-func (seal *appSeal) sharePasswd(os linux.System) {
- // look up shell
- sh := "/bin/sh"
- if s, ok := os.LookupEnv(shell); ok {
- seal.sys.bwrap.SetEnv[shell] = s
- sh = s
- }
-
- // generate /etc/passwd
- passwdPath := path.Join(seal.share, "passwd")
- username := "chronos"
- if seal.sys.user.username != "" {
- username = seal.sys.user.username
- }
- homeDir := "/var/empty"
- if seal.sys.user.home != "" {
- homeDir = seal.sys.user.home
- }
-
- // bind home directory
- seal.sys.bwrap.Bind(seal.sys.user.data, homeDir, false, true)
- seal.sys.bwrap.Chdir = homeDir
-
- seal.sys.bwrap.SetEnv["USER"] = username
- seal.sys.bwrap.SetEnv["HOME"] = homeDir
-
- passwd := username + ":x:" + seal.sys.mappedIDString + ":" + seal.sys.mappedIDString + ":Fortify:" + homeDir + ":" + sh + "\n"
- seal.sys.Write(passwdPath, passwd)
-
- // write /etc/group
- groupPath := path.Join(seal.share, "group")
- seal.sys.Write(groupPath, "fortify:x:"+seal.sys.mappedIDString+":\n")
-
- // bind /etc/passwd and /etc/group
- seal.sys.bwrap.Bind(passwdPath, "/etc/passwd")
- seal.sys.bwrap.Bind(groupPath, "/etc/group")
-}
diff --git a/internal/app/system.go b/internal/app/system.go
index 84028540..241eafa5 100644
--- a/internal/app/system.go
+++ b/internal/app/system.go
@@ -1,9 +1,7 @@
package app
import (
- "git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/helper/bwrap"
- "git.gensokyo.uk/security/fortify/internal/linux"
"git.gensokyo.uk/security/fortify/internal/system"
)
@@ -51,37 +49,3 @@ type appUser struct {
// passwd database username
username string
}
-
-// shareAll calls all share methods in sequence
-func (seal *appSeal) shareAll(bus [2]*dbus.Config, os linux.System) error {
- if seal.shared {
- panic("seal shared twice")
- }
- seal.shared = true
-
- seal.shareSystem()
- seal.shareRuntime()
- seal.sharePasswd(os)
- if err := seal.shareDisplay(os); err != nil {
- return err
- }
- if err := seal.sharePulse(os); err != nil {
- return err
- }
-
- // ensure dbus session bus defaults
- if bus[0] == nil {
- bus[0] = dbus.NewConfig(seal.fid, true, true)
- }
-
- if err := seal.shareDBus(bus); err != nil {
- return err
- }
-
- // 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
-}