app: move wayland mediation to shim package
All checks were successful
test / test (push) Successful in 29s
All checks were successful
test / test (push) Successful in 29s
Values used in the Wayland mediation implementation is stored in various struct fields strewn across multiple app structs and checks are messy and confusing. This commit unifies them into a single struct and access it using much better looking methods. Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
parent
133f23e0de
commit
380d1f4585
@ -1,7 +1,6 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os/exec"
|
||||
"sync"
|
||||
)
|
||||
@ -27,9 +26,6 @@ type app struct {
|
||||
cmd *exec.Cmd
|
||||
// child process related information
|
||||
seal *appSeal
|
||||
|
||||
// wayland connection if wayland mediation is enabled
|
||||
wayland *net.UnixConn
|
||||
// error returned waiting for process
|
||||
waitErr error
|
||||
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"git.ophivana.moe/security/fortify/dbus"
|
||||
"git.ophivana.moe/security/fortify/internal"
|
||||
"git.ophivana.moe/security/fortify/internal/fmsg"
|
||||
"git.ophivana.moe/security/fortify/internal/shim"
|
||||
"git.ophivana.moe/security/fortify/internal/state"
|
||||
"git.ophivana.moe/security/fortify/internal/system"
|
||||
"git.ophivana.moe/security/fortify/internal/verbose"
|
||||
@ -36,6 +37,43 @@ var (
|
||||
ErrMachineCtl = errors.New("machinectl not available")
|
||||
)
|
||||
|
||||
// appSeal seals the application with child-related information
|
||||
type appSeal struct {
|
||||
// app unique ID string representation
|
||||
id string
|
||||
// wayland mediation, disabled if nil
|
||||
wl *shim.Wayland
|
||||
|
||||
// freedesktop application ID
|
||||
fid string
|
||||
// argv to start process with in the final confined environment
|
||||
command []string
|
||||
// persistent process state store
|
||||
store state.Store
|
||||
|
||||
// uint8 representation of launch method sealed from config
|
||||
launchOption uint8
|
||||
// process-specific share directory path
|
||||
share string
|
||||
// process-specific share directory path local to XDG_RUNTIME_DIR
|
||||
shareLocal string
|
||||
|
||||
// path to launcher program
|
||||
toolPath string
|
||||
// pass-through enablement tracking from config
|
||||
et system.Enablements
|
||||
|
||||
// prevents sharing from happening twice
|
||||
shared bool
|
||||
// seal system-level component
|
||||
sys *appSealSys
|
||||
|
||||
// used in various sealing operations
|
||||
internal.SystemConstants
|
||||
|
||||
// protected by upstream mutex
|
||||
}
|
||||
|
||||
// Seal seals the app launch context
|
||||
func (a *app) Seal(config *Config) error {
|
||||
a.lock.Lock()
|
||||
@ -176,10 +214,10 @@ func (a *app) Seal(config *Config) error {
|
||||
seal.sys.bwrap.SetEnv = make(map[string]string)
|
||||
}
|
||||
|
||||
// create wayland client wait channel if mediated wayland is enabled
|
||||
// this channel being set enables mediated wayland setup later on
|
||||
// create wayland struct and client wait channel if mediated wayland is enabled
|
||||
// this field being set enables mediated wayland setup later on
|
||||
if config.Confinement.Sandbox.Wayland {
|
||||
seal.wlDone = make(chan struct{})
|
||||
seal.wl = shim.NewWayland()
|
||||
}
|
||||
|
||||
// open process state store
|
||||
|
@ -34,7 +34,7 @@ func (seal *appSeal) shareDisplay() error {
|
||||
if wd, ok := os.LookupEnv(waylandDisplay); !ok {
|
||||
return fmsg.WrapError(ErrWayland,
|
||||
"WAYLAND_DISPLAY is not set")
|
||||
} else if seal.wlDone == nil {
|
||||
} else if seal.wl == nil {
|
||||
// hardlink wayland socket
|
||||
wp := path.Join(seal.RuntimePath, wd)
|
||||
wpi := path.Join(seal.shareLocal, "wayland")
|
||||
@ -46,8 +46,8 @@ func (seal *appSeal) shareDisplay() error {
|
||||
// ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`)
|
||||
seal.sys.UpdatePermType(system.EWayland, 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)
|
||||
// set wayland socket path for mediation (e.g. `/run/user/%d/wayland-%d`)
|
||||
seal.wl.Path = path.Join(seal.RuntimePath, wd)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,23 +62,19 @@ func (a *app) Start() error {
|
||||
confSockPath := path.Join(a.seal.share, "shim")
|
||||
a.cmd = exec.Command(a.seal.toolPath, commandBuilder(shim.EnvShim+"="+confSockPath)...)
|
||||
a.cmd.Env = []string{}
|
||||
a.cmd.Stdin = os.Stdin
|
||||
a.cmd.Stdout = os.Stdout
|
||||
a.cmd.Stderr = os.Stderr
|
||||
a.cmd.Stdin, a.cmd.Stdout, a.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
a.cmd.Dir = a.seal.RunDirPath
|
||||
|
||||
if wls, err := shim.ServeConfig(confSockPath, a.seal.sys.UID(), &shim.Payload{
|
||||
if err := shim.ServeConfig(confSockPath, a.seal.sys.UID(), &shim.Payload{
|
||||
Argv: a.seal.command,
|
||||
Exec: shimExec,
|
||||
Bwrap: a.seal.sys.bwrap,
|
||||
WL: a.seal.wlDone != nil,
|
||||
WL: a.seal.wl != nil,
|
||||
|
||||
Verbose: verbose.Get(),
|
||||
}, a.seal.wl, a.seal.wlDone); err != nil {
|
||||
}, a.seal.wl); err != nil {
|
||||
return fmsg.WrapErrorSuffix(err,
|
||||
"cannot listen on shim socket:")
|
||||
} else {
|
||||
a.wayland = wls
|
||||
"cannot serve shim setup:")
|
||||
}
|
||||
|
||||
// start shim
|
||||
@ -185,9 +181,8 @@ func (a *app) Wait() (int, error) {
|
||||
verbose.Println("process", strconv.Itoa(a.cmd.Process.Pid), "exited with exit code", r)
|
||||
|
||||
// close wayland connection
|
||||
if a.wayland != nil {
|
||||
close(a.seal.wlDone)
|
||||
if err := a.wayland.Close(); err != nil {
|
||||
if a.seal.wl != nil {
|
||||
if err := a.seal.wl.Close(); err != nil {
|
||||
fmt.Println("fortify: cannot close wayland connection:", err)
|
||||
}
|
||||
}
|
||||
|
@ -5,51 +5,9 @@ import (
|
||||
|
||||
"git.ophivana.moe/security/fortify/dbus"
|
||||
"git.ophivana.moe/security/fortify/helper/bwrap"
|
||||
"git.ophivana.moe/security/fortify/internal"
|
||||
"git.ophivana.moe/security/fortify/internal/state"
|
||||
"git.ophivana.moe/security/fortify/internal/system"
|
||||
)
|
||||
|
||||
// appSeal seals the application with child-related information
|
||||
type appSeal struct {
|
||||
// wayland socket path if mediated wayland is enabled
|
||||
wl string
|
||||
// wait for wayland client to exit if mediated wayland is enabled,
|
||||
// (wlDone == nil) determines whether mediated wayland setup is performed
|
||||
wlDone chan struct{}
|
||||
|
||||
// app unique ID string representation
|
||||
id string
|
||||
// freedesktop application ID
|
||||
fid string
|
||||
// argv to start process with in the final confined environment
|
||||
command []string
|
||||
// persistent process state store
|
||||
store state.Store
|
||||
|
||||
// uint8 representation of launch method sealed from config
|
||||
launchOption uint8
|
||||
// process-specific share directory path
|
||||
share string
|
||||
// process-specific share directory path local to XDG_RUNTIME_DIR
|
||||
shareLocal string
|
||||
|
||||
// path to launcher program
|
||||
toolPath string
|
||||
// pass-through enablement tracking from config
|
||||
et system.Enablements
|
||||
|
||||
// prevents sharing from happening twice
|
||||
shared bool
|
||||
// seal system-level component
|
||||
sys *appSealSys
|
||||
|
||||
// used in various sealing operations
|
||||
internal.SystemConstants
|
||||
|
||||
// protected by upstream mutex
|
||||
}
|
||||
|
||||
// appSealSys encapsulates app seal behaviour with OS interactions
|
||||
type appSealSys struct {
|
||||
bwrap *bwrap.Config
|
||||
|
@ -14,19 +14,18 @@ import (
|
||||
|
||||
// called in the parent process
|
||||
|
||||
func ServeConfig(socket string, uid int, payload *Payload, wl string, done chan struct{}) (*net.UnixConn, error) {
|
||||
var ws *net.UnixConn
|
||||
func ServeConfig(socket string, uid int, payload *Payload, wl *Wayland) error {
|
||||
if payload.WL {
|
||||
if f, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: wl, Net: "unix"}); err != nil {
|
||||
return nil, err
|
||||
if f, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: wl.Path, Net: "unix"}); err != nil {
|
||||
return err
|
||||
} else {
|
||||
verbose.Println("connected to wayland at", wl)
|
||||
ws = f
|
||||
wl.UnixConn = f
|
||||
}
|
||||
}
|
||||
|
||||
if c, err := net.ListenUnix("unix", &net.UnixAddr{Name: socket, Net: "unix"}); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
} else {
|
||||
verbose.Println("configuring shim on socket", socket)
|
||||
if err = acl.UpdatePerm(socket, uid, acl.Read, acl.Write, acl.Execute); err != nil {
|
||||
@ -47,7 +46,7 @@ func ServeConfig(socket string, uid int, payload *Payload, wl string, done chan
|
||||
if payload.WL {
|
||||
// get raw connection
|
||||
var rc syscall.RawConn
|
||||
if rc, err = ws.SyscallConn(); err != nil {
|
||||
if rc, err = wl.SyscallConn(); err != nil {
|
||||
fmt.Println("fortify: cannot obtain raw wayland connection:", err)
|
||||
return
|
||||
} else {
|
||||
@ -61,7 +60,7 @@ func ServeConfig(socket string, uid int, payload *Payload, wl string, done chan
|
||||
_ = conn.Close()
|
||||
|
||||
// block until shim exits
|
||||
<-done
|
||||
<-wl.done
|
||||
verbose.Println("releasing wayland connection")
|
||||
}); err != nil {
|
||||
fmt.Println("fortify: cannot obtain wayland connection fd:", err)
|
||||
@ -79,6 +78,6 @@ func ServeConfig(socket string, uid int, payload *Payload, wl string, done chan
|
||||
fmt.Println("fortify: cannot remove dangling shim socket:", err)
|
||||
}
|
||||
}()
|
||||
return ws, nil
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
35
internal/shim/wayland.go
Normal file
35
internal/shim/wayland.go
Normal file
@ -0,0 +1,35 @@
|
||||
package shim
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Wayland implements wayland mediation.
|
||||
type Wayland struct {
|
||||
// wayland socket path
|
||||
Path string
|
||||
|
||||
// wayland connection
|
||||
*net.UnixConn
|
||||
|
||||
connErr error
|
||||
sync.Once
|
||||
// wait for wayland client to exit
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func (wl *Wayland) Close() error {
|
||||
wl.Do(func() {
|
||||
close(wl.done)
|
||||
wl.connErr = wl.UnixConn.Close()
|
||||
})
|
||||
|
||||
return wl.connErr
|
||||
}
|
||||
|
||||
func NewWayland() *Wayland {
|
||||
wl := new(Wayland)
|
||||
wl.done = make(chan struct{})
|
||||
return wl
|
||||
}
|
Loading…
Reference in New Issue
Block a user