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
362ee73893
@ -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
|
||||
|
||||
|
@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.ophivana.moe/security/fortify/internal/shim"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
@ -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