aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/fpkg/with.go
blob: 03718dd06d8218bcfed824b99beca3e1e88ef7f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main

import (
	"path"
	"strings"

	"git.gensokyo.uk/security/fortify/fst"
	"git.gensokyo.uk/security/fortify/helper/bwrap"
	"git.gensokyo.uk/security/fortify/internal/fmsg"
)

func withNixDaemon(
	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{
		ID: app.ID,
		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) && " +
			// create directory so nix stops complaining
			"mkdir -p /nix/var/nix/profiles/per-user/root/channels && " +
			strings.Join(command, " && ") +
			// terminate nix-daemon
			" && pkill nix-daemon",
		},
		Confinement: fst.ConfinementConfig{
			AppID:    app.AppID,
			Username: "fortify",
			Inner:    path.Join("/data/data", app.ID),
			Outer:    pathSet.homeDir,
			Sandbox: &fst.SandboxConfig{
				Hostname:     formatHostname(app.Name) + "-" + action,
				UserNS:       true, // nix sandbox requires userns
				Net:          net,
				Syscall:      &bwrap.SyscallPolicy{Multiarch: true},
				NoNewSession: dropShell,
				Filesystem: []*fst.FilesystemConfig{
					{Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true},
				},
				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},
			},
		},
	}), dropShell, beforeFail)
}

func withCacheDir(action string, command []string, workDir string, app *bundleInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) {
	fortifyAppDropShell(&fst.Config{
		ID:      app.ID,
		Command: []string{shell, "-lc", strings.Join(command, " && ")},
		Confinement: fst.ConfinementConfig{
			AppID:    app.AppID,
			Username: "nixos",
			Inner:    path.Join("/data/data", app.ID, "cache"),
			Outer:    pathSet.cacheDir, // this also ensures cacheDir via shim
			Sandbox: &fst.SandboxConfig{
				Hostname:     formatHostname(app.Name) + "-" + action,
				Syscall:      &bwrap.SyscallPolicy{Multiarch: true},
				NoNewSession: dropShell,
				Filesystem: []*fst.FilesystemConfig{
					{Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true},
					{Src: workDir, Dst: path.Join(fst.Tmp, "bundle"), Must: true},
				},
				Link: [][2]string{
					{app.CurrentSystem, "/run/current-system"},
					{"/run/current-system/sw/bin", "/bin"},
					{"/run/current-system/sw/bin", "/usr/bin"},
				},
				Etc:     path.Join(workDir, "etc"),
				AutoEtc: true,
			},
			ExtraPerms: []*fst.ExtraPermConfig{
				{Path: dataHome, Execute: true},
				{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
				{Path: workDir, Execute: true},
			},
		},
	}, dropShell, beforeFail)
}

func fortifyAppDropShell(config *fst.Config, dropShell bool, beforeFail func()) {
	if dropShell {
		config.Command = []string{shell, "-l"}
		fortifyApp(config, beforeFail)
		beforeFail()
		fmsg.Exit(0)
	}
	fortifyApp(config, beforeFail)
}