diff options
| author | Ophestra Umiker <cat@ophivana.moe> | 2024-10-27 00:46:15 +0900 |
|---|---|---|
| committer | Ophestra Umiker <cat@ophivana.moe> | 2024-10-27 00:46:15 +0900 |
| commit | 1d6ea8120552665072f5044a004128e7dbbf3a64 (patch) | |
| tree | 1ea0b9d2f687909cdd5fab3fbf50c473f942e7cf /internal/app | |
| parent | ae1a102882103221ef842176dfd8cb1090d5f591 (diff) | |
shim: user switcher process management struct
This change moves all user switcher and shim management to the shim package and withholds output while shim is alive. This also eliminated all exit scenarios where revert is skipped.
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'internal/app')
| -rw-r--r-- | internal/app/app.go | 12 | ||||
| -rw-r--r-- | internal/app/start.go | 132 | ||||
| -rw-r--r-- | internal/app/system.go | 2 |
3 files changed, 67 insertions, 79 deletions
diff --git a/internal/app/app.go b/internal/app/app.go index de2c461f..264975c5 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -1,10 +1,10 @@ package app import ( - "os/exec" "sync" "git.ophivana.moe/security/fortify/internal" + "git.ophivana.moe/security/fortify/internal/shim" ) type App interface { @@ -26,10 +26,8 @@ type app struct { id *ID // operating system interface os internal.System - // underlying user switcher process - cmd *exec.Cmd - // shim setup abort reason and completion - abort chan error + // shim process manager + shim *shim.Shim // child process related information seal *appSeal // error returned waiting for process @@ -50,8 +48,8 @@ func (a *app) String() string { a.lock.RLock() defer a.lock.RUnlock() - if a.cmd != nil { - return a.cmd.String() + if a.shim != nil { + return a.shim.String() } if a.seal != nil { diff --git a/internal/app/start.go b/internal/app/start.go index 49a4678a..ea216018 100644 --- a/internal/app/start.go +++ b/internal/app/start.go @@ -3,12 +3,10 @@ package app import ( "errors" "fmt" - "os" "os/exec" "path" "path/filepath" "strings" - "time" "git.ophivana.moe/security/fortify/helper" "git.ophivana.moe/security/fortify/internal/fmsg" @@ -17,7 +15,8 @@ import ( "git.ophivana.moe/security/fortify/internal/system" ) -// Start starts the fortified child +// Start selects a user switcher and starts shim. +// Note that Wait must be called regardless of error returned by Start. func (a *app) Start() error { a.lock.Lock() defer a.lock.Unlock() @@ -41,12 +40,8 @@ func (a *app) Start() error { } } - if err := a.seal.sys.Commit(); err != nil { - return err - } - // select command builder - var commandBuilder func(shimEnv string) (args []string) + var commandBuilder shim.CommandBuilder switch a.seal.launchOption { case LaunchMethodSudo: commandBuilder = a.commandBuilderSudo @@ -56,60 +51,45 @@ func (a *app) Start() error { panic("unreachable") } - // configure child process - 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, a.cmd.Stdout, a.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr - a.cmd.Dir = a.seal.RunDirPath + // construct shim manager + a.shim = shim.New(a.seal.toolPath, uint32(a.seal.sys.UID()), path.Join(a.seal.share, "shim"), a.seal.wl, + &shim.Payload{ + Argv: a.seal.command, + Exec: shimExec, + Bwrap: a.seal.sys.bwrap, + WL: a.seal.wl != nil, - a.abort = make(chan error) - procReady := make(chan struct{}) - if err := shim.ServeConfig(confSockPath, a.abort, func() { - <-procReady - if err := a.cmd.Process.Signal(os.Interrupt); err != nil { - fmsg.Println("cannot kill shim on faulted setup:", err) - } - fmt.Print("\r") - }, a.seal.sys.UID(), &shim.Payload{ - Argv: a.seal.command, - Exec: shimExec, - Bwrap: a.seal.sys.bwrap, - WL: a.seal.wl != nil, + Verbose: fmsg.Verbose(), + }, + ) - Verbose: fmsg.Verbose(), - }, a.seal.wl); err != nil { - a.abort <- err - <-a.abort - return fmsg.WrapErrorSuffix(err, - "cannot serve shim setup:") + // startup will go ahead, commit system setup + if err := a.seal.sys.Commit(); err != nil { + return err } + a.seal.sys.needRevert = true - // start shim - fmsg.VPrintln("starting shim as target user:", a.cmd) - if err := a.cmd.Start(); err != nil { - return fmsg.WrapErrorSuffix(err, - "cannot start process:") - } - startTime := time.Now().UTC() - close(procReady) + if startTime, err := a.shim.Start(commandBuilder); err != nil { + return err + } else { + // shim start and setup success, create process state + sd := state.State{ + PID: a.shim.Unwrap().Process.Pid, + Command: a.seal.command, + Capability: a.seal.et, + Method: method[a.seal.launchOption], + Argv: a.shim.Unwrap().Args, + Time: *startTime, + } - // create process state - sd := state.State{ - PID: a.cmd.Process.Pid, - Command: a.seal.command, - Capability: a.seal.et, - Method: method[a.seal.launchOption], - Argv: a.cmd.Args, - Time: startTime, + // register process state + var err0 = new(StateStoreError) + err0.Inner, err0.DoErr = a.seal.store.Do(func(b state.Backend) { + err0.InnerErr = b.Save(&sd) + }) + a.seal.sys.saveState = true + return err0.equiv("cannot save process state:") } - - // register process state - var err = new(StateStoreError) - err.Inner, err.DoErr = a.seal.store.Do(func(b state.Backend) { - err.InnerErr = b.Save(&sd) - }) - return err.equiv("cannot save process state:") } // StateStoreError is returned for a failed state save @@ -173,21 +153,28 @@ func (a *app) Wait() (int, error) { var r int - // wait for process and resolve exit code - if err := a.cmd.Wait(); err != nil { - var exitError *exec.ExitError - if !errors.As(err, &exitError) { - // should be unreachable - a.waitErr = err - } - - // store non-zero return code - r = exitError.ExitCode() + if cmd := a.shim.Unwrap(); cmd == nil { + // failure prior to process start + r = 255 } else { - r = a.cmd.ProcessState.ExitCode() + // wait for process and resolve exit code + if err := cmd.Wait(); err != nil { + var exitError *exec.ExitError + if !errors.As(err, &exitError) { + // should be unreachable + a.waitErr = err + } + + // store non-zero return code + r = exitError.ExitCode() + } else { + r = cmd.ProcessState.ExitCode() + } + fmsg.VPrintf("process %d exited with exit code %d", cmd.Process.Pid, r) } - fmsg.VPrintf("process %d exited with exit code %d", a.cmd.Process.Pid, r) + // child process exited, resume output + fmsg.Resume() // close wayland connection if a.seal.wl != nil { @@ -201,8 +188,10 @@ func (a *app) Wait() (int, error) { e.Inner, e.DoErr = a.seal.store.Do(func(b state.Backend) { e.InnerErr = func() error { // destroy defunct state entry - if err := b.Destroy(a.cmd.Process.Pid); err != nil { - return err + if cmd := a.shim.Unwrap(); cmd != nil && a.seal.sys.saveState { + if err := b.Destroy(cmd.Process.Pid); err != nil { + return err + } } // enablements of remaining launchers @@ -243,8 +232,7 @@ func (a *app) Wait() (int, error) { } } - a.abort <- errors.New("shim exited") - <-a.abort + a.shim.AbortWait(errors.New("shim exited")) if err := a.seal.sys.Revert(ec); err != nil { return err.(RevertCompoundError) } diff --git a/internal/app/system.go b/internal/app/system.go index 7ccc2eeb..74b8e611 100644 --- a/internal/app/system.go +++ b/internal/app/system.go @@ -22,6 +22,8 @@ type appSealSys struct { // target user sealed from config user *user.User + needRevert bool + saveState bool *system.I // protected by upstream mutex |
