diff options
| author | Ophestra <cat@gensokyo.uk> | 2024-12-29 17:55:56 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2024-12-29 17:55:56 +0900 |
| commit | 5302879b880f095d528b57de2c72d4242faa62ec (patch) | |
| tree | 9c6ea9c8294d9303f064b4fbed9c2fb09d688f4f /cmd/fpkg | |
| parent | 891b3cbde75c071b7339716d6fae727e26f19c0a (diff) | |
cmd/fpkg: improve readability of fortify invocations
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd/fpkg')
| -rw-r--r-- | cmd/fpkg/install.go | 177 |
1 files changed, 101 insertions, 76 deletions
diff --git a/cmd/fpkg/install.go b/cmd/fpkg/install.go index 86c6ab25..988f4a86 100644 --- a/cmd/fpkg/install.go +++ b/cmd/fpkg/install.go @@ -5,6 +5,7 @@ import ( "flag" "os" "path" + "strings" "git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/fortify/internal/fmsg" @@ -123,32 +124,96 @@ func actionInstall(args []string) { Setup steps for files owned by the target user. */ - installConfig := &fst.Config{ + withCacheDir("install", []string{ + // export inner bundle path in the environment + "export BUNDLE=" + fst.Tmp + "/bundle", + // replace inner /etc + "mkdir -p etc", + "chmod -R +w etc", + "rm -rf etc", + "cp -dRf $BUNDLE/etc etc", + // replace inner /nix + "mkdir -p nix", + "chmod -R +w nix", + "rm -rf nix", + "cp -dRf /nix nix", + // copy from binary cache + "nix copy --offline --no-check-sigs --all --from file://$BUNDLE/res --to $PWD", + // make cache directory world-readable for autoetc + "chmod 0755 .", + }, workDir, bundle, pathSet, dropShellInstall, cleanup) + + /* + Activate home-manager generation. + */ + + withNixDaemon("activate", []string{ + // clean up broken links + "mkdir -p .local/state/{nix,home-manager}", + "chmod -R +w .local/state/{nix,home-manager}", + "rm -rf .local/state/{nix,home-manager}", + // run activation script + bundle.ActivationPackage + "/activate", + }, workDir, bundle, pathSet, dropShellActivate, cleanup) + + /* + Installation complete. Write metadata to block re-installs or downgrades. + */ + + // serialise metadata to ensure consistency + if f, err := os.OpenFile(pathSet.metaPath+"~", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err != nil { + cleanup() + fmsg.Fatalf("cannot create metadata file: %v", err) + panic("unreachable") + } else if err = json.NewEncoder(f).Encode(bundle); err != nil { + cleanup() + fmsg.Fatalf("cannot write metadata: %v", err) + panic("unreachable") + } else if err = f.Close(); err != nil { + fmsg.Printf("cannot close metadata file: %v", err) + // not fatal + } + + if err := os.Rename(pathSet.metaPath+"~", pathSet.metaPath); err != nil { + cleanup() + fmsg.Fatalf("cannot rename metadata file: %v", err) + panic("unreachable") + } + + cleanup() +} + +func withNixDaemon(action string, command []string, workDir string, bundle *bundleInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) { + fortifyAppDropShell(&fst.Config{ ID: bundle.ID, - Command: []string{shell, "-lc", "export BUNDLE=" + fst.Tmp + "/bundle && " + // export inner bundle path in the environment - "mkdir -p etc && chmod -R +w etc && rm -rf etc && cp -dRf $BUNDLE/etc etc && " + // replace inner /etc - "mkdir -p nix && chmod -R +w nix && rm -rf nix && cp -dRf /nix nix && " + // replace inner /nix - "nix copy --offline --no-check-sigs --all --from file://$BUNDLE/res --to $PWD && " + // copy from binary cache - "chmod 0755 .", // make cache directory world-readable for autoetc + Command: []string{shell, "-lc", "rm -f /nix/var/nix/daemon-socket/socket && " + + // start nix-daemon + "nix-daemon --store / & " + + // wait for socket to appear + "(while [ ! -S /nix/var/nix/daemon-socket/socket ]; do sleep 0.01; done) && " + + strings.Join(command, " && ") + + // terminate nix-daemon + " && pkill nix-daemon", }, Confinement: fst.ConfinementConfig{ AppID: bundle.AppID, - Username: "nixos", - Inner: path.Join("/data/data", bundle.ID, "cache"), - Outer: pathSet.cacheDir, // this also ensures cacheDir via fshim + Groups: bundle.Groups, + Username: "fortify", + Inner: path.Join("/data/data", bundle.ID), + Outer: pathSet.homeDir, Sandbox: &fst.SandboxConfig{ - Hostname: formatHostname(bundle.Name) + "-install", - NoNewSession: dropShellInstall, // nix copy should not need job control + Hostname: formatHostname(bundle.Name) + "-" + action, + UserNS: true, // nix sandbox requires userns + NoNewSession: dropShell, Filesystem: []*fst.FilesystemConfig{ - {Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true}, - {Src: workDir, Dst: path.Join(fst.Tmp, "bundle"), Must: true}, + {Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true}, }, Link: [][2]string{ {bundle.CurrentSystem, "/run/current-system"}, {"/run/current-system/sw/bin", "/bin"}, {"/run/current-system/sw/bin", "/usr/bin"}, }, - Etc: path.Join(workDir, "etc"), + Etc: path.Join(pathSet.cacheDir, "etc"), AutoEtc: true, }, ExtraPerms: []*fst.ExtraPermConfig{ @@ -157,47 +222,31 @@ func actionInstall(args []string) { {Path: workDir, Execute: true}, }, }, - } - - if dropShellInstall { - installConfig.Command = []string{shell, "-l"} - fortifyApp(installConfig, cleanup) - cleanup() - fmsg.Exit(0) - } - fortifyApp(installConfig, cleanup) - - /* - Activate home-manager generation. - */ + }, dropShell, beforeFail) +} - activateConfig := &fst.Config{ - ID: bundle.ID, - Command: []string{shell, "-lc", "mkdir -p .local/state/{nix,home-manager} && chmod -R +w .local/state/{nix,home-manager} && rm -rf .local/state/{nix,home-manager} && " + // clean up broken links - "nix-daemon --store / & " + // start nix-daemon - "(while [ ! -S /nix/var/nix/daemon-socket/socket ]; do sleep 0.01; done) && " + // wait for socket to appear - bundle.ActivationPackage + "/activate && " + // run activation script - "pkill nix-daemon", // terminate nix-daemon - }, +func withCacheDir(action string, command []string, workDir string, bundle *bundleInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) { + fortifyAppDropShell(&fst.Config{ + ID: bundle.ID, + Command: []string{shell, "-lc", strings.Join(command, " && ")}, Confinement: fst.ConfinementConfig{ AppID: bundle.AppID, - Groups: bundle.Groups, - Username: "fortify", - Inner: path.Join("/data/data", bundle.ID), - Outer: pathSet.homeDir, + Username: "nixos", + Inner: path.Join("/data/data", bundle.ID, "cache"), + Outer: pathSet.cacheDir, // this also ensures cacheDir via fshim Sandbox: &fst.SandboxConfig{ - Hostname: formatHostname(bundle.Name) + "-activate", - UserNS: true, // nix sandbox requires userns - NoNewSession: dropShellActivate, // home-manager activation should not need job control + Hostname: formatHostname(bundle.Name) + "-" + action, + NoNewSession: dropShell, Filesystem: []*fst.FilesystemConfig{ - {Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true}, + {Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true}, + {Src: workDir, Dst: path.Join(fst.Tmp, "bundle"), Must: true}, }, Link: [][2]string{ {bundle.CurrentSystem, "/run/current-system"}, {"/run/current-system/sw/bin", "/bin"}, {"/run/current-system/sw/bin", "/usr/bin"}, }, - Etc: path.Join(pathSet.cacheDir, "etc"), + Etc: path.Join(workDir, "etc"), AutoEtc: true, }, ExtraPerms: []*fst.ExtraPermConfig{ @@ -206,39 +255,15 @@ func actionInstall(args []string) { {Path: workDir, Execute: true}, }, }, - } + }, dropShell, beforeFail) +} - if dropShellActivate { - activateConfig.Command = []string{shell, "-l"} - fortifyApp(activateConfig, cleanup) - cleanup() +func fortifyAppDropShell(config *fst.Config, dropShell bool, beforeFail func()) { + if dropShell { + config.Command = []string{shell, "-l"} + fortifyApp(config, beforeFail) + beforeFail() fmsg.Exit(0) } - fortifyApp(activateConfig, cleanup) - - /* - Installation complete. Write metadata to block re-installs or downgrades. - */ - - // serialise metadata to ensure consistency - if f, err := os.OpenFile(pathSet.metaPath+"~", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644); err != nil { - cleanup() - fmsg.Fatalf("cannot create metadata file: %v", err) - panic("unreachable") - } else if err = json.NewEncoder(f).Encode(bundle); err != nil { - cleanup() - fmsg.Fatalf("cannot write metadata: %v", err) - panic("unreachable") - } else if err = f.Close(); err != nil { - fmsg.Printf("cannot close metadata file: %v", err) - // not fatal - } - - if err := os.Rename(pathSet.metaPath+"~", pathSet.metaPath); err != nil { - cleanup() - fmsg.Fatalf("cannot rename metadata file: %v", err) - panic("unreachable") - } - - cleanup() + fortifyApp(config, beforeFail) } |
