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:
@@ -1,7 +1,6 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
@@ -27,9 +26,6 @@ type app struct {
|
|||||||
cmd *exec.Cmd
|
cmd *exec.Cmd
|
||||||
// child process related information
|
// child process related information
|
||||||
seal *appSeal
|
seal *appSeal
|
||||||
|
|
||||||
// wayland connection if wayland mediation is enabled
|
|
||||||
wayland *net.UnixConn
|
|
||||||
// error returned waiting for process
|
// error returned waiting for process
|
||||||
waitErr error
|
waitErr error
|
||||||
|
|
||||||
|
|||||||
+41
-3
@@ -11,6 +11,7 @@ import (
|
|||||||
"git.ophivana.moe/security/fortify/dbus"
|
"git.ophivana.moe/security/fortify/dbus"
|
||||||
"git.ophivana.moe/security/fortify/internal"
|
"git.ophivana.moe/security/fortify/internal"
|
||||||
"git.ophivana.moe/security/fortify/internal/fmsg"
|
"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/state"
|
||||||
"git.ophivana.moe/security/fortify/internal/system"
|
"git.ophivana.moe/security/fortify/internal/system"
|
||||||
"git.ophivana.moe/security/fortify/internal/verbose"
|
"git.ophivana.moe/security/fortify/internal/verbose"
|
||||||
@@ -36,6 +37,43 @@ var (
|
|||||||
ErrMachineCtl = errors.New("machinectl not available")
|
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
|
// Seal seals the app launch context
|
||||||
func (a *app) Seal(config *Config) error {
|
func (a *app) Seal(config *Config) error {
|
||||||
a.lock.Lock()
|
a.lock.Lock()
|
||||||
@@ -176,10 +214,10 @@ func (a *app) Seal(config *Config) error {
|
|||||||
seal.sys.bwrap.SetEnv = make(map[string]string)
|
seal.sys.bwrap.SetEnv = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create wayland client wait channel if mediated wayland is enabled
|
// create wayland struct and client wait channel if mediated wayland is enabled
|
||||||
// this channel being set enables mediated wayland setup later on
|
// this field being set enables mediated wayland setup later on
|
||||||
if config.Confinement.Sandbox.Wayland {
|
if config.Confinement.Sandbox.Wayland {
|
||||||
seal.wlDone = make(chan struct{})
|
seal.wl = shim.NewWayland()
|
||||||
}
|
}
|
||||||
|
|
||||||
// open process state store
|
// open process state store
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (seal *appSeal) shareDisplay() error {
|
|||||||
if wd, ok := os.LookupEnv(waylandDisplay); !ok {
|
if wd, ok := os.LookupEnv(waylandDisplay); !ok {
|
||||||
return fmsg.WrapError(ErrWayland,
|
return fmsg.WrapError(ErrWayland,
|
||||||
"WAYLAND_DISPLAY is not set")
|
"WAYLAND_DISPLAY is not set")
|
||||||
} else if seal.wlDone == nil {
|
} else if seal.wl == nil {
|
||||||
// hardlink wayland socket
|
// hardlink wayland socket
|
||||||
wp := path.Join(seal.RuntimePath, wd)
|
wp := path.Join(seal.RuntimePath, wd)
|
||||||
wpi := path.Join(seal.shareLocal, "wayland")
|
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`)
|
// ensure Wayland socket ACL (e.g. `/run/user/%d/wayland-%d`)
|
||||||
seal.sys.UpdatePermType(system.EWayland, wp, acl.Read, acl.Write, acl.Execute)
|
seal.sys.UpdatePermType(system.EWayland, wp, acl.Read, acl.Write, acl.Execute)
|
||||||
} else {
|
} else {
|
||||||
// set wayland socket path (e.g. `/run/user/%d/wayland-%d`)
|
// set wayland socket path for mediation (e.g. `/run/user/%d/wayland-%d`)
|
||||||
seal.wl = path.Join(seal.RuntimePath, wd)
|
seal.wl.Path = path.Join(seal.RuntimePath, wd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-12
@@ -62,23 +62,19 @@ func (a *app) Start() error {
|
|||||||
confSockPath := path.Join(a.seal.share, "shim")
|
confSockPath := path.Join(a.seal.share, "shim")
|
||||||
a.cmd = exec.Command(a.seal.toolPath, commandBuilder(shim.EnvShim+"="+confSockPath)...)
|
a.cmd = exec.Command(a.seal.toolPath, commandBuilder(shim.EnvShim+"="+confSockPath)...)
|
||||||
a.cmd.Env = []string{}
|
a.cmd.Env = []string{}
|
||||||
a.cmd.Stdin = os.Stdin
|
a.cmd.Stdin, a.cmd.Stdout, a.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||||
a.cmd.Stdout = os.Stdout
|
|
||||||
a.cmd.Stderr = os.Stderr
|
|
||||||
a.cmd.Dir = a.seal.RunDirPath
|
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,
|
Argv: a.seal.command,
|
||||||
Exec: shimExec,
|
Exec: shimExec,
|
||||||
Bwrap: a.seal.sys.bwrap,
|
Bwrap: a.seal.sys.bwrap,
|
||||||
WL: a.seal.wlDone != nil,
|
WL: a.seal.wl != nil,
|
||||||
|
|
||||||
Verbose: verbose.Get(),
|
Verbose: verbose.Get(),
|
||||||
}, a.seal.wl, a.seal.wlDone); err != nil {
|
}, a.seal.wl); err != nil {
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return fmsg.WrapErrorSuffix(err,
|
||||||
"cannot listen on shim socket:")
|
"cannot serve shim setup:")
|
||||||
} else {
|
|
||||||
a.wayland = wls
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// start shim
|
// 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)
|
verbose.Println("process", strconv.Itoa(a.cmd.Process.Pid), "exited with exit code", r)
|
||||||
|
|
||||||
// close wayland connection
|
// close wayland connection
|
||||||
if a.wayland != nil {
|
if a.seal.wl != nil {
|
||||||
close(a.seal.wlDone)
|
if err := a.seal.wl.Close(); err != nil {
|
||||||
if err := a.wayland.Close(); err != nil {
|
|
||||||
fmt.Println("fortify: cannot close wayland connection:", err)
|
fmt.Println("fortify: cannot close wayland connection:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,51 +5,9 @@ import (
|
|||||||
|
|
||||||
"git.ophivana.moe/security/fortify/dbus"
|
"git.ophivana.moe/security/fortify/dbus"
|
||||||
"git.ophivana.moe/security/fortify/helper/bwrap"
|
"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"
|
"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
|
// appSealSys encapsulates app seal behaviour with OS interactions
|
||||||
type appSealSys struct {
|
type appSealSys struct {
|
||||||
bwrap *bwrap.Config
|
bwrap *bwrap.Config
|
||||||
|
|||||||
@@ -14,19 +14,18 @@ import (
|
|||||||
|
|
||||||
// called in the parent process
|
// called in the parent process
|
||||||
|
|
||||||
func ServeConfig(socket string, uid int, payload *Payload, wl string, done chan struct{}) (*net.UnixConn, error) {
|
func ServeConfig(socket string, uid int, payload *Payload, wl *Wayland) error {
|
||||||
var ws *net.UnixConn
|
|
||||||
if payload.WL {
|
if payload.WL {
|
||||||
if f, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: wl, Net: "unix"}); err != nil {
|
if f, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: wl.Path, Net: "unix"}); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
} else {
|
} else {
|
||||||
verbose.Println("connected to wayland at", wl)
|
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 {
|
if c, err := net.ListenUnix("unix", &net.UnixAddr{Name: socket, Net: "unix"}); err != nil {
|
||||||
return nil, err
|
return err
|
||||||
} else {
|
} else {
|
||||||
verbose.Println("configuring shim on socket", socket)
|
verbose.Println("configuring shim on socket", socket)
|
||||||
if err = acl.UpdatePerm(socket, uid, acl.Read, acl.Write, acl.Execute); err != nil {
|
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 {
|
if payload.WL {
|
||||||
// get raw connection
|
// get raw connection
|
||||||
var rc syscall.RawConn
|
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)
|
fmt.Println("fortify: cannot obtain raw wayland connection:", err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
@@ -61,7 +60,7 @@ func ServeConfig(socket string, uid int, payload *Payload, wl string, done chan
|
|||||||
_ = conn.Close()
|
_ = conn.Close()
|
||||||
|
|
||||||
// block until shim exits
|
// block until shim exits
|
||||||
<-done
|
<-wl.done
|
||||||
verbose.Println("releasing wayland connection")
|
verbose.Println("releasing wayland connection")
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println("fortify: cannot obtain wayland connection fd:", err)
|
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)
|
fmt.Println("fortify: cannot remove dangling shim socket:", err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return ws, nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user