From e6cd2bb2a8098d555f11034fa912158c469e6138 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 23 Feb 2025 23:23:54 +0900 Subject: [PATCH] cmd/fpkg: integrate command handler Signed-off-by: Ophestra --- cmd/fpkg/install.go | 191 ----------------------- cmd/fpkg/main.go | 365 +++++++++++++++++++++++++++++++++++++++++--- cmd/fpkg/paths.go | 30 ++++ cmd/fpkg/start.go | 178 --------------------- 4 files changed, 371 insertions(+), 393 deletions(-) delete mode 100644 cmd/fpkg/install.go delete mode 100644 cmd/fpkg/start.go diff --git a/cmd/fpkg/install.go b/cmd/fpkg/install.go deleted file mode 100644 index d1643b4..0000000 --- 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 c9e68c2..ba0228f 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 init() { - flag.BoolVar(&flagVerbose, "v", false, "Verbose output") -} - func main() { - fmsg.Prepare("fpkg") + 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") - flag.Parse() - fmsg.Store(flagVerbose) + { + 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) + } + } - args := flag.Args() - if len(args) < 1 { - log.Fatal("invalid argument") + /* + 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 + } + + // 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 + } + + // 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 + } - default: - log.Fatal("invalid argument") + /* + 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. + */ + + 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 231388e..3d832d6 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 29f14b4..0000000 --- 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}, - }...) -}