app: migrate to new shim implementation

Both machinectl and sudo launch methods launch shim as shim is now responsible for setting up the sandbox. Various app structures are adapted to accommodate bwrap configuration and mediated wayland access.

Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
This commit is contained in:
2024-10-11 02:01:03 +09:00
parent b86fa6b4c9
commit 6220f7e197
11 changed files with 105 additions and 109 deletions

View File

@@ -2,11 +2,16 @@ package app
import (
"errors"
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strconv"
"time"
"git.ophivana.moe/cat/fortify/helper"
"git.ophivana.moe/cat/fortify/internal/shim"
"git.ophivana.moe/cat/fortify/internal/state"
"git.ophivana.moe/cat/fortify/internal/verbose"
)
@@ -14,6 +19,8 @@ import (
type (
// ProcessError encapsulates errors returned by starting *exec.Cmd
ProcessError BaseError
// ShimError encapsulates errors returned by shim.ServeConfig.
ShimError BaseError
)
// Start starts the fortified child
@@ -21,12 +28,30 @@ func (a *app) Start() error {
a.lock.Lock()
defer a.lock.Unlock()
// resolve exec paths
e := [2]string{helper.BubblewrapName}
if len(a.seal.command) > 0 {
e[1] = a.seal.command[0]
}
for i, n := range e {
if len(n) == 0 {
continue
}
if filepath.Base(n) == n {
if s, err := exec.LookPath(n); err == nil {
e[i] = s
} else {
return (*ProcessError)(wrapError(err, fmt.Sprintf("cannot find %q in PATH: %v", n, err)))
}
}
}
if err := a.seal.sys.commit(); err != nil {
return err
}
// select command builder
var commandBuilder func() (args []string)
var commandBuilder func(shimEnv string) (args []string)
switch a.seal.launchOption {
case LaunchMethodSudo:
commandBuilder = a.commandBuilderSudo
@@ -37,15 +62,30 @@ func (a *app) Start() error {
}
// configure child process
a.cmd = exec.Command(a.seal.toolPath, commandBuilder()...)
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.Dir = a.seal.RunDirPath
// start child process
verbose.Println("starting main process:", a.cmd)
if wls, err := shim.ServeConfig(confSockPath, &shim.Payload{
Argv: a.seal.command,
Env: a.seal.env,
Exec: e,
Bwrap: a.seal.bwrap,
WL: a.seal.wlDone != nil,
Verbose: verbose.Get(),
}, a.seal.wl, a.seal.wlDone); err != nil {
return (*ShimError)(wrapError(err, "cannot listen on shim socket:", err))
} else {
a.wayland = wls
}
// start shim
verbose.Println("starting shim as target user:", a.cmd)
if err := a.cmd.Start(); err != nil {
return (*ProcessError)(wrapError(err, "cannot start process:", err))
}
@@ -62,11 +102,11 @@ func (a *app) Start() error {
}
// register process state
var e = new(StateStoreError)
e.Inner, e.DoErr = a.seal.store.Do(func(b state.Backend) {
e.InnerErr = b.Save(&sd)
var err = new(StateStoreError)
err.Inner, err.DoErr = a.seal.store.Do(func(b state.Backend) {
err.InnerErr = b.Save(&sd)
})
return e.equiv("cannot save process state:", e)
return err.equiv("cannot save process state:", e)
}
// StateStoreError is returned for a failed state save
@@ -146,6 +186,14 @@ 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 {
fmt.Println("fortify: cannot close wayland connection:", err)
}
}
// update store and revert app setup transaction
e := new(StateStoreError)
e.Inner, e.DoErr = a.seal.store.Do(func(b state.Backend) {
@@ -187,7 +235,9 @@ func (a *app) Wait() (int, error) {
ct = append(ct, i)
}
}
verbose.Println("will revert operations tagged", ct, "as no remaining launchers hold these enablements")
if len(ct) > 0 {
verbose.Println("will revert operations tagged", ct, "as no remaining launchers hold these enablements")
}
}
if err := a.seal.sys.revert(tags); err != nil {