cmd/fpkg: call app in-process
Wrapping fortify is slow, painful and error-prone. Start apps in-process instead. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -1,23 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"syscall"
|
||||
|
||||
"git.gensokyo.uk/security/fortify/command"
|
||||
"git.gensokyo.uk/security/fortify/fst"
|
||||
"git.gensokyo.uk/security/fortify/helper/bwrap"
|
||||
"git.gensokyo.uk/security/fortify/helper/seccomp"
|
||||
"git.gensokyo.uk/security/fortify/internal"
|
||||
init0 "git.gensokyo.uk/security/fortify/internal/app/init"
|
||||
"git.gensokyo.uk/security/fortify/internal/app/shim"
|
||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
||||
)
|
||||
|
||||
const shellPath = "/run/current-system/sw/bin/bash"
|
||||
|
||||
var (
|
||||
errSuccess = errors.New("success")
|
||||
|
||||
std sys.State = new(sys.Std)
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -28,14 +37,40 @@ func init() {
|
||||
}
|
||||
|
||||
func main() {
|
||||
// early init argv0 check, skips root check and duplicate PR_SET_DUMPABLE
|
||||
init0.TryArgv0()
|
||||
|
||||
if err := internal.PR_SET_DUMPABLE__SUID_DUMP_DISABLE(); err != nil {
|
||||
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||
// not fatal: this program runs as the privileged user
|
||||
}
|
||||
|
||||
if os.Geteuid() == 0 {
|
||||
log.Fatal("this program must not run as root")
|
||||
}
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(),
|
||||
syscall.SIGINT, syscall.SIGTERM)
|
||||
defer stop() // unreachable
|
||||
|
||||
var (
|
||||
flagVerbose bool
|
||||
flagDropShell bool
|
||||
)
|
||||
c := command.New(os.Stderr, log.Printf, "fpkg", func([]string) error { fmsg.Store(flagVerbose); return nil }).
|
||||
c := command.New(os.Stderr, log.Printf, "fpkg", func([]string) error {
|
||||
fmsg.Store(flagVerbose)
|
||||
if flagVerbose {
|
||||
seccomp.CPrintln = log.Println
|
||||
}
|
||||
return nil
|
||||
}).
|
||||
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
|
||||
Flag(&flagDropShell, "s", command.BoolFlag(false), "Drop to a shell in place of next fortify action")
|
||||
|
||||
// internal commands
|
||||
c.Command("shim", command.UsageInternal, func([]string) error { shim.Main(); return errSuccess })
|
||||
c.Command("init", command.UsageInternal, func([]string) error { init0.Main(); return errSuccess })
|
||||
|
||||
{
|
||||
var (
|
||||
flagDropShellActivate bool
|
||||
@@ -149,7 +184,7 @@ func main() {
|
||||
Setup steps for files owned by the target user.
|
||||
*/
|
||||
|
||||
withCacheDir("install", []string{
|
||||
withCacheDir(ctx, "install", []string{
|
||||
// export inner bundle path in the environment
|
||||
"export BUNDLE=" + fst.Tmp + "/bundle",
|
||||
// replace inner /etc
|
||||
@@ -171,7 +206,7 @@ func main() {
|
||||
}, workDir, bundle, pathSet, flagDropShell, cleanup)
|
||||
|
||||
if bundle.GPU {
|
||||
withCacheDir("mesa-wrappers", []string{
|
||||
withCacheDir(ctx, "mesa-wrappers", []string{
|
||||
// link nixGL mesa wrappers
|
||||
"mkdir -p nix/.nixGL",
|
||||
"ln -s " + bundle.Mesa + "/bin/nixGLIntel nix/.nixGL/nixGL",
|
||||
@@ -183,7 +218,7 @@ func main() {
|
||||
Activate home-manager generation.
|
||||
*/
|
||||
|
||||
withNixDaemon("activate", []string{
|
||||
withNixDaemon(ctx, "activate", []string{
|
||||
// clean up broken links
|
||||
"mkdir -p .local/state/{nix,home-manager}",
|
||||
"chmod -R +w .local/state/{nix,home-manager}",
|
||||
@@ -251,7 +286,7 @@ func main() {
|
||||
*/
|
||||
|
||||
if app.GPU && flagAutoDrivers {
|
||||
withNixDaemon("nix-gl", []string{
|
||||
withNixDaemon(ctx, "nix-gl", []string{
|
||||
"mkdir -p /nix/.nixGL/auto",
|
||||
"rm -rf /nix/.nixGL/auto",
|
||||
"export NIXPKGS_ALLOW_UNFREE=1",
|
||||
@@ -349,7 +384,7 @@ func main() {
|
||||
Spawn app.
|
||||
*/
|
||||
|
||||
fortifyApp(config, func() {})
|
||||
mustRunApp(ctx, config, func() {})
|
||||
return errSuccess
|
||||
}).
|
||||
Flag(&flagDropShellNixGL, "s", command.BoolFlag(false), "Drop to a shell on nixGL build").
|
||||
|
||||
@@ -1,59 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"git.gensokyo.uk/security/fortify/fst"
|
||||
"git.gensokyo.uk/security/fortify/internal"
|
||||
"git.gensokyo.uk/security/fortify/internal/app"
|
||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
||||
)
|
||||
|
||||
func fortifyApp(config *fst.Config, beforeFail func()) {
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
st io.WriteCloser
|
||||
)
|
||||
if p, ok := internal.Path(internal.Fortify); !ok {
|
||||
beforeFail()
|
||||
log.Fatal("invalid fortify path, this copy of fpkg is not compiled correctly")
|
||||
} else if r, w, err := os.Pipe(); err != nil {
|
||||
beforeFail()
|
||||
log.Fatalf("cannot pipe: %v", err)
|
||||
func mustRunApp(ctx context.Context, config *fst.Config, beforeFail func()) {
|
||||
rs := new(fst.RunState)
|
||||
a := app.MustNew(std)
|
||||
|
||||
if sa, err := a.Seal(config); err != nil {
|
||||
fmsg.PrintBaseError(err, "cannot seal app:")
|
||||
rs.ExitCode = 1
|
||||
} else {
|
||||
if fmsg.Load() {
|
||||
cmd = exec.Command(p, "-v", "app", "3")
|
||||
} else {
|
||||
cmd = exec.Command(p, "app", "3")
|
||||
}
|
||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||
cmd.ExtraFiles = []*os.File{r}
|
||||
st = w
|
||||
// this updates ExitCode
|
||||
app.PrintRunStateErr(rs, sa.Run(ctx, rs))
|
||||
}
|
||||
|
||||
go func() {
|
||||
if err := json.NewEncoder(st).Encode(config); err != nil {
|
||||
beforeFail()
|
||||
log.Fatalf("cannot send configuration: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
if rs.ExitCode != 0 {
|
||||
beforeFail()
|
||||
log.Fatalf("cannot start fortify: %v", err)
|
||||
}
|
||||
if err := cmd.Wait(); err != nil {
|
||||
var exitError *exec.ExitError
|
||||
if errors.As(err, &exitError) {
|
||||
beforeFail()
|
||||
internal.Exit(exitError.ExitCode())
|
||||
} else {
|
||||
beforeFail()
|
||||
log.Fatalf("cannot wait: %v", err)
|
||||
}
|
||||
os.Exit(rs.ExitCode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
@@ -10,10 +11,11 @@ import (
|
||||
)
|
||||
|
||||
func withNixDaemon(
|
||||
ctx context.Context,
|
||||
action string, command []string, net bool, updateConfig func(config *fst.Config) *fst.Config,
|
||||
app *bundleInfo, pathSet *appPathSet, dropShell bool, beforeFail func(),
|
||||
) {
|
||||
fortifyAppDropShell(updateConfig(&fst.Config{
|
||||
mustRunAppDropShell(ctx, updateConfig(&fst.Config{
|
||||
ID: app.ID,
|
||||
Command: []string{shellPath, "-lc", "rm -f /nix/var/nix/daemon-socket/socket && " +
|
||||
// start nix-daemon
|
||||
@@ -56,8 +58,11 @@ func withNixDaemon(
|
||||
}), dropShell, beforeFail)
|
||||
}
|
||||
|
||||
func withCacheDir(action string, command []string, workDir string, app *bundleInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) {
|
||||
fortifyAppDropShell(&fst.Config{
|
||||
func withCacheDir(
|
||||
ctx context.Context,
|
||||
action string, command []string, workDir string,
|
||||
app *bundleInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) {
|
||||
mustRunAppDropShell(ctx, &fst.Config{
|
||||
ID: app.ID,
|
||||
Command: []string{shellPath, "-lc", strings.Join(command, " && ")},
|
||||
Confinement: fst.ConfinementConfig{
|
||||
@@ -90,12 +95,12 @@ func withCacheDir(action string, command []string, workDir string, app *bundleIn
|
||||
}, dropShell, beforeFail)
|
||||
}
|
||||
|
||||
func fortifyAppDropShell(config *fst.Config, dropShell bool, beforeFail func()) {
|
||||
func mustRunAppDropShell(ctx context.Context, config *fst.Config, dropShell bool, beforeFail func()) {
|
||||
if dropShell {
|
||||
config.Command = []string{shellPath, "-l"}
|
||||
fortifyApp(config, beforeFail)
|
||||
mustRunApp(ctx, config, beforeFail)
|
||||
beforeFail()
|
||||
internal.Exit(0)
|
||||
}
|
||||
fortifyApp(config, beforeFail)
|
||||
mustRunApp(ctx, config, beforeFail)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user