app: hardlink sockets to process-specific share local to XDG_RUNTIME_DIR
This avoids adding ACLs to the PulseAudio directory. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
parent
2220055e26
commit
86cb5ac1db
|
@ -35,9 +35,11 @@ func (seal *appSeal) shareDisplay() error {
|
||||||
if wd, ok := os.LookupEnv(waylandDisplay); !ok {
|
if wd, ok := os.LookupEnv(waylandDisplay); !ok {
|
||||||
return (*ErrDisplayEnv)(wrapError(ErrWayland, "WAYLAND_DISPLAY is not set"))
|
return (*ErrDisplayEnv)(wrapError(ErrWayland, "WAYLAND_DISPLAY is not set"))
|
||||||
} else {
|
} else {
|
||||||
// wayland socket path
|
// hardlink wayland socket
|
||||||
wp := path.Join(seal.RuntimePath, wd)
|
wp := path.Join(seal.RuntimePath, wd)
|
||||||
seal.appendEnv(waylandDisplay, wp)
|
wpi := path.Join(seal.shareLocal, "wayland")
|
||||||
|
seal.sys.link(wp, wpi)
|
||||||
|
seal.appendEnv(waylandDisplay, wpi)
|
||||||
|
|
||||||
// ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`)
|
// ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`)
|
||||||
seal.sys.updatePerm(wp, acl.Read, acl.Write, acl.Execute)
|
seal.sys.updatePerm(wp, acl.Read, acl.Write, acl.Execute)
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"git.ophivana.moe/cat/fortify/acl"
|
|
||||||
"git.ophivana.moe/cat/fortify/internal/state"
|
"git.ophivana.moe/cat/fortify/internal/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,7 +34,7 @@ func (seal *appSeal) sharePulse() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure PulseAudio directory ACL (e.g. `/run/user/%d/pulse`)
|
// check PulseAudio directory presence (e.g. `/run/user/%d/pulse`)
|
||||||
pd := path.Join(seal.RuntimePath, "pulse")
|
pd := path.Join(seal.RuntimePath, "pulse")
|
||||||
ps := path.Join(pd, "native")
|
ps := path.Join(pd, "native")
|
||||||
if _, err := os.Stat(pd); err != nil {
|
if _, err := os.Stat(pd); err != nil {
|
||||||
|
@ -47,10 +46,7 @@ func (seal *appSeal) sharePulse() error {
|
||||||
fmt.Sprintf("PulseAudio directory '%s' not found", pd)))
|
fmt.Sprintf("PulseAudio directory '%s' not found", pd)))
|
||||||
}
|
}
|
||||||
|
|
||||||
seal.appendEnv(pulseServer, "unix:"+ps)
|
// check PulseAudio socket permission (e.g. `/run/user/%d/pulse/native`)
|
||||||
seal.sys.updatePerm(pd, acl.Execute)
|
|
||||||
|
|
||||||
// ensure PulseAudio socket permission (e.g. `/run/user/%d/pulse/native`)
|
|
||||||
if s, err := os.Stat(ps); err != nil {
|
if s, err := os.Stat(ps); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return (*PulseSocketAccessError)(wrapError(err,
|
return (*PulseSocketAccessError)(wrapError(err,
|
||||||
|
@ -65,6 +61,11 @@ func (seal *appSeal) sharePulse() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hard link pulse socket into target-executable share
|
||||||
|
psi := path.Join(seal.shareLocal, "pulse")
|
||||||
|
seal.sys.link(ps, psi)
|
||||||
|
seal.appendEnv(pulseServer, "unix:"+psi)
|
||||||
|
|
||||||
// publish current user's pulse cookie for target user
|
// publish current user's pulse cookie for target user
|
||||||
if src, err := discoverPulseCookie(); err != nil {
|
if src, err := discoverPulseCookie(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -16,6 +16,7 @@ const (
|
||||||
func (seal *appSeal) shareRuntime() {
|
func (seal *appSeal) shareRuntime() {
|
||||||
// ensure RunDir (e.g. `/run/user/%d/fortify`)
|
// ensure RunDir (e.g. `/run/user/%d/fortify`)
|
||||||
seal.sys.ensure(seal.RunDirPath, 0700)
|
seal.sys.ensure(seal.RunDirPath, 0700)
|
||||||
|
seal.sys.updatePerm(seal.RunDirPath, acl.Execute)
|
||||||
|
|
||||||
// ensure runtime directory ACL (e.g. `/run/user/%d`)
|
// ensure runtime directory ACL (e.g. `/run/user/%d`)
|
||||||
seal.sys.updatePerm(seal.RuntimePath, acl.Execute)
|
seal.sys.updatePerm(seal.RuntimePath, acl.Execute)
|
||||||
|
@ -28,6 +29,11 @@ func (seal *appSeal) shareRuntime() {
|
||||||
// acl is unnecessary as this directory is world executable
|
// acl is unnecessary as this directory is world executable
|
||||||
seal.share = path.Join(seal.SharePath, seal.id.String())
|
seal.share = path.Join(seal.SharePath, seal.id.String())
|
||||||
seal.sys.ensureEphemeral(seal.share, 0701)
|
seal.sys.ensureEphemeral(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)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (seal *appSeal) shareRuntimeChild() string {
|
func (seal *appSeal) shareRuntimeChild() string {
|
||||||
|
|
|
@ -33,6 +33,8 @@ type appSeal struct {
|
||||||
launchOption uint8
|
launchOption uint8
|
||||||
// process-specific share directory path
|
// process-specific share directory path
|
||||||
share string
|
share string
|
||||||
|
// process-specific share directory path local to XDG_RUNTIME_DIR
|
||||||
|
shareLocal string
|
||||||
|
|
||||||
// path to launcher program
|
// path to launcher program
|
||||||
toolPath string
|
toolPath string
|
||||||
|
@ -74,6 +76,8 @@ type appSealTx struct {
|
||||||
mkdir []appEnsureEntry
|
mkdir []appEnsureEntry
|
||||||
// dst, src pairs of temporarily shared files
|
// dst, src pairs of temporarily shared files
|
||||||
tmpfiles [][2]string
|
tmpfiles [][2]string
|
||||||
|
// dst, src pairs of temporarily hard linked files
|
||||||
|
hardlinks [][2]string
|
||||||
|
|
||||||
// sealed path to fortify executable, used by shim
|
// sealed path to fortify executable, used by shim
|
||||||
executable string
|
executable string
|
||||||
|
@ -143,6 +147,11 @@ func (tx *appSealTx) copyFile(dst, src string) {
|
||||||
tx.updatePerm(dst, acl.Read)
|
tx.updatePerm(dst, acl.Read)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// link appends a hardlink action
|
||||||
|
func (tx *appSealTx) link(oldname, newname string) {
|
||||||
|
tx.hardlinks = append(tx.hardlinks, [2]string{oldname, newname})
|
||||||
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
ChangeHostsError BaseError
|
ChangeHostsError BaseError
|
||||||
EnsureDirError BaseError
|
EnsureDirError BaseError
|
||||||
|
@ -152,7 +161,7 @@ type (
|
||||||
)
|
)
|
||||||
|
|
||||||
// commit applies recorded actions
|
// commit applies recorded actions
|
||||||
// order: xhost, mkdir, tmpfiles, dbus, acl
|
// order: xhost, mkdir, tmpfiles, hardlinks, dbus, acl
|
||||||
func (tx *appSealTx) commit() error {
|
func (tx *appSealTx) commit() error {
|
||||||
if tx.complete {
|
if tx.complete {
|
||||||
panic("seal transaction committed twice")
|
panic("seal transaction committed twice")
|
||||||
|
@ -211,6 +220,18 @@ func (tx *appSealTx) commit() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
if tx.dbus != nil {
|
||||||
// start dbus proxy
|
// start dbus proxy
|
||||||
verbose.Printf("session bus proxy on '%s' for upstream '%s'\n", tx.dbusAddr[0][1], tx.dbusAddr[0][0])
|
verbose.Printf("session bus proxy on '%s' for upstream '%s'\n", tx.dbusAddr[0][1], tx.dbusAddr[0][0])
|
||||||
|
@ -245,7 +266,7 @@ func (tx *appSealTx) commit() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// revert rolls back recorded actions
|
// revert rolls back recorded actions
|
||||||
// order: acl, dbus, tmpfiles, mkdir, xhost
|
// order: acl, dbus, hardlinks, tmpfiles, mkdir, xhost
|
||||||
// errors are printed but not treated as fatal
|
// errors are printed but not treated as fatal
|
||||||
func (tx *appSealTx) revert(global bool) error {
|
func (tx *appSealTx) revert(global bool) error {
|
||||||
if tx.closed {
|
if tx.closed {
|
||||||
|
@ -279,6 +300,13 @@ func (tx *appSealTx) revert(global bool) error {
|
||||||
joinError(err, "cannot stop message bus proxy:", err)
|
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
|
// remove tmpfiles
|
||||||
for _, tmpfile := range tx.tmpfiles {
|
for _, tmpfile := range tx.tmpfiles {
|
||||||
verbose.Println("removing tmpfile", tmpfile[0])
|
verbose.Println("removing tmpfile", tmpfile[0])
|
||||||
|
|
Loading…
Reference in New Issue