aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-02-23 23:23:54 +0900
committerOphestra <cat@gensokyo.uk>2025-02-23 23:25:12 +0900
commite6cd2bb2a8098d555f11034fa912158c469e6138 (patch)
treefdb34784fdbebf870bc06f0d6456c08fa299c00f /cmd
parent0fb72e5d99226a1c67536f926ee2aeba25ca0fdd (diff)
cmd/fpkg: integrate command handler
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'cmd')
-rw-r--r--cmd/fpkg/install.go191
-rw-r--r--cmd/fpkg/main.go363
-rw-r--r--cmd/fpkg/paths.go30
-rw-r--r--cmd/fpkg/start.go178
4 files changed, 370 insertions, 392 deletions
diff --git a/cmd/fpkg/install.go b/cmd/fpkg/install.go
deleted file mode 100644
index d1643b40..00000000
--- a/cmd/fpkg/install.go
+++ /dev/null
@@ -1,191 +0,0 @@
-package main
-
-import (
- "encoding/json"
- "flag"
- "log"
- "os"
- "path"
-
- "git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/internal"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
-)
-
-func actionInstall(args []string) {
- set := flag.NewFlagSet("install", flag.ExitOnError)
- var (
- dropShellInstall bool
- dropShellActivate bool
- )
- set.BoolVar(&dropShellInstall, "si", false, "Drop to a shell on installation")
- set.BoolVar(&dropShellActivate, "sa", false, "Drop to a shell on activation")
-
- // Ignore errors; set is set for ExitOnError.
- _ = set.Parse(args)
-
- args = set.Args()
-
- if len(args) != 1 {
- log.Fatal("invalid argument")
- }
- pkgPath := args[0]
- if !path.IsAbs(pkgPath) {
- if dir, err := os.Getwd(); err != nil {
- log.Fatalf("cannot get current directory: %v", err)
- } else {
- pkgPath = path.Join(dir, pkgPath)
- }
- }
-
- /*
- Look up paths to programs started by fpkg.
- This is done here to ease error handling as cleanup is not yet required.
- */
-
- var (
- _ = lookPath("zstd")
- tar = lookPath("tar")
- chmod = lookPath("chmod")
- rm = lookPath("rm")
- )
-
- /*
- Extract package and set up for cleanup.
- */
-
- var workDir string
- if p, err := os.MkdirTemp("", "fpkg.*"); err != nil {
- log.Fatalf("cannot create temporary directory: %v", err)
- } else {
- workDir = p
- }
- cleanup := func() {
- // should be faster than a native implementation
- mustRun(chmod, "-R", "+w", workDir)
- mustRun(rm, "-rf", workDir)
- }
- beforeRunFail.Store(&cleanup)
-
- mustRun(tar, "-C", workDir, "-xf", pkgPath)
-
- /*
- Parse bundle and app metadata, do pre-install checks.
- */
-
- bundle := loadBundleInfo(path.Join(workDir, "bundle.json"), cleanup)
- pathSet := pathSetByApp(bundle.ID)
-
- app := bundle
- if s, err := os.Stat(pathSet.metaPath); err != nil {
- if !os.IsNotExist(err) {
- cleanup()
- log.Fatalf("cannot access %q: %v", pathSet.metaPath, err)
- }
- // did not modify app, clean installation condition met later
- } else if s.IsDir() {
- cleanup()
- log.Fatalf("metadata path %q is not a file", pathSet.metaPath)
- } else {
- app = loadBundleInfo(pathSet.metaPath, cleanup)
- if app.ID != bundle.ID {
- cleanup()
- log.Fatalf("app %q claims to have identifier %q", bundle.ID, app.ID)
- }
- // sec: should verify credentials
- }
-
- if app != bundle {
- // do not try to re-install
- if app.NixGL == bundle.NixGL &&
- app.CurrentSystem == bundle.CurrentSystem &&
- app.Launcher == bundle.Launcher &&
- app.ActivationPackage == bundle.ActivationPackage {
- cleanup()
- log.Printf("package %q is identical to local application %q", pkgPath, app.ID)
- internal.Exit(0)
- }
-
- // AppID determines uid
- if app.AppID != bundle.AppID {
- cleanup()
- log.Fatalf("package %q app id %d differs from installed %d", pkgPath, bundle.AppID, app.AppID)
- }
-
- // sec: should compare version string
- fmsg.Verbosef("installing application %q version %q over local %q", bundle.ID, bundle.Version, app.Version)
- } else {
- fmsg.Verbosef("application %q clean installation", bundle.ID)
- // sec: should install credentials
- }
-
- /*
- Setup steps for files owned by the target user.
- */
-
- 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",
- // deduplicate nix store
- "nix store --offline --store $PWD optimise",
- // make cache directory world-readable for autoetc
- "chmod 0755 .",
- }, workDir, bundle, pathSet, dropShellInstall, cleanup)
-
- if bundle.GPU {
- withCacheDir("mesa-wrappers", []string{
- // link nixGL mesa wrappers
- "mkdir -p nix/.nixGL",
- "ln -s " + bundle.Mesa + "/bin/nixGLIntel nix/.nixGL/nixGL",
- "ln -s " + bundle.Mesa + "/bin/nixVulkanIntel nix/.nixGL/nixVulkan",
- }, workDir, bundle, pathSet, false, 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",
- }, false, func(config *fst.Config) *fst.Config { return config }, 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()
- log.Fatalf("cannot create metadata file: %v", err)
- } else if err = json.NewEncoder(f).Encode(bundle); err != nil {
- cleanup()
- log.Fatalf("cannot write metadata: %v", err)
- } else if err = f.Close(); err != nil {
- log.Printf("cannot close metadata file: %v", err)
- // not fatal
- }
-
- if err := os.Rename(pathSet.metaPath+"~", pathSet.metaPath); err != nil {
- cleanup()
- log.Fatalf("cannot rename metadata file: %v", err)
- }
-
- cleanup()
-}
diff --git a/cmd/fpkg/main.go b/cmd/fpkg/main.go
index c9e68c28..ba0228f8 100644
--- a/cmd/fpkg/main.go
+++ b/cmd/fpkg/main.go
@@ -1,50 +1,367 @@
package main
import (
- "flag"
+ "encoding/json"
+ "errors"
"log"
"os"
+ "path"
+ "syscall"
- "git.gensokyo.uk/security/fortify/internal"
+ "git.gensokyo.uk/security/fortify/command"
+ "git.gensokyo.uk/security/fortify/fst"
+ "git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/internal/fmsg"
)
const shellPath = "/run/current-system/sw/bin/bash"
+var (
+ errSuccess = errors.New("success")
+)
+
func init() {
+ fmsg.Prepare("fpkg")
if err := os.Setenv("SHELL", shellPath); err != nil {
log.Fatalf("cannot set $SHELL: %v", err)
}
}
-var (
- flagVerbose bool
-)
+func main() {
+ var (
+ flagVerbose bool
+ flagDropShell bool
+ )
+ c := command.New(os.Stderr, log.Printf, "fpkg", func([]string) error { fmsg.Store(flagVerbose); 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")
-func init() {
- flag.BoolVar(&flagVerbose, "v", false, "Verbose output")
-}
+ {
+ var (
+ flagDropShellActivate bool
+ )
+ c.NewCommand("install", "Install an application from its package", func(args []string) error {
+ if len(args) != 1 {
+ log.Println("invalid argument")
+ return syscall.EINVAL
+ }
+ pkgPath := args[0]
+ if !path.IsAbs(pkgPath) {
+ if dir, err := os.Getwd(); err != nil {
+ log.Printf("cannot get current directory: %v", err)
+ return err
+ } else {
+ pkgPath = path.Join(dir, pkgPath)
+ }
+ }
-func main() {
- fmsg.Prepare("fpkg")
+ /*
+ Look up paths to programs started by fpkg.
+ This is done here to ease error handling as cleanup is not yet required.
+ */
+
+ var (
+ _ = lookPath("zstd")
+ tar = lookPath("tar")
+ chmod = lookPath("chmod")
+ rm = lookPath("rm")
+ )
+
+ /*
+ Extract package and set up for cleanup.
+ */
+
+ var workDir string
+ if p, err := os.MkdirTemp("", "fpkg.*"); err != nil {
+ log.Printf("cannot create temporary directory: %v", err)
+ return err
+ } else {
+ workDir = p
+ }
+ cleanup := func() {
+ // should be faster than a native implementation
+ mustRun(chmod, "-R", "+w", workDir)
+ mustRun(rm, "-rf", workDir)
+ }
+ beforeRunFail.Store(&cleanup)
+
+ mustRun(tar, "-C", workDir, "-xf", pkgPath)
+
+ /*
+ Parse bundle and app metadata, do pre-install checks.
+ */
+
+ bundle := loadBundleInfo(path.Join(workDir, "bundle.json"), cleanup)
+ pathSet := pathSetByApp(bundle.ID)
+
+ app := bundle
+ if s, err := os.Stat(pathSet.metaPath); err != nil {
+ if !os.IsNotExist(err) {
+ cleanup()
+ log.Printf("cannot access %q: %v", pathSet.metaPath, err)
+ return err
+ }
+ // did not modify app, clean installation condition met later
+ } else if s.IsDir() {
+ cleanup()
+ log.Printf("metadata path %q is not a file", pathSet.metaPath)
+ return syscall.EBADMSG
+ } else {
+ app = loadBundleInfo(pathSet.metaPath, cleanup)
+ if app.ID != bundle.ID {
+ cleanup()
+ log.Printf("app %q claims to have identifier %q",
+ bundle.ID, app.ID)
+ return syscall.EBADE
+ }
+ // sec: should verify credentials
+ }
+
+ if app != bundle {
+ // do not try to re-install
+ if app.NixGL == bundle.NixGL &&
+ app.CurrentSystem == bundle.CurrentSystem &&
+ app.Launcher == bundle.Launcher &&
+ app.ActivationPackage == bundle.ActivationPackage {
+ cleanup()
+ log.Printf("package %q is identical to local application %q",
+ pkgPath, app.ID)
+ return errSuccess
+ }
- flag.Parse()
- fmsg.Store(flagVerbose)
+ // AppID determines uid
+ if app.AppID != bundle.AppID {
+ cleanup()
+ log.Printf("package %q app id %d differs from installed %d",
+ pkgPath, bundle.AppID, app.AppID)
+ return syscall.EBADE
+ }
- args := flag.Args()
- if len(args) < 1 {
- log.Fatal("invalid argument")
+ // sec: should compare version string
+ fmsg.Verbosef("installing application %q version %q over local %q",
+ bundle.ID, bundle.Version, app.Version)
+ } else {
+ fmsg.Verbosef("application %q clean installation", bundle.ID)
+ // sec: should install credentials
+ }
+
+ /*
+ Setup steps for files owned by the target user.
+ */
+
+ 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",
+ // deduplicate nix store
+ "nix store --offline --store $PWD optimise",
+ // make cache directory world-readable for autoetc
+ "chmod 0755 .",
+ }, workDir, bundle, pathSet, flagDropShell, cleanup)
+
+ if bundle.GPU {
+ withCacheDir("mesa-wrappers", []string{
+ // link nixGL mesa wrappers
+ "mkdir -p nix/.nixGL",
+ "ln -s " + bundle.Mesa + "/bin/nixGLIntel nix/.nixGL/nixGL",
+ "ln -s " + bundle.Mesa + "/bin/nixVulkanIntel nix/.nixGL/nixVulkan",
+ }, workDir, bundle, pathSet, false, 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",
+ }, false, func(config *fst.Config) *fst.Config { return config },
+ bundle, pathSet, flagDropShellActivate, 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()
+ log.Printf("cannot create metadata file: %v", err)
+ return err
+ } else if err = json.NewEncoder(f).Encode(bundle); err != nil {
+ cleanup()
+ log.Printf("cannot write metadata: %v", err)
+ return err
+ } else if err = f.Close(); err != nil {
+ log.Printf("cannot close metadata file: %v", err)
+ // not fatal
+ }
+
+ if err := os.Rename(pathSet.metaPath+"~", pathSet.metaPath); err != nil {
+ cleanup()
+ log.Printf("cannot rename metadata file: %v", err)
+ return err
+ }
+
+ cleanup()
+ return errSuccess
+ }).
+ Flag(&flagDropShellActivate, "s", command.BoolFlag(false), "Drop to a shell on activation")
}
- switch args[0] {
- case "install":
- actionInstall(args[1:])
- case "start":
- actionStart(args[1:])
+ {
+ var (
+ flagDropShellNixGL bool
+ flagAutoDrivers bool
+ )
+ c.NewCommand("start", "Start an application", func(args []string) error {
+ if len(args) < 1 {
+ log.Println("invalid argument")
+ return syscall.EINVAL
+ }
+
+ /*
+ Parse app metadata.
+ */
+
+ id := args[0]
+ pathSet := pathSetByApp(id)
+ app := loadBundleInfo(pathSet.metaPath, func() {})
+ if app.ID != id {
+ log.Printf("app %q claims to have identifier %q", id, app.ID)
+ return syscall.EBADE
+ }
+
+ /*
+ Prepare nixGL.
+ */
+
+ if app.GPU && flagAutoDrivers {
+ withNixDaemon("nix-gl", []string{
+ "mkdir -p /nix/.nixGL/auto",
+ "rm -rf /nix/.nixGL/auto",
+ "export NIXPKGS_ALLOW_UNFREE=1",
+ "nix build --impure " +
+ "--out-link /nix/.nixGL/auto/opengl " +
+ "--override-input nixpkgs path:/etc/nixpkgs " +
+ "path:" + app.NixGL,
+ "nix build --impure " +
+ "--out-link /nix/.nixGL/auto/vulkan " +
+ "--override-input nixpkgs path:/etc/nixpkgs " +
+ "path:" + app.NixGL + "#nixVulkanNvidia",
+ }, true, func(config *fst.Config) *fst.Config {
+ config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem, []*fst.FilesystemConfig{
+ {Src: "/etc/resolv.conf"},
+ {Src: "/sys/block"},
+ {Src: "/sys/bus"},
+ {Src: "/sys/class"},
+ {Src: "/sys/dev"},
+ {Src: "/sys/devices"},
+ }...)
+ appendGPUFilesystem(config)
+ return config
+ }, app, pathSet, flagDropShellNixGL, func() {})
+ }
+
+ /*
+ Create app configuration.
+ */
+
+ argv := make([]string, 1, len(args))
+ if !flagDropShell {
+ argv[0] = app.Launcher
+ } else {
+ argv[0] = shellPath
+ }
+ argv = append(argv, args[1:]...)
+
+ config := &fst.Config{
+ ID: app.ID,
+ Command: argv,
+ Confinement: fst.ConfinementConfig{
+ AppID: app.AppID,
+ Groups: app.Groups,
+ Username: "fortify",
+ Inner: path.Join("/data/data", app.ID),
+ Outer: pathSet.homeDir,
+ Sandbox: &fst.SandboxConfig{
+ Hostname: formatHostname(app.Name),
+ UserNS: app.UserNS,
+ Net: app.Net,
+ Dev: app.Dev,
+ Syscall: &bwrap.SyscallPolicy{DenyDevel: !app.Devel, Multiarch: app.Multiarch, Bluetooth: app.Bluetooth},
+ NoNewSession: app.NoNewSession || flagDropShell,
+ MapRealUID: app.MapRealUID,
+ DirectWayland: app.DirectWayland,
+ Filesystem: []*fst.FilesystemConfig{
+ {Src: path.Join(pathSet.nixPath, "store"), Dst: "/nix/store", Must: true},
+ {Src: pathSet.metaPath, Dst: path.Join(fst.Tmp, "app"), Must: true},
+ {Src: "/etc/resolv.conf"},
+ {Src: "/sys/block"},
+ {Src: "/sys/bus"},
+ {Src: "/sys/class"},
+ {Src: "/sys/dev"},
+ {Src: "/sys/devices"},
+ },
+ Link: [][2]string{
+ {app.CurrentSystem, "/run/current-system"},
+ {"/run/current-system/sw/bin", "/bin"},
+ {"/run/current-system/sw/bin", "/usr/bin"},
+ },
+ Etc: path.Join(pathSet.cacheDir, "etc"),
+ AutoEtc: true,
+ },
+ ExtraPerms: []*fst.ExtraPermConfig{
+ {Path: dataHome, Execute: true},
+ {Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
+ },
+ SystemBus: app.SystemBus,
+ SessionBus: app.SessionBus,
+ Enablements: app.Enablements,
+ },
+ }
+
+ /*
+ Expose GPU devices.
+ */
+
+ if app.GPU {
+ config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem,
+ &fst.FilesystemConfig{Src: path.Join(pathSet.nixPath, ".nixGL"), Dst: path.Join(fst.Tmp, "nixGL")})
+ appendGPUFilesystem(config)
+ }
+
+ /*
+ Spawn app.
+ */
- default:
- log.Fatal("invalid argument")
+ fortifyApp(config, func() {})
+ return errSuccess
+ }).
+ Flag(&flagDropShellNixGL, "s", command.BoolFlag(false), "Drop to a shell on nixGL build").
+ Flag(&flagAutoDrivers, "auto-drivers", command.BoolFlag(false), "Attempt automatic opengl driver detection")
}
- internal.Exit(0)
+ c.MustParse(os.Args[1:], func(err error) {
+ fmsg.Verbosef("command returned %v", err)
+ if errors.Is(err, errSuccess) {
+ fmsg.BeforeExit()
+ os.Exit(0)
+ }
+ })
+ log.Fatal("unreachable")
}
diff --git a/cmd/fpkg/paths.go b/cmd/fpkg/paths.go
index 231388e5..3d832d65 100644
--- a/cmd/fpkg/paths.go
+++ b/cmd/fpkg/paths.go
@@ -8,6 +8,7 @@ import (
"strconv"
"sync/atomic"
+ "git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/fmsg"
)
@@ -69,3 +70,32 @@ func pathSetByApp(id string) *appPathSet {
pathSet.nixPath = path.Join(pathSet.cacheDir, "nix")
return pathSet
}
+
+func appendGPUFilesystem(config *fst.Config) {
+ config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem, []*fst.FilesystemConfig{
+ // flatpak commit 763a686d874dd668f0236f911de00b80766ffe79
+ {Src: "/dev/dri", Device: true},
+ // mali
+ {Src: "/dev/mali", Device: true},
+ {Src: "/dev/mali0", Device: true},
+ {Src: "/dev/umplock", Device: true},
+ // nvidia
+ {Src: "/dev/nvidiactl", Device: true},
+ {Src: "/dev/nvidia-modeset", Device: true},
+ // nvidia OpenCL/CUDA
+ {Src: "/dev/nvidia-uvm", Device: true},
+ {Src: "/dev/nvidia-uvm-tools", Device: true},
+
+ // flatpak commit d2dff2875bb3b7e2cd92d8204088d743fd07f3ff
+ {Src: "/dev/nvidia0", Device: true}, {Src: "/dev/nvidia1", Device: true},
+ {Src: "/dev/nvidia2", Device: true}, {Src: "/dev/nvidia3", Device: true},
+ {Src: "/dev/nvidia4", Device: true}, {Src: "/dev/nvidia5", Device: true},
+ {Src: "/dev/nvidia6", Device: true}, {Src: "/dev/nvidia7", Device: true},
+ {Src: "/dev/nvidia8", Device: true}, {Src: "/dev/nvidia9", Device: true},
+ {Src: "/dev/nvidia10", Device: true}, {Src: "/dev/nvidia11", Device: true},
+ {Src: "/dev/nvidia12", Device: true}, {Src: "/dev/nvidia13", Device: true},
+ {Src: "/dev/nvidia14", Device: true}, {Src: "/dev/nvidia15", Device: true},
+ {Src: "/dev/nvidia16", Device: true}, {Src: "/dev/nvidia17", Device: true},
+ {Src: "/dev/nvidia18", Device: true}, {Src: "/dev/nvidia19", Device: true},
+ }...)
+}
diff --git a/cmd/fpkg/start.go b/cmd/fpkg/start.go
deleted file mode 100644
index 29f14b4d..00000000
--- a/cmd/fpkg/start.go
+++ /dev/null
@@ -1,178 +0,0 @@
-package main
-
-import (
- "flag"
- "log"
- "path"
-
- "git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper/bwrap"
- "git.gensokyo.uk/security/fortify/internal"
-)
-
-func actionStart(args []string) {
- set := flag.NewFlagSet("start", flag.ExitOnError)
- var (
- dropShell bool
- dropShellNixGL bool
- autoDrivers bool
- )
- set.BoolVar(&dropShell, "s", false, "Drop to a shell")
- set.BoolVar(&dropShellNixGL, "sg", false, "Drop to a shell on nixGL build")
- set.BoolVar(&autoDrivers, "autodrivers", false, "Attempt automatic opengl driver detection")
-
- // Ignore errors; set is set for ExitOnError.
- _ = set.Parse(args)
-
- args = set.Args()
-
- if len(args) < 1 {
- log.Fatal("invalid argument")
- }
-
- /*
- Parse app metadata.
- */
-
- id := args[0]
- pathSet := pathSetByApp(id)
- app := loadBundleInfo(pathSet.metaPath, func() {})
- if app.ID != id {
- log.Fatalf("app %q claims to have identifier %q", id, app.ID)
- }
-
- /*
- Prepare nixGL.
- */
-
- if app.GPU && autoDrivers {
- withNixDaemon("nix-gl", []string{
- "mkdir -p /nix/.nixGL/auto",
- "rm -rf /nix/.nixGL/auto",
- "export NIXPKGS_ALLOW_UNFREE=1",
- "nix build --impure " +
- "--out-link /nix/.nixGL/auto/opengl " +
- "--override-input nixpkgs path:/etc/nixpkgs " +
- "path:" + app.NixGL,
- "nix build --impure " +
- "--out-link /nix/.nixGL/auto/vulkan " +
- "--override-input nixpkgs path:/etc/nixpkgs " +
- "path:" + app.NixGL + "#nixVulkanNvidia",
- }, true, func(config *fst.Config) *fst.Config {
- config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem, []*fst.FilesystemConfig{
- {Src: "/etc/resolv.conf"},
- {Src: "/sys/block"},
- {Src: "/sys/bus"},
- {Src: "/sys/class"},
- {Src: "/sys/dev"},
- {Src: "/sys/devices"},
- }...)
- appendGPUFilesystem(config)
- return config
- }, app, pathSet, dropShellNixGL, func() {})
- }
-
- /*
- Create app configuration.
- */
-
- command := make([]string, 1, len(args))
- if !dropShell {
- command[0] = app.Launcher
- } else {
- command[0] = shellPath
- }
- command = append(command, args[1:]...)
-
- config := &fst.Config{
- ID: app.ID,
- Command: command,
- Confinement: fst.ConfinementConfig{
- AppID: app.AppID,
- Groups: app.Groups,
- Username: "fortify",
- Inner: path.Join("/data/data", app.ID),
- Outer: pathSet.homeDir,
- Sandbox: &fst.SandboxConfig{
- Hostname: formatHostname(app.Name),
- UserNS: app.UserNS,
- Net: app.Net,
- Dev: app.Dev,
- Syscall: &bwrap.SyscallPolicy{DenyDevel: !app.Devel, Multiarch: app.Multiarch, Bluetooth: app.Bluetooth},
- NoNewSession: app.NoNewSession || dropShell,
- MapRealUID: app.MapRealUID,
- DirectWayland: app.DirectWayland,
- Filesystem: []*fst.FilesystemConfig{
- {Src: path.Join(pathSet.nixPath, "store"), Dst: "/nix/store", Must: true},
- {Src: pathSet.metaPath, Dst: path.Join(fst.Tmp, "app"), Must: true},
- {Src: "/etc/resolv.conf"},
- {Src: "/sys/block"},
- {Src: "/sys/bus"},
- {Src: "/sys/class"},
- {Src: "/sys/dev"},
- {Src: "/sys/devices"},
- },
- Link: [][2]string{
- {app.CurrentSystem, "/run/current-system"},
- {"/run/current-system/sw/bin", "/bin"},
- {"/run/current-system/sw/bin", "/usr/bin"},
- },
- Etc: path.Join(pathSet.cacheDir, "etc"),
- AutoEtc: true,
- },
- ExtraPerms: []*fst.ExtraPermConfig{
- {Path: dataHome, Execute: true},
- {Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
- },
- SystemBus: app.SystemBus,
- SessionBus: app.SessionBus,
- Enablements: app.Enablements,
- },
- }
-
- /*
- Expose GPU devices.
- */
-
- if app.GPU {
- config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem,
- &fst.FilesystemConfig{Src: path.Join(pathSet.nixPath, ".nixGL"), Dst: path.Join(fst.Tmp, "nixGL")})
- appendGPUFilesystem(config)
- }
-
- /*
- Spawn app.
- */
-
- fortifyApp(config, func() {})
- internal.Exit(0)
-}
-
-func appendGPUFilesystem(config *fst.Config) {
- config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem, []*fst.FilesystemConfig{
- // flatpak commit 763a686d874dd668f0236f911de00b80766ffe79
- {Src: "/dev/dri", Device: true},
- // mali
- {Src: "/dev/mali", Device: true},
- {Src: "/dev/mali0", Device: true},
- {Src: "/dev/umplock", Device: true},
- // nvidia
- {Src: "/dev/nvidiactl", Device: true},
- {Src: "/dev/nvidia-modeset", Device: true},
- // nvidia OpenCL/CUDA
- {Src: "/dev/nvidia-uvm", Device: true},
- {Src: "/dev/nvidia-uvm-tools", Device: true},
-
- // flatpak commit d2dff2875bb3b7e2cd92d8204088d743fd07f3ff
- {Src: "/dev/nvidia0", Device: true}, {Src: "/dev/nvidia1", Device: true},
- {Src: "/dev/nvidia2", Device: true}, {Src: "/dev/nvidia3", Device: true},
- {Src: "/dev/nvidia4", Device: true}, {Src: "/dev/nvidia5", Device: true},
- {Src: "/dev/nvidia6", Device: true}, {Src: "/dev/nvidia7", Device: true},
- {Src: "/dev/nvidia8", Device: true}, {Src: "/dev/nvidia9", Device: true},
- {Src: "/dev/nvidia10", Device: true}, {Src: "/dev/nvidia11", Device: true},
- {Src: "/dev/nvidia12", Device: true}, {Src: "/dev/nvidia13", Device: true},
- {Src: "/dev/nvidia14", Device: true}, {Src: "/dev/nvidia15", Device: true},
- {Src: "/dev/nvidia16", Device: true}, {Src: "/dev/nvidia17", Device: true},
- {Src: "/dev/nvidia18", Device: true}, {Src: "/dev/nvidia19", Device: true},
- }...)
-}