aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/app
diff options
context:
space:
mode:
Diffstat (limited to 'internal/app')
-rw-r--r--internal/app/app.go11
-rw-r--r--internal/app/app_nixos_test.go267
-rw-r--r--internal/app/app_pd_test.go516
-rw-r--r--internal/app/app_stub_test.go6
-rw-r--r--internal/app/app_test.go28
-rw-r--r--internal/app/export_test.go4
-rw-r--r--internal/app/init0/early.go18
-rw-r--r--internal/app/init0/main.go165
-rw-r--r--internal/app/init0/payload.go13
-rw-r--r--internal/app/process.go50
-rw-r--r--internal/app/seal.go181
-rw-r--r--internal/app/shim/main.go129
-rw-r--r--internal/app/shim/payload.go23
-rw-r--r--internal/app/shim/proc.go (renamed from internal/app/shim/manager.go)35
14 files changed, 581 insertions, 865 deletions
diff --git a/internal/app/app.go b/internal/app/app.go
index c4668a08..42d67b96 100644
--- a/internal/app/app.go
+++ b/internal/app/app.go
@@ -1,6 +1,7 @@
package app
import (
+ "context"
"fmt"
"log"
"sync"
@@ -10,9 +11,10 @@ import (
"git.gensokyo.uk/security/fortify/internal/sys"
)
-func New(os sys.State) (fst.App, error) {
+func New(ctx context.Context, os sys.State) (fst.App, error) {
a := new(app)
a.sys = os
+ a.ctx = ctx
id := new(fst.ID)
err := fst.NewAppID(id)
@@ -21,8 +23,8 @@ func New(os sys.State) (fst.App, error) {
return a, err
}
-func MustNew(os sys.State) fst.App {
- a, err := New(os)
+func MustNew(ctx context.Context, os sys.State) fst.App {
+ a, err := New(ctx, os)
if err != nil {
log.Fatalf("cannot create app: %v", err)
}
@@ -32,6 +34,7 @@ func MustNew(os sys.State) fst.App {
type app struct {
id *stringPair[fst.ID]
sys sys.State
+ ctx context.Context
*outcome
mu sync.RWMutex
@@ -71,7 +74,7 @@ func (a *app) Seal(config *fst.Config) (fst.SealedApp, error) {
seal := new(outcome)
seal.id = a.id
- err := seal.finalise(a.sys, config)
+ err := seal.finalise(a.ctx, a.sys, config)
if err == nil {
a.outcome = seal
}
diff --git a/internal/app/app_nixos_test.go b/internal/app/app_nixos_test.go
index 683b179a..ca9fde08 100644
--- a/internal/app/app_nixos_test.go
+++ b/internal/app/app_nixos_test.go
@@ -4,7 +4,7 @@ import (
"git.gensokyo.uk/security/fortify/acl"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper/bwrap"
+ "git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
)
@@ -12,20 +12,20 @@ var testCasesNixos = []sealTestCase{
{
"nixos chromium direct wayland", new(stubNixOS),
&fst.Config{
- ID: "org.chromium.Chromium",
- Command: []string{"/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"},
+ ID: "org.chromium.Chromium",
+ Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
Confinement: fst.ConfinementConfig{
AppID: 1, Groups: []string{}, Username: "u0_a1",
Outer: "/var/lib/persist/module/fortify/0/1",
Sandbox: &fst.SandboxConfig{
- UserNS: true, Net: true, MapRealUID: true, DirectWayland: true, Env: nil, AutoEtc: true,
+ Userns: true, Net: true, MapRealUID: true, DirectWayland: true, Env: nil, AutoEtc: true,
Filesystem: []*fst.FilesystemConfig{
{Src: "/bin", Must: true}, {Src: "/usr/bin", Must: true},
{Src: "/nix/store", Must: true}, {Src: "/run/current-system", Must: true},
{Src: "/sys/block"}, {Src: "/sys/bus"}, {Src: "/sys/class"}, {Src: "/sys/dev"}, {Src: "/sys/devices"},
{Src: "/run/opengl-driver", Must: true}, {Src: "/dev/dri", Device: true},
},
- Override: []string{"/var/run/nscd"},
+ Cover: []string{"/var/run/nscd"},
},
SystemBus: &dbus.Config{
Talk: []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"},
@@ -88,136 +88,133 @@ var testCasesNixos = []sealTestCase{
}).
UpdatePerm("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", acl.Read, acl.Write).
UpdatePerm("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", acl.Read, acl.Write),
- (&bwrap.Config{
- Net: true,
- UserNS: true,
- Chdir: "/var/lib/persist/module/fortify/0/1",
- Clearenv: true,
- SetEnv: map[string]string{
- "DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/1971/bus",
- "DBUS_SYSTEM_BUS_ADDRESS": "unix:path=/run/dbus/system_bus_socket",
- "HOME": "/var/lib/persist/module/fortify/0/1",
- "PULSE_COOKIE": fst.Tmp + "/pulse-cookie",
- "PULSE_SERVER": "unix:/run/user/1971/pulse/native",
- "SHELL": "/run/current-system/sw/bin/zsh",
- "TERM": "xterm-256color",
- "USER": "u0_a1",
- "WAYLAND_DISPLAY": "wayland-0",
- "XDG_RUNTIME_DIR": "/run/user/1971",
- "XDG_SESSION_CLASS": "user",
- "XDG_SESSION_TYPE": "tty",
+ &sandbox.Params{
+ Uid: 1971,
+ Gid: 100,
+ Flags: sandbox.FAllowNet | sandbox.FAllowUserns,
+ Dir: "/var/lib/persist/module/fortify/0/1",
+ Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
+ Args: []string{"/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"},
+ Env: []string{
+ "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1971/bus",
+ "DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
+ "HOME=/var/lib/persist/module/fortify/0/1",
+ "PULSE_COOKIE=" + fst.Tmp + "/pulse-cookie",
+ "PULSE_SERVER=unix:/run/user/1971/pulse/native",
+ "TERM=xterm-256color",
+ "USER=u0_a1",
+ "WAYLAND_DISPLAY=wayland-0",
+ "XDG_RUNTIME_DIR=/run/user/1971",
+ "XDG_SESSION_CLASS=user",
+ "XDG_SESSION_TYPE=tty",
},
- Chmod: make(bwrap.ChmodConfig),
- NewSession: true,
- DieWithParent: true,
- AsInit: true,
- }).SetUID(1971).SetGID(1971).
- Procfs("/proc").
- Tmpfs(fst.Tmp, 4096).
- DevTmpfs("/dev").Mqueue("/dev/mqueue").
- Bind("/bin", "/bin").
- Bind("/usr/bin", "/usr/bin").
- Bind("/nix/store", "/nix/store").
- Bind("/run/current-system", "/run/current-system").
- Bind("/sys/block", "/sys/block", true).
- Bind("/sys/bus", "/sys/bus", true).
- Bind("/sys/class", "/sys/class", true).
- Bind("/sys/dev", "/sys/dev", true).
- Bind("/sys/devices", "/sys/devices", true).
- Bind("/run/opengl-driver", "/run/opengl-driver").
- Bind("/dev/dri", "/dev/dri", true, true, true).
- Bind("/etc", fst.Tmp+"/etc").
- Symlink(fst.Tmp+"/etc/alsa", "/etc/alsa").
- Symlink(fst.Tmp+"/etc/bashrc", "/etc/bashrc").
- Symlink(fst.Tmp+"/etc/binfmt.d", "/etc/binfmt.d").
- Symlink(fst.Tmp+"/etc/dbus-1", "/etc/dbus-1").
- Symlink(fst.Tmp+"/etc/default", "/etc/default").
- Symlink(fst.Tmp+"/etc/ethertypes", "/etc/ethertypes").
- Symlink(fst.Tmp+"/etc/fonts", "/etc/fonts").
- Symlink(fst.Tmp+"/etc/fstab", "/etc/fstab").
- Symlink(fst.Tmp+"/etc/fuse.conf", "/etc/fuse.conf").
- Symlink(fst.Tmp+"/etc/host.conf", "/etc/host.conf").
- Symlink(fst.Tmp+"/etc/hostid", "/etc/hostid").
- Symlink(fst.Tmp+"/etc/hostname", "/etc/hostname").
- Symlink(fst.Tmp+"/etc/hostname.CHECKSUM", "/etc/hostname.CHECKSUM").
- Symlink(fst.Tmp+"/etc/hosts", "/etc/hosts").
- Symlink(fst.Tmp+"/etc/inputrc", "/etc/inputrc").
- Symlink(fst.Tmp+"/etc/ipsec.d", "/etc/ipsec.d").
- Symlink(fst.Tmp+"/etc/issue", "/etc/issue").
- Symlink(fst.Tmp+"/etc/kbd", "/etc/kbd").
- Symlink(fst.Tmp+"/etc/libblockdev", "/etc/libblockdev").
- Symlink(fst.Tmp+"/etc/locale.conf", "/etc/locale.conf").
- Symlink(fst.Tmp+"/etc/localtime", "/etc/localtime").
- Symlink(fst.Tmp+"/etc/login.defs", "/etc/login.defs").
- Symlink(fst.Tmp+"/etc/lsb-release", "/etc/lsb-release").
- Symlink(fst.Tmp+"/etc/lvm", "/etc/lvm").
- Symlink(fst.Tmp+"/etc/machine-id", "/etc/machine-id").
- Symlink(fst.Tmp+"/etc/man_db.conf", "/etc/man_db.conf").
- Symlink(fst.Tmp+"/etc/modprobe.d", "/etc/modprobe.d").
- Symlink(fst.Tmp+"/etc/modules-load.d", "/etc/modules-load.d").
- Symlink("/proc/mounts", "/etc/mtab").
- Symlink(fst.Tmp+"/etc/nanorc", "/etc/nanorc").
- Symlink(fst.Tmp+"/etc/netgroup", "/etc/netgroup").
- Symlink(fst.Tmp+"/etc/NetworkManager", "/etc/NetworkManager").
- Symlink(fst.Tmp+"/etc/nix", "/etc/nix").
- Symlink(fst.Tmp+"/etc/nixos", "/etc/nixos").
- Symlink(fst.Tmp+"/etc/NIXOS", "/etc/NIXOS").
- Symlink(fst.Tmp+"/etc/nscd.conf", "/etc/nscd.conf").
- Symlink(fst.Tmp+"/etc/nsswitch.conf", "/etc/nsswitch.conf").
- Symlink(fst.Tmp+"/etc/opensnitchd", "/etc/opensnitchd").
- Symlink(fst.Tmp+"/etc/os-release", "/etc/os-release").
- Symlink(fst.Tmp+"/etc/pam", "/etc/pam").
- Symlink(fst.Tmp+"/etc/pam.d", "/etc/pam.d").
- Symlink(fst.Tmp+"/etc/pipewire", "/etc/pipewire").
- Symlink(fst.Tmp+"/etc/pki", "/etc/pki").
- Symlink(fst.Tmp+"/etc/polkit-1", "/etc/polkit-1").
- Symlink(fst.Tmp+"/etc/profile", "/etc/profile").
- Symlink(fst.Tmp+"/etc/protocols", "/etc/protocols").
- Symlink(fst.Tmp+"/etc/qemu", "/etc/qemu").
- Symlink(fst.Tmp+"/etc/resolv.conf", "/etc/resolv.conf").
- Symlink(fst.Tmp+"/etc/resolvconf.conf", "/etc/resolvconf.conf").
- Symlink(fst.Tmp+"/etc/rpc", "/etc/rpc").
- Symlink(fst.Tmp+"/etc/samba", "/etc/samba").
- Symlink(fst.Tmp+"/etc/sddm.conf", "/etc/sddm.conf").
- Symlink(fst.Tmp+"/etc/secureboot", "/etc/secureboot").
- Symlink(fst.Tmp+"/etc/services", "/etc/services").
- Symlink(fst.Tmp+"/etc/set-environment", "/etc/set-environment").
- Symlink(fst.Tmp+"/etc/shadow", "/etc/shadow").
- Symlink(fst.Tmp+"/etc/shells", "/etc/shells").
- Symlink(fst.Tmp+"/etc/ssh", "/etc/ssh").
- Symlink(fst.Tmp+"/etc/ssl", "/etc/ssl").
- Symlink(fst.Tmp+"/etc/static", "/etc/static").
- Symlink(fst.Tmp+"/etc/subgid", "/etc/subgid").
- Symlink(fst.Tmp+"/etc/subuid", "/etc/subuid").
- Symlink(fst.Tmp+"/etc/sudoers", "/etc/sudoers").
- Symlink(fst.Tmp+"/etc/sysctl.d", "/etc/sysctl.d").
- Symlink(fst.Tmp+"/etc/systemd", "/etc/systemd").
- Symlink(fst.Tmp+"/etc/terminfo", "/etc/terminfo").
- Symlink(fst.Tmp+"/etc/tmpfiles.d", "/etc/tmpfiles.d").
- Symlink(fst.Tmp+"/etc/udev", "/etc/udev").
- Symlink(fst.Tmp+"/etc/udisks2", "/etc/udisks2").
- Symlink(fst.Tmp+"/etc/UPower", "/etc/UPower").
- Symlink(fst.Tmp+"/etc/vconsole.conf", "/etc/vconsole.conf").
- Symlink(fst.Tmp+"/etc/X11", "/etc/X11").
- Symlink(fst.Tmp+"/etc/zfs", "/etc/zfs").
- Symlink(fst.Tmp+"/etc/zinputrc", "/etc/zinputrc").
- Symlink(fst.Tmp+"/etc/zoneinfo", "/etc/zoneinfo").
- Symlink(fst.Tmp+"/etc/zprofile", "/etc/zprofile").
- Symlink(fst.Tmp+"/etc/zshenv", "/etc/zshenv").
- Symlink(fst.Tmp+"/etc/zshrc", "/etc/zshrc").
- Tmpfs("/run/user", 1048576).
- Tmpfs("/run/user/1971", 8388608).
- Bind("/tmp/fortify.1971/tmpdir/1", "/tmp", false, true).
- Bind("/var/lib/persist/module/fortify/0/1", "/var/lib/persist/module/fortify/0/1", false, true).
- CopyBind("/etc/passwd", []byte("u0_a1:x:1971:1971:Fortify:/var/lib/persist/module/fortify/0/1:/run/current-system/sw/bin/zsh\n")).
- CopyBind("/etc/group", []byte("fortify:x:1971:\n")).
- Bind("/run/user/1971/wayland-0", "/run/user/1971/wayland-0").
- Bind("/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1/pulse", "/run/user/1971/pulse/native").
- CopyBind(fst.Tmp+"/pulse-cookie", nil).
- Bind("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", "/run/user/1971/bus").
- Bind("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", "/run/dbus/system_bus_socket").
- Tmpfs("/var/run/nscd", 8192).
- Bind("/run/wrappers/bin/fortify", "/.fortify/sbin/fortify").
- Symlink("fortify", "/.fortify/sbin/init0"),
+ Ops: new(sandbox.Ops).
+ Proc("/proc").
+ Tmpfs(fst.Tmp, 4096, 0755).
+ Dev("/dev").Mqueue("/dev/mqueue").
+ Bind("/bin", "/bin", 0).
+ Bind("/usr/bin", "/usr/bin", 0).
+ Bind("/nix/store", "/nix/store", 0).
+ Bind("/run/current-system", "/run/current-system", 0).
+ Bind("/sys/block", "/sys/block", sandbox.BindOptional).
+ Bind("/sys/bus", "/sys/bus", sandbox.BindOptional).
+ Bind("/sys/class", "/sys/class", sandbox.BindOptional).
+ Bind("/sys/dev", "/sys/dev", sandbox.BindOptional).
+ Bind("/sys/devices", "/sys/devices", sandbox.BindOptional).
+ Bind("/run/opengl-driver", "/run/opengl-driver", 0).
+ Bind("/dev/dri", "/dev/dri", sandbox.BindDevice|sandbox.BindWritable|sandbox.BindOptional).
+ Bind("/etc", fst.Tmp+"/etc", 0).
+ Mkdir("/etc", 0700).
+ Link(fst.Tmp+"/etc/alsa", "/etc/alsa").
+ Link(fst.Tmp+"/etc/bashrc", "/etc/bashrc").
+ Link(fst.Tmp+"/etc/binfmt.d", "/etc/binfmt.d").
+ Link(fst.Tmp+"/etc/dbus-1", "/etc/dbus-1").
+ Link(fst.Tmp+"/etc/default", "/etc/default").
+ Link(fst.Tmp+"/etc/ethertypes", "/etc/ethertypes").
+ Link(fst.Tmp+"/etc/fonts", "/etc/fonts").
+ Link(fst.Tmp+"/etc/fstab", "/etc/fstab").
+ Link(fst.Tmp+"/etc/fuse.conf", "/etc/fuse.conf").
+ Link(fst.Tmp+"/etc/host.conf", "/etc/host.conf").
+ Link(fst.Tmp+"/etc/hostid", "/etc/hostid").
+ Link(fst.Tmp+"/etc/hostname", "/etc/hostname").
+ Link(fst.Tmp+"/etc/hostname.CHECKSUM", "/etc/hostname.CHECKSUM").
+ Link(fst.Tmp+"/etc/hosts", "/etc/hosts").
+ Link(fst.Tmp+"/etc/inputrc", "/etc/inputrc").
+ Link(fst.Tmp+"/etc/ipsec.d", "/etc/ipsec.d").
+ Link(fst.Tmp+"/etc/issue", "/etc/issue").
+ Link(fst.Tmp+"/etc/kbd", "/etc/kbd").
+ Link(fst.Tmp+"/etc/libblockdev", "/etc/libblockdev").
+ Link(fst.Tmp+"/etc/locale.conf", "/etc/locale.conf").
+ Link(fst.Tmp+"/etc/localtime", "/etc/localtime").
+ Link(fst.Tmp+"/etc/login.defs", "/etc/login.defs").
+ Link(fst.Tmp+"/etc/lsb-release", "/etc/lsb-release").
+ Link(fst.Tmp+"/etc/lvm", "/etc/lvm").
+ Link(fst.Tmp+"/etc/machine-id", "/etc/machine-id").
+ Link(fst.Tmp+"/etc/man_db.conf", "/etc/man_db.conf").
+ Link(fst.Tmp+"/etc/modprobe.d", "/etc/modprobe.d").
+ Link(fst.Tmp+"/etc/modules-load.d", "/etc/modules-load.d").
+ Link("/proc/mounts", "/etc/mtab").
+ Link(fst.Tmp+"/etc/nanorc", "/etc/nanorc").
+ Link(fst.Tmp+"/etc/netgroup", "/etc/netgroup").
+ Link(fst.Tmp+"/etc/NetworkManager", "/etc/NetworkManager").
+ Link(fst.Tmp+"/etc/nix", "/etc/nix").
+ Link(fst.Tmp+"/etc/nixos", "/etc/nixos").
+ Link(fst.Tmp+"/etc/NIXOS", "/etc/NIXOS").
+ Link(fst.Tmp+"/etc/nscd.conf", "/etc/nscd.conf").
+ Link(fst.Tmp+"/etc/nsswitch.conf", "/etc/nsswitch.conf").
+ Link(fst.Tmp+"/etc/opensnitchd", "/etc/opensnitchd").
+ Link(fst.Tmp+"/etc/os-release", "/etc/os-release").
+ Link(fst.Tmp+"/etc/pam", "/etc/pam").
+ Link(fst.Tmp+"/etc/pam.d", "/etc/pam.d").
+ Link(fst.Tmp+"/etc/pipewire", "/etc/pipewire").
+ Link(fst.Tmp+"/etc/pki", "/etc/pki").
+ Link(fst.Tmp+"/etc/polkit-1", "/etc/polkit-1").
+ Link(fst.Tmp+"/etc/profile", "/etc/profile").
+ Link(fst.Tmp+"/etc/protocols", "/etc/protocols").
+ Link(fst.Tmp+"/etc/qemu", "/etc/qemu").
+ Link(fst.Tmp+"/etc/resolv.conf", "/etc/resolv.conf").
+ Link(fst.Tmp+"/etc/resolvconf.conf", "/etc/resolvconf.conf").
+ Link(fst.Tmp+"/etc/rpc", "/etc/rpc").
+ Link(fst.Tmp+"/etc/samba", "/etc/samba").
+ Link(fst.Tmp+"/etc/sddm.conf", "/etc/sddm.conf").
+ Link(fst.Tmp+"/etc/secureboot", "/etc/secureboot").
+ Link(fst.Tmp+"/etc/services", "/etc/services").
+ Link(fst.Tmp+"/etc/set-environment", "/etc/set-environment").
+ Link(fst.Tmp+"/etc/shadow", "/etc/shadow").
+ Link(fst.Tmp+"/etc/shells", "/etc/shells").
+ Link(fst.Tmp+"/etc/ssh", "/etc/ssh").
+ Link(fst.Tmp+"/etc/ssl", "/etc/ssl").
+ Link(fst.Tmp+"/etc/static", "/etc/static").
+ Link(fst.Tmp+"/etc/subgid", "/etc/subgid").
+ Link(fst.Tmp+"/etc/subuid", "/etc/subuid").
+ Link(fst.Tmp+"/etc/sudoers", "/etc/sudoers").
+ Link(fst.Tmp+"/etc/sysctl.d", "/etc/sysctl.d").
+ Link(fst.Tmp+"/etc/systemd", "/etc/systemd").
+ Link(fst.Tmp+"/etc/terminfo", "/etc/terminfo").
+ Link(fst.Tmp+"/etc/tmpfiles.d", "/etc/tmpfiles.d").
+ Link(fst.Tmp+"/etc/udev", "/etc/udev").
+ Link(fst.Tmp+"/etc/udisks2", "/etc/udisks2").
+ Link(fst.Tmp+"/etc/UPower", "/etc/UPower").
+ Link(fst.Tmp+"/etc/vconsole.conf", "/etc/vconsole.conf").
+ Link(fst.Tmp+"/etc/X11", "/etc/X11").
+ Link(fst.Tmp+"/etc/zfs", "/etc/zfs").
+ Link(fst.Tmp+"/etc/zinputrc", "/etc/zinputrc").
+ Link(fst.Tmp+"/etc/zoneinfo", "/etc/zoneinfo").
+ Link(fst.Tmp+"/etc/zprofile", "/etc/zprofile").
+ Link(fst.Tmp+"/etc/zshenv", "/etc/zshenv").
+ Link(fst.Tmp+"/etc/zshrc", "/etc/zshrc").
+ Tmpfs("/run/user", 4096, 0755).
+ Tmpfs("/run/user/1971", 8388608, 0755).
+ Bind("/tmp/fortify.1971/tmpdir/1", "/tmp", sandbox.BindWritable).
+ Bind("/var/lib/persist/module/fortify/0/1", "/var/lib/persist/module/fortify/0/1", sandbox.BindWritable).
+ Place("/etc/passwd", []byte("u0_a1:x:1971:100:Fortify:/var/lib/persist/module/fortify/0/1:/run/current-system/sw/bin/zsh\n")).
+ Place("/etc/group", []byte("fortify:x:100:\n")).
+ Bind("/run/user/1971/wayland-0", "/run/user/1971/wayland-0", 0).
+ Bind("/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1/pulse", "/run/user/1971/pulse/native", 0).
+ Place(fst.Tmp+"/pulse-cookie", nil).
+ Bind("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", "/run/user/1971/bus", 0).
+ Bind("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", "/run/dbus/system_bus_socket", 0).
+ Tmpfs("/var/run/nscd", 8192, 0755),
+ },
},
}
diff --git a/internal/app/app_pd_test.go b/internal/app/app_pd_test.go
index 602965ce..15355797 100644
--- a/internal/app/app_pd_test.go
+++ b/internal/app/app_pd_test.go
@@ -6,7 +6,7 @@ import (
"git.gensokyo.uk/security/fortify/acl"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper/bwrap"
+ "git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
)
@@ -14,7 +14,6 @@ var testCasesPd = []sealTestCase{
{
"nixos permissive defaults no enablements", new(stubNixOS),
&fst.Config{
- Command: make([]string, 0),
Confinement: fst.ConfinementConfig{
AppID: 0,
Username: "chronos",
@@ -35,136 +34,132 @@ var testCasesPd = []sealTestCase{
Ephemeral(system.Process, "/run/user/1971/fortify/4a450b6596d7bc15bd01780eb9a607ac", 0700).UpdatePermType(system.Process, "/run/user/1971/fortify/4a450b6596d7bc15bd01780eb9a607ac", acl.Execute).
Ensure("/tmp/fortify.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir", acl.Execute).
Ensure("/tmp/fortify.1971/tmpdir/0", 01700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir/0", acl.Read, acl.Write, acl.Execute),
- (&bwrap.Config{
- Net: true,
- UserNS: true,
- Clearenv: true,
- Syscall: new(bwrap.SyscallPolicy),
- Chdir: "/home/chronos",
- SetEnv: map[string]string{
- "HOME": "/home/chronos",
- "SHELL": "/run/current-system/sw/bin/zsh",
- "TERM": "xterm-256color",
- "USER": "chronos",
- "XDG_RUNTIME_DIR": "/run/user/65534",
- "XDG_SESSION_CLASS": "user",
- "XDG_SESSION_TYPE": "tty"},
- Chmod: make(bwrap.ChmodConfig),
- DieWithParent: true,
- AsInit: true,
- }).SetUID(65534).SetGID(65534).
- Procfs("/proc").
- Tmpfs(fst.Tmp, 4096).
- DevTmpfs("/dev").Mqueue("/dev/mqueue").
- Bind("/bin", "/bin", false, true).
- Bind("/boot", "/boot", false, true).
- Bind("/home", "/home", false, true).
- Bind("/lib", "/lib", false, true).
- Bind("/lib64", "/lib64", false, true).
- Bind("/nix", "/nix", false, true).
- Bind("/root", "/root", false, true).
- Bind("/run", "/run", false, true).
- Bind("/srv", "/srv", false, true).
- Bind("/sys", "/sys", false, true).
- Bind("/usr", "/usr", false, true).
- Bind("/var", "/var", false, true).
- Bind("/dev/kvm", "/dev/kvm", true, true, true).
- Tmpfs("/run/user/1971", 8192).
- Tmpfs("/run/dbus", 8192).
- Bind("/etc", fst.Tmp+"/etc").
- Symlink(fst.Tmp+"/etc/alsa", "/etc/alsa").
- Symlink(fst.Tmp+"/etc/bashrc", "/etc/bashrc").
- Symlink(fst.Tmp+"/etc/binfmt.d", "/etc/binfmt.d").
- Symlink(fst.Tmp+"/etc/dbus-1", "/etc/dbus-1").
- Symlink(fst.Tmp+"/etc/default", "/etc/default").
- Symlink(fst.Tmp+"/etc/ethertypes", "/etc/ethertypes").
- Symlink(fst.Tmp+"/etc/fonts", "/etc/fonts").
- Symlink(fst.Tmp+"/etc/fstab", "/etc/fstab").
- Symlink(fst.Tmp+"/etc/fuse.conf", "/etc/fuse.conf").
- Symlink(fst.Tmp+"/etc/host.conf", "/etc/host.conf").
- Symlink(fst.Tmp+"/etc/hostid", "/etc/hostid").
- Symlink(fst.Tmp+"/etc/hostname", "/etc/hostname").
- Symlink(fst.Tmp+"/etc/hostname.CHECKSUM", "/etc/hostname.CHECKSUM").
- Symlink(fst.Tmp+"/etc/hosts", "/etc/hosts").
- Symlink(fst.Tmp+"/etc/inputrc", "/etc/inputrc").
- Symlink(fst.Tmp+"/etc/ipsec.d", "/etc/ipsec.d").
- Symlink(fst.Tmp+"/etc/issue", "/etc/issue").
- Symlink(fst.Tmp+"/etc/kbd", "/etc/kbd").
- Symlink(fst.Tmp+"/etc/libblockdev", "/etc/libblockdev").
- Symlink(fst.Tmp+"/etc/locale.conf", "/etc/locale.conf").
- Symlink(fst.Tmp+"/etc/localtime", "/etc/localtime").
- Symlink(fst.Tmp+"/etc/login.defs", "/etc/login.defs").
- Symlink(fst.Tmp+"/etc/lsb-release", "/etc/lsb-release").
- Symlink(fst.Tmp+"/etc/lvm", "/etc/lvm").
- Symlink(fst.Tmp+"/etc/machine-id", "/etc/machine-id").
- Symlink(fst.Tmp+"/etc/man_db.conf", "/etc/man_db.conf").
- Symlink(fst.Tmp+"/etc/modprobe.d", "/etc/modprobe.d").
- Symlink(fst.Tmp+"/etc/modules-load.d", "/etc/modules-load.d").
- Symlink("/proc/mounts", "/etc/mtab").
- Symlink(fst.Tmp+"/etc/nanorc", "/etc/nanorc").
- Symlink(fst.Tmp+"/etc/netgroup", "/etc/netgroup").
- Symlink(fst.Tmp+"/etc/NetworkManager", "/etc/NetworkManager").
- Symlink(fst.Tmp+"/etc/nix", "/etc/nix").
- Symlink(fst.Tmp+"/etc/nixos", "/etc/nixos").
- Symlink(fst.Tmp+"/etc/NIXOS", "/etc/NIXOS").
- Symlink(fst.Tmp+"/etc/nscd.conf", "/etc/nscd.conf").
- Symlink(fst.Tmp+"/etc/nsswitch.conf", "/etc/nsswitch.conf").
- Symlink(fst.Tmp+"/etc/opensnitchd", "/etc/opensnitchd").
- Symlink(fst.Tmp+"/etc/os-release", "/etc/os-release").
- Symlink(fst.Tmp+"/etc/pam", "/etc/pam").
- Symlink(fst.Tmp+"/etc/pam.d", "/etc/pam.d").
- Symlink(fst.Tmp+"/etc/pipewire", "/etc/pipewire").
- Symlink(fst.Tmp+"/etc/pki", "/etc/pki").
- Symlink(fst.Tmp+"/etc/polkit-1", "/etc/polkit-1").
- Symlink(fst.Tmp+"/etc/profile", "/etc/profile").
- Symlink(fst.Tmp+"/etc/protocols", "/etc/protocols").
- Symlink(fst.Tmp+"/etc/qemu", "/etc/qemu").
- Symlink(fst.Tmp+"/etc/resolv.conf", "/etc/resolv.conf").
- Symlink(fst.Tmp+"/etc/resolvconf.conf", "/etc/resolvconf.conf").
- Symlink(fst.Tmp+"/etc/rpc", "/etc/rpc").
- Symlink(fst.Tmp+"/etc/samba", "/etc/samba").
- Symlink(fst.Tmp+"/etc/sddm.conf", "/etc/sddm.conf").
- Symlink(fst.Tmp+"/etc/secureboot", "/etc/secureboot").
- Symlink(fst.Tmp+"/etc/services", "/etc/services").
- Symlink(fst.Tmp+"/etc/set-environment", "/etc/set-environment").
- Symlink(fst.Tmp+"/etc/shadow", "/etc/shadow").
- Symlink(fst.Tmp+"/etc/shells", "/etc/shells").
- Symlink(fst.Tmp+"/etc/ssh", "/etc/ssh").
- Symlink(fst.Tmp+"/etc/ssl", "/etc/ssl").
- Symlink(fst.Tmp+"/etc/static", "/etc/static").
- Symlink(fst.Tmp+"/etc/subgid", "/etc/subgid").
- Symlink(fst.Tmp+"/etc/subuid", "/etc/subuid").
- Symlink(fst.Tmp+"/etc/sudoers", "/etc/sudoers").
- Symlink(fst.Tmp+"/etc/sysctl.d", "/etc/sysctl.d").
- Symlink(fst.Tmp+"/etc/systemd", "/etc/systemd").
- Symlink(fst.Tmp+"/etc/terminfo", "/etc/terminfo").
- Symlink(fst.Tmp+"/etc/tmpfiles.d", "/etc/tmpfiles.d").
- Symlink(fst.Tmp+"/etc/udev", "/etc/udev").
- Symlink(fst.Tmp+"/etc/udisks2", "/etc/udisks2").
- Symlink(fst.Tmp+"/etc/UPower", "/etc/UPower").
- Symlink(fst.Tmp+"/etc/vconsole.conf", "/etc/vconsole.conf").
- Symlink(fst.Tmp+"/etc/X11", "/etc/X11").
- Symlink(fst.Tmp+"/etc/zfs", "/etc/zfs").
- Symlink(fst.Tmp+"/etc/zinputrc", "/etc/zinputrc").
- Symlink(fst.Tmp+"/etc/zoneinfo", "/etc/zoneinfo").
- Symlink(fst.Tmp+"/etc/zprofile", "/etc/zprofile").
- Symlink(fst.Tmp+"/etc/zshenv", "/etc/zshenv").
- Symlink(fst.Tmp+"/etc/zshrc", "/etc/zshrc").
- Tmpfs("/run/user", 1048576).
- Tmpfs("/run/user/65534", 8388608).
- Bind("/tmp/fortify.1971/tmpdir/0", "/tmp", false, true).
- Bind("/home/chronos", "/home/chronos", false, true).
- CopyBind("/etc/passwd", []byte("chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n")).
- CopyBind("/etc/group", []byte("fortify:x:65534:\n")).
- Tmpfs("/var/run/nscd", 8192).
- Bind("/run/wrappers/bin/fortify", "/.fortify/sbin/fortify").
- Symlink("fortify", "/.fortify/sbin/init0"),
+ &sandbox.Params{
+ Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
+ Dir: "/home/chronos",
+ Path: "/run/current-system/sw/bin/zsh",
+ Args: []string{"/run/current-system/sw/bin/zsh"},
+ Env: []string{
+ "HOME=/home/chronos",
+ "TERM=xterm-256color",
+ "USER=chronos",
+ "XDG_RUNTIME_DIR=/run/user/65534",
+ "XDG_SESSION_CLASS=user",
+ "XDG_SESSION_TYPE=tty",
+ },
+ Ops: new(sandbox.Ops).
+ Proc("/proc").
+ Tmpfs(fst.Tmp, 4096, 0755).
+ Dev("/dev").Mqueue("/dev/mqueue").
+ Bind("/bin", "/bin", sandbox.BindWritable).
+ Bind("/boot", "/boot", sandbox.BindWritable).
+ Bind("/home", "/home", sandbox.BindWritable).
+ Bind("/lib", "/lib", sandbox.BindWritable).
+ Bind("/lib64", "/lib64", sandbox.BindWritable).
+ Bind("/nix", "/nix", sandbox.BindWritable).
+ Bind("/root", "/root", sandbox.BindWritable).
+ Bind("/run", "/run", sandbox.BindWritable).
+ Bind("/srv", "/srv", sandbox.BindWritable).
+ Bind("/sys", "/sys", sandbox.BindWritable).
+ Bind("/usr", "/usr", sandbox.BindWritable).
+ Bind("/var", "/var", sandbox.BindWritable).
+ Bind("/dev/kvm", "/dev/kvm", sandbox.BindWritable|sandbox.BindDevice|sandbox.BindOptional).
+ Tmpfs("/run/user/1971", 8192, 0755).
+ Tmpfs("/run/dbus", 8192, 0755).
+ Bind("/etc", fst.Tmp+"/etc", 0).
+ Mkdir("/etc", 0700).
+ Link(fst.Tmp+"/etc/alsa", "/etc/alsa").
+ Link(fst.Tmp+"/etc/bashrc", "/etc/bashrc").
+ Link(fst.Tmp+"/etc/binfmt.d", "/etc/binfmt.d").
+ Link(fst.Tmp+"/etc/dbus-1", "/etc/dbus-1").
+ Link(fst.Tmp+"/etc/default", "/etc/default").
+ Link(fst.Tmp+"/etc/ethertypes", "/etc/ethertypes").
+ Link(fst.Tmp+"/etc/fonts", "/etc/fonts").
+ Link(fst.Tmp+"/etc/fstab", "/etc/fstab").
+ Link(fst.Tmp+"/etc/fuse.conf", "/etc/fuse.conf").
+ Link(fst.Tmp+"/etc/host.conf", "/etc/host.conf").
+ Link(fst.Tmp+"/etc/hostid", "/etc/hostid").
+ Link(fst.Tmp+"/etc/hostname", "/etc/hostname").
+ Link(fst.Tmp+"/etc/hostname.CHECKSUM", "/etc/hostname.CHECKSUM").
+ Link(fst.Tmp+"/etc/hosts", "/etc/hosts").
+ Link(fst.Tmp+"/etc/inputrc", "/etc/inputrc").
+ Link(fst.Tmp+"/etc/ipsec.d", "/etc/ipsec.d").
+ Link(fst.Tmp+"/etc/issue", "/etc/issue").
+ Link(fst.Tmp+"/etc/kbd", "/etc/kbd").
+ Link(fst.Tmp+"/etc/libblockdev", "/etc/libblockdev").
+ Link(fst.Tmp+"/etc/locale.conf", "/etc/locale.conf").
+ Link(fst.Tmp+"/etc/localtime", "/etc/localtime").
+ Link(fst.Tmp+"/etc/login.defs", "/etc/login.defs").
+ Link(fst.Tmp+"/etc/lsb-release", "/etc/lsb-release").
+ Link(fst.Tmp+"/etc/lvm", "/etc/lvm").
+ Link(fst.Tmp+"/etc/machine-id", "/etc/machine-id").
+ Link(fst.Tmp+"/etc/man_db.conf", "/etc/man_db.conf").
+ Link(fst.Tmp+"/etc/modprobe.d", "/etc/modprobe.d").
+ Link(fst.Tmp+"/etc/modules-load.d", "/etc/modules-load.d").
+ Link("/proc/mounts", "/etc/mtab").
+ Link(fst.Tmp+"/etc/nanorc", "/etc/nanorc").
+ Link(fst.Tmp+"/etc/netgroup", "/etc/netgroup").
+ Link(fst.Tmp+"/etc/NetworkManager", "/etc/NetworkManager").
+ Link(fst.Tmp+"/etc/nix", "/etc/nix").
+ Link(fst.Tmp+"/etc/nixos", "/etc/nixos").
+ Link(fst.Tmp+"/etc/NIXOS", "/etc/NIXOS").
+ Link(fst.Tmp+"/etc/nscd.conf", "/etc/nscd.conf").
+ Link(fst.Tmp+"/etc/nsswitch.conf", "/etc/nsswitch.conf").
+ Link(fst.Tmp+"/etc/opensnitchd", "/etc/opensnitchd").
+ Link(fst.Tmp+"/etc/os-release", "/etc/os-release").
+ Link(fst.Tmp+"/etc/pam", "/etc/pam").
+ Link(fst.Tmp+"/etc/pam.d", "/etc/pam.d").
+ Link(fst.Tmp+"/etc/pipewire", "/etc/pipewire").
+ Link(fst.Tmp+"/etc/pki", "/etc/pki").
+ Link(fst.Tmp+"/etc/polkit-1", "/etc/polkit-1").
+ Link(fst.Tmp+"/etc/profile", "/etc/profile").
+ Link(fst.Tmp+"/etc/protocols", "/etc/protocols").
+ Link(fst.Tmp+"/etc/qemu", "/etc/qemu").
+ Link(fst.Tmp+"/etc/resolv.conf", "/etc/resolv.conf").
+ Link(fst.Tmp+"/etc/resolvconf.conf", "/etc/resolvconf.conf").
+ Link(fst.Tmp+"/etc/rpc", "/etc/rpc").
+ Link(fst.Tmp+"/etc/samba", "/etc/samba").
+ Link(fst.Tmp+"/etc/sddm.conf", "/etc/sddm.conf").
+ Link(fst.Tmp+"/etc/secureboot", "/etc/secureboot").
+ Link(fst.Tmp+"/etc/services", "/etc/services").
+ Link(fst.Tmp+"/etc/set-environment", "/etc/set-environment").
+ Link(fst.Tmp+"/etc/shadow", "/etc/shadow").
+ Link(fst.Tmp+"/etc/shells", "/etc/shells").
+ Link(fst.Tmp+"/etc/ssh", "/etc/ssh").
+ Link(fst.Tmp+"/etc/ssl", "/etc/ssl").
+ Link(fst.Tmp+"/etc/static", "/etc/static").
+ Link(fst.Tmp+"/etc/subgid", "/etc/subgid").
+ Link(fst.Tmp+"/etc/subuid", "/etc/subuid").
+ Link(fst.Tmp+"/etc/sudoers", "/etc/sudoers").
+ Link(fst.Tmp+"/etc/sysctl.d", "/etc/sysctl.d").
+ Link(fst.Tmp+"/etc/systemd", "/etc/systemd").
+ Link(fst.Tmp+"/etc/terminfo", "/etc/terminfo").
+ Link(fst.Tmp+"/etc/tmpfiles.d", "/etc/tmpfiles.d").
+ Link(fst.Tmp+"/etc/udev", "/etc/udev").
+ Link(fst.Tmp+"/etc/udisks2", "/etc/udisks2").
+ Link(fst.Tmp+"/etc/UPower", "/etc/UPower").
+ Link(fst.Tmp+"/etc/vconsole.conf", "/etc/vconsole.conf").
+ Link(fst.Tmp+"/etc/X11", "/etc/X11").
+ Link(fst.Tmp+"/etc/zfs", "/etc/zfs").
+ Link(fst.Tmp+"/etc/zinputrc", "/etc/zinputrc").
+ Link(fst.Tmp+"/etc/zoneinfo", "/etc/zoneinfo").
+ Link(fst.Tmp+"/etc/zprofile", "/etc/zprofile").
+ Link(fst.Tmp+"/etc/zshenv", "/etc/zshenv").
+ Link(fst.Tmp+"/etc/zshrc", "/etc/zshrc").
+ Tmpfs("/run/user", 4096, 0755).
+ Tmpfs("/run/user/65534", 8388608, 0755).
+ Bind("/tmp/fortify.1971/tmpdir/0", "/tmp", sandbox.BindWritable).
+ Bind("/home/chronos", "/home/chronos", sandbox.BindWritable).
+ Place("/etc/passwd", []byte("chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n")).
+ Place("/etc/group", []byte("fortify:x:65534:\n")).
+ Tmpfs("/var/run/nscd", 8192, 0755),
+ },
},
{
"nixos permissive defaults chromium", new(stubNixOS),
&fst.Config{
- ID: "org.chromium.Chromium",
- Command: []string{"/run/current-system/sw/bin/zsh", "-c", "exec chromium "},
+ ID: "org.chromium.Chromium",
+ Args: []string{"zsh", "-c", "exec chromium "},
Confinement: fst.ConfinementConfig{
AppID: 9,
Groups: []string{"video"},
@@ -254,141 +249,136 @@ var testCasesPd = []sealTestCase{
}).
UpdatePerm("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", acl.Read, acl.Write).
UpdatePerm("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", acl.Read, acl.Write),
- (&bwrap.Config{
- Net: true,
- UserNS: true,
- Chdir: "/home/chronos",
- Clearenv: true,
- Syscall: new(bwrap.SyscallPolicy),
- SetEnv: map[string]string{
- "DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/65534/bus",
- "DBUS_SYSTEM_BUS_ADDRESS": "unix:path=/run/dbus/system_bus_socket",
- "HOME": "/home/chronos",
- "PULSE_COOKIE": fst.Tmp + "/pulse-cookie",
- "PULSE_SERVER": "unix:/run/user/65534/pulse/native",
- "SHELL": "/run/current-system/sw/bin/zsh",
- "TERM": "xterm-256color",
- "USER": "chronos",
- "WAYLAND_DISPLAY": "wayland-0",
- "XDG_RUNTIME_DIR": "/run/user/65534",
- "XDG_SESSION_CLASS": "user",
- "XDG_SESSION_TYPE": "tty",
+ &sandbox.Params{
+ Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
+ Dir: "/home/chronos",
+ Path: "/run/current-system/sw/bin/zsh",
+ Args: []string{"zsh", "-c", "exec chromium "},
+ Env: []string{
+ "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
+ "DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
+ "HOME=/home/chronos",
+ "PULSE_COOKIE=" + fst.Tmp + "/pulse-cookie",
+ "PULSE_SERVER=unix:/run/user/65534/pulse/native",
+ "TERM=xterm-256color",
+ "USER=chronos",
+ "WAYLAND_DISPLAY=wayland-0",
+ "XDG_RUNTIME_DIR=/run/user/65534",
+ "XDG_SESSION_CLASS=user",
+ "XDG_SESSION_TYPE=tty",
},
- Chmod: make(bwrap.ChmodConfig),
- DieWithParent: true,
- AsInit: true,
- }).SetUID(65534).SetGID(65534).
- Procfs("/proc").
- Tmpfs(fst.Tmp, 4096).
- DevTmpfs("/dev").Mqueue("/dev/mqueue").
- Bind("/bin", "/bin", false, true).
- Bind("/boot", "/boot", false, true).
- Bind("/home", "/home", false, true).
- Bind("/lib", "/lib", false, true).
- Bind("/lib64", "/lib64", false, true).
- Bind("/nix", "/nix", false, true).
- Bind("/root", "/root", false, true).
- Bind("/run", "/run", false, true).
- Bind("/srv", "/srv", false, true).
- Bind("/sys", "/sys", false, true).
- Bind("/usr", "/usr", false, true).
- Bind("/var", "/var", false, true).
- Bind("/dev/dri", "/dev/dri", true, true, true).
- Bind("/dev/kvm", "/dev/kvm", true, true, true).
- Tmpfs("/run/user/1971", 8192).
- Tmpfs("/run/dbus", 8192).
- Bind("/etc", fst.Tmp+"/etc").
- Symlink(fst.Tmp+"/etc/alsa", "/etc/alsa").
- Symlink(fst.Tmp+"/etc/bashrc", "/etc/bashrc").
- Symlink(fst.Tmp+"/etc/binfmt.d", "/etc/binfmt.d").
- Symlink(fst.Tmp+"/etc/dbus-1", "/etc/dbus-1").
- Symlink(fst.Tmp+"/etc/default", "/etc/default").
- Symlink(fst.Tmp+"/etc/ethertypes", "/etc/ethertypes").
- Symlink(fst.Tmp+"/etc/fonts", "/etc/fonts").
- Symlink(fst.Tmp+"/etc/fstab", "/etc/fstab").
- Symlink(fst.Tmp+"/etc/fuse.conf", "/etc/fuse.conf").
- Symlink(fst.Tmp+"/etc/host.conf", "/etc/host.conf").
- Symlink(fst.Tmp+"/etc/hostid", "/etc/hostid").
- Symlink(fst.Tmp+"/etc/hostname", "/etc/hostname").
- Symlink(fst.Tmp+"/etc/hostname.CHECKSUM", "/etc/hostname.CHECKSUM").
- Symlink(fst.Tmp+"/etc/hosts", "/etc/hosts").
- Symlink(fst.Tmp+"/etc/inputrc", "/etc/inputrc").
- Symlink(fst.Tmp+"/etc/ipsec.d", "/etc/ipsec.d").
- Symlink(fst.Tmp+"/etc/issue", "/etc/issue").
- Symlink(fst.Tmp+"/etc/kbd", "/etc/kbd").
- Symlink(fst.Tmp+"/etc/libblockdev", "/etc/libblockdev").
- Symlink(fst.Tmp+"/etc/locale.conf", "/etc/locale.conf").
- Symlink(fst.Tmp+"/etc/localtime", "/etc/localtime").
- Symlink(fst.Tmp+"/etc/login.defs", "/etc/login.defs").
- Symlink(fst.Tmp+"/etc/lsb-release", "/etc/lsb-release").
- Symlink(fst.Tmp+"/etc/lvm", "/etc/lvm").
- Symlink(fst.Tmp+"/etc/machine-id", "/etc/machine-id").
- Symlink(fst.Tmp+"/etc/man_db.conf", "/etc/man_db.conf").
- Symlink(fst.Tmp+"/etc/modprobe.d", "/etc/modprobe.d").
- Symlink(fst.Tmp+"/etc/modules-load.d", "/etc/modules-load.d").
- Symlink("/proc/mounts", "/etc/mtab").
- Symlink(fst.Tmp+"/etc/nanorc", "/etc/nanorc").
- Symlink(fst.Tmp+"/etc/netgroup", "/etc/netgroup").
- Symlink(fst.Tmp+"/etc/NetworkManager", "/etc/NetworkManager").
- Symlink(fst.Tmp+"/etc/nix", "/etc/nix").
- Symlink(fst.Tmp+"/etc/nixos", "/etc/nixos").
- Symlink(fst.Tmp+"/etc/NIXOS", "/etc/NIXOS").
- Symlink(fst.Tmp+"/etc/nscd.conf", "/etc/nscd.conf").
- Symlink(fst.Tmp+"/etc/nsswitch.conf", "/etc/nsswitch.conf").
- Symlink(fst.Tmp+"/etc/opensnitchd", "/etc/opensnitchd").
- Symlink(fst.Tmp+"/etc/os-release", "/etc/os-release").
- Symlink(fst.Tmp+"/etc/pam", "/etc/pam").
- Symlink(fst.Tmp+"/etc/pam.d", "/etc/pam.d").
- Symlink(fst.Tmp+"/etc/pipewire", "/etc/pipewire").
- Symlink(fst.Tmp+"/etc/pki", "/etc/pki").
- Symlink(fst.Tmp+"/etc/polkit-1", "/etc/polkit-1").
- Symlink(fst.Tmp+"/etc/profile", "/etc/profile").
- Symlink(fst.Tmp+"/etc/protocols", "/etc/protocols").
- Symlink(fst.Tmp+"/etc/qemu", "/etc/qemu").
- Symlink(fst.Tmp+"/etc/resolv.conf", "/etc/resolv.conf").
- Symlink(fst.Tmp+"/etc/resolvconf.conf", "/etc/resolvconf.conf").
- Symlink(fst.Tmp+"/etc/rpc", "/etc/rpc").
- Symlink(fst.Tmp+"/etc/samba", "/etc/samba").
- Symlink(fst.Tmp+"/etc/sddm.conf", "/etc/sddm.conf").
- Symlink(fst.Tmp+"/etc/secureboot", "/etc/secureboot").
- Symlink(fst.Tmp+"/etc/services", "/etc/services").
- Symlink(fst.Tmp+"/etc/set-environment", "/etc/set-environment").
- Symlink(fst.Tmp+"/etc/shadow", "/etc/shadow").
- Symlink(fst.Tmp+"/etc/shells", "/etc/shells").
- Symlink(fst.Tmp+"/etc/ssh", "/etc/ssh").
- Symlink(fst.Tmp+"/etc/ssl", "/etc/ssl").
- Symlink(fst.Tmp+"/etc/static", "/etc/static").
- Symlink(fst.Tmp+"/etc/subgid", "/etc/subgid").
- Symlink(fst.Tmp+"/etc/subuid", "/etc/subuid").
- Symlink(fst.Tmp+"/etc/sudoers", "/etc/sudoers").
- Symlink(fst.Tmp+"/etc/sysctl.d", "/etc/sysctl.d").
- Symlink(fst.Tmp+"/etc/systemd", "/etc/systemd").
- Symlink(fst.Tmp+"/etc/terminfo", "/etc/terminfo").
- Symlink(fst.Tmp+"/etc/tmpfiles.d", "/etc/tmpfiles.d").
- Symlink(fst.Tmp+"/etc/udev", "/etc/udev").
- Symlink(fst.Tmp+"/etc/udisks2", "/etc/udisks2").
- Symlink(fst.Tmp+"/etc/UPower", "/etc/UPower").
- Symlink(fst.Tmp+"/etc/vconsole.conf", "/etc/vconsole.conf").
- Symlink(fst.Tmp+"/etc/X11", "/etc/X11").
- Symlink(fst.Tmp+"/etc/zfs", "/etc/zfs").
- Symlink(fst.Tmp+"/etc/zinputrc", "/etc/zinputrc").
- Symlink(fst.Tmp+"/etc/zoneinfo", "/etc/zoneinfo").
- Symlink(fst.Tmp+"/etc/zprofile", "/etc/zprofile").
- Symlink(fst.Tmp+"/etc/zshenv", "/etc/zshenv").
- Symlink(fst.Tmp+"/etc/zshrc", "/etc/zshrc").
- Tmpfs("/run/user", 1048576).
- Tmpfs("/run/user/65534", 8388608).
- Bind("/tmp/fortify.1971/tmpdir/9", "/tmp", false, true).
- Bind("/home/chronos", "/home/chronos", false, true).
- CopyBind("/etc/passwd", []byte("chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n")).
- CopyBind("/etc/group", []byte("fortify:x:65534:\n")).
- Bind("/tmp/fortify.1971/wayland/ebf083d1b175911782d413369b64ce7c", "/run/user/65534/wayland-0").
- Bind("/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/pulse", "/run/user/65534/pulse/native").
- CopyBind(fst.Tmp+"/pulse-cookie", nil).
- Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", "/run/user/65534/bus").
- Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", "/run/dbus/system_bus_socket").
- Tmpfs("/var/run/nscd", 8192).
- Bind("/run/wrappers/bin/fortify", "/.fortify/sbin/fortify").
- Symlink("fortify", "/.fortify/sbin/init0"),
+ Ops: new(sandbox.Ops).
+ Proc("/proc").
+ Tmpfs(fst.Tmp, 4096, 0755).
+ Dev("/dev").Mqueue("/dev/mqueue").
+ Bind("/bin", "/bin", sandbox.BindWritable).
+ Bind("/boot", "/boot", sandbox.BindWritable).
+ Bind("/home", "/home", sandbox.BindWritable).
+ Bind("/lib", "/lib", sandbox.BindWritable).
+ Bind("/lib64", "/lib64", sandbox.BindWritable).
+ Bind("/nix", "/nix", sandbox.BindWritable).
+ Bind("/root", "/root", sandbox.BindWritable).
+ Bind("/run", "/run", sandbox.BindWritable).
+ Bind("/srv", "/srv", sandbox.BindWritable).
+ Bind("/sys", "/sys", sandbox.BindWritable).
+ Bind("/usr", "/usr", sandbox.BindWritable).
+ Bind("/var", "/var", sandbox.BindWritable).
+ Bind("/dev/dri", "/dev/dri", sandbox.BindWritable|sandbox.BindDevice|sandbox.BindOptional).
+ Bind("/dev/kvm", "/dev/kvm", sandbox.BindWritable|sandbox.BindDevice|sandbox.BindOptional).
+ Tmpfs("/run/user/1971", 8192, 0755).
+ Tmpfs("/run/dbus", 8192, 0755).
+ Bind("/etc", fst.Tmp+"/etc", 0).
+ Mkdir("/etc", 0700).
+ Link(fst.Tmp+"/etc/alsa", "/etc/alsa").
+ Link(fst.Tmp+"/etc/bashrc", "/etc/bashrc").
+ Link(fst.Tmp+"/etc/binfmt.d", "/etc/binfmt.d").
+ Link(fst.Tmp+"/etc/dbus-1", "/etc/dbus-1").
+ Link(fst.Tmp+"/etc/default", "/etc/default").
+ Link(fst.Tmp+"/etc/ethertypes", "/etc/ethertypes").
+ Link(fst.Tmp+"/etc/fonts", "/etc/fonts").
+ Link(fst.Tmp+"/etc/fstab", "/etc/fstab").
+ Link(fst.Tmp+"/etc/fuse.conf", "/etc/fuse.conf").
+ Link(fst.Tmp+"/etc/host.conf", "/etc/host.conf").
+ Link(fst.Tmp+"/etc/hostid", "/etc/hostid").
+ Link(fst.Tmp+"/etc/hostname", "/etc/hostname").
+ Link(fst.Tmp+"/etc/hostname.CHECKSUM", "/etc/hostname.CHECKSUM").
+ Link(fst.Tmp+"/etc/hosts", "/etc/hosts").
+ Link(fst.Tmp+"/etc/inputrc", "/etc/inputrc").
+ Link(fst.Tmp+"/etc/ipsec.d", "/etc/ipsec.d").
+ Link(fst.Tmp+"/etc/issue", "/etc/issue").
+ Link(fst.Tmp+"/etc/kbd", "/etc/kbd").
+ Link(fst.Tmp+"/etc/libblockdev", "/etc/libblockdev").
+ Link(fst.Tmp+"/etc/locale.conf", "/etc/locale.conf").
+ Link(fst.Tmp+"/etc/localtime", "/etc/localtime").
+ Link(fst.Tmp+"/etc/login.defs", "/etc/login.defs").
+ Link(fst.Tmp+"/etc/lsb-release", "/etc/lsb-release").
+ Link(fst.Tmp+"/etc/lvm", "/etc/lvm").
+ Link(fst.Tmp+"/etc/machine-id", "/etc/machine-id").
+ Link(fst.Tmp+"/etc/man_db.conf", "/etc/man_db.conf").
+ Link(fst.Tmp+"/etc/modprobe.d", "/etc/modprobe.d").
+ Link(fst.Tmp+"/etc/modules-load.d", "/etc/modules-load.d").
+ Link("/proc/mounts", "/etc/mtab").
+ Link(fst.Tmp+"/etc/nanorc", "/etc/nanorc").
+ Link(fst.Tmp+"/etc/netgroup", "/etc/netgroup").
+ Link(fst.Tmp+"/etc/NetworkManager", "/etc/NetworkManager").
+ Link(fst.Tmp+"/etc/nix", "/etc/nix").
+ Link(fst.Tmp+"/etc/nixos", "/etc/nixos").
+ Link(fst.Tmp+"/etc/NIXOS", "/etc/NIXOS").
+ Link(fst.Tmp+"/etc/nscd.conf", "/etc/nscd.conf").
+ Link(fst.Tmp+"/etc/nsswitch.conf", "/etc/nsswitch.conf").
+ Link(fst.Tmp+"/etc/opensnitchd", "/etc/opensnitchd").
+ Link(fst.Tmp+"/etc/os-release", "/etc/os-release").
+ Link(fst.Tmp+"/etc/pam", "/etc/pam").
+ Link(fst.Tmp+"/etc/pam.d", "/etc/pam.d").
+ Link(fst.Tmp+"/etc/pipewire", "/etc/pipewire").
+ Link(fst.Tmp+"/etc/pki", "/etc/pki").
+ Link(fst.Tmp+"/etc/polkit-1", "/etc/polkit-1").
+ Link(fst.Tmp+"/etc/profile", "/etc/profile").
+ Link(fst.Tmp+"/etc/protocols", "/etc/protocols").
+ Link(fst.Tmp+"/etc/qemu", "/etc/qemu").
+ Link(fst.Tmp+"/etc/resolv.conf", "/etc/resolv.conf").
+ Link(fst.Tmp+"/etc/resolvconf.conf", "/etc/resolvconf.conf").
+ Link(fst.Tmp+"/etc/rpc", "/etc/rpc").
+ Link(fst.Tmp+"/etc/samba", "/etc/samba").
+ Link(fst.Tmp+"/etc/sddm.conf", "/etc/sddm.conf").
+ Link(fst.Tmp+"/etc/secureboot", "/etc/secureboot").
+ Link(fst.Tmp+"/etc/services", "/etc/services").
+ Link(fst.Tmp+"/etc/set-environment", "/etc/set-environment").
+ Link(fst.Tmp+"/etc/shadow", "/etc/shadow").
+ Link(fst.Tmp+"/etc/shells", "/etc/shells").
+ Link(fst.Tmp+"/etc/ssh", "/etc/ssh").
+ Link(fst.Tmp+"/etc/ssl", "/etc/ssl").
+ Link(fst.Tmp+"/etc/static", "/etc/static").
+ Link(fst.Tmp+"/etc/subgid", "/etc/subgid").
+ Link(fst.Tmp+"/etc/subuid", "/etc/subuid").
+ Link(fst.Tmp+"/etc/sudoers", "/etc/sudoers").
+ Link(fst.Tmp+"/etc/sysctl.d", "/etc/sysctl.d").
+ Link(fst.Tmp+"/etc/systemd", "/etc/systemd").
+ Link(fst.Tmp+"/etc/terminfo", "/etc/terminfo").
+ Link(fst.Tmp+"/etc/tmpfiles.d", "/etc/tmpfiles.d").
+ Link(fst.Tmp+"/etc/udev", "/etc/udev").
+ Link(fst.Tmp+"/etc/udisks2", "/etc/udisks2").
+ Link(fst.Tmp+"/etc/UPower", "/etc/UPower").
+ Link(fst.Tmp+"/etc/vconsole.conf", "/etc/vconsole.conf").
+ Link(fst.Tmp+"/etc/X11", "/etc/X11").
+ Link(fst.Tmp+"/etc/zfs", "/etc/zfs").
+ Link(fst.Tmp+"/etc/zinputrc", "/etc/zinputrc").
+ Link(fst.Tmp+"/etc/zoneinfo", "/etc/zoneinfo").
+ Link(fst.Tmp+"/etc/zprofile", "/etc/zprofile").
+ Link(fst.Tmp+"/etc/zshenv", "/etc/zshenv").
+ Link(fst.Tmp+"/etc/zshrc", "/etc/zshrc").
+ Tmpfs("/run/user", 4096, 0755).
+ Tmpfs("/run/user/65534", 8388608, 0755).
+ Bind("/tmp/fortify.1971/tmpdir/9", "/tmp", sandbox.BindWritable).
+ Bind("/home/chronos", "/home/chronos", sandbox.BindWritable).
+ Place("/etc/passwd", []byte("chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n")).
+ Place("/etc/group", []byte("fortify:x:65534:\n")).
+ Bind("/tmp/fortify.1971/wayland/ebf083d1b175911782d413369b64ce7c", "/run/user/65534/wayland-0", 0).
+ Bind("/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/pulse", "/run/user/65534/pulse/native", 0).
+ Place(fst.Tmp+"/pulse-cookie", nil).
+ Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", "/run/user/65534/bus", 0).
+ Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", "/run/dbus/system_bus_socket", 0).
+ Tmpfs("/var/run/nscd", 8192, 0755),
+ },
},
}
diff --git a/internal/app/app_stub_test.go b/internal/app/app_stub_test.go
index be496177..665dfa04 100644
--- a/internal/app/app_stub_test.go
+++ b/internal/app/app_stub_test.go
@@ -55,10 +55,8 @@ func (s *stubNixOS) LookPath(file string) (string, error) {
}
switch file {
- case "sudo":
- return "/run/wrappers/bin/sudo", nil
- case "machinectl":
- return "/home/ophestra/.nix-profile/bin/machinectl", nil
+ case "zsh":
+ return "/run/current-system/sw/bin/zsh", nil
default:
panic(fmt.Sprintf("attempted to look up unexpected executable %q", file))
}
diff --git a/internal/app/app_test.go b/internal/app/app_test.go
index b4481537..fa13ddd9 100644
--- a/internal/app/app_test.go
+++ b/internal/app/app_test.go
@@ -8,19 +8,19 @@ import (
"time"
"git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/sys"
+ "git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
)
type sealTestCase struct {
- name string
- os sys.State
- config *fst.Config
- id fst.ID
- wantSys *system.I
- wantBwrap *bwrap.Config
+ name string
+ os sys.State
+ config *fst.Config
+ id fst.ID
+ wantSys *system.I
+ wantContainer *sandbox.Params
}
func TestApp(t *testing.T) {
@@ -30,15 +30,15 @@ func TestApp(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
a := app.NewWithID(tc.id, tc.os)
var (
- gotSys *system.I
- gotBwrap *bwrap.Config
+ gotSys *system.I
+ gotContainer *sandbox.Params
)
if !t.Run("seal", func(t *testing.T) {
if sa, err := a.Seal(tc.config); err != nil {
t.Errorf("Seal: error = %v", err)
return
} else {
- gotSys, gotBwrap = app.AppSystemBwrap(a, sa)
+ gotSys, gotContainer = app.AppIParams(a, sa)
}
}) {
return
@@ -51,10 +51,10 @@ func TestApp(t *testing.T) {
}
})
- t.Run("compare bwrap", func(t *testing.T) {
- if !reflect.DeepEqual(gotBwrap, tc.wantBwrap) {
- t.Errorf("seal: bwrap =\n%s\n, want\n%s",
- mustMarshal(gotBwrap), mustMarshal(tc.wantBwrap))
+ t.Run("compare params", func(t *testing.T) {
+ if !reflect.DeepEqual(gotContainer, tc.wantContainer) {
+ t.Errorf("seal: params =\n%s\n, want\n%s",
+ mustMarshal(gotContainer), mustMarshal(tc.wantContainer))
}
})
})
diff --git a/internal/app/export_test.go b/internal/app/export_test.go
index 199b6c1f..60d97b36 100644
--- a/internal/app/export_test.go
+++ b/internal/app/export_test.go
@@ -2,8 +2,8 @@ package app
import (
"git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/internal/sys"
+ "git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
)
@@ -14,7 +14,7 @@ func NewWithID(id fst.ID, os sys.State) fst.App {
return a
}
-func AppSystemBwrap(a fst.App, sa fst.SealedApp) (*system.I, *bwrap.Config) {
+func AppIParams(a fst.App, sa fst.SealedApp) (*system.I, *sandbox.Params) {
v := a.(*app)
seal := sa.(*outcome)
if v.outcome != seal || v.id != seal.id {
diff --git a/internal/app/init0/early.go b/internal/app/init0/early.go
deleted file mode 100644
index 0bcf094c..00000000
--- a/internal/app/init0/early.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package init0
-
-import (
- "os"
- "path"
-
- "git.gensokyo.uk/security/fortify/internal"
-)
-
-// used by the parent process
-
-// TryArgv0 calls [Main] if the last element of argv0 is "init0".
-func TryArgv0() {
- if len(os.Args) > 0 && path.Base(os.Args[0]) == "init0" {
- Main()
- internal.Exit(0)
- }
-}
diff --git a/internal/app/init0/main.go b/internal/app/init0/main.go
deleted file mode 100644
index 7b8d27c6..00000000
--- a/internal/app/init0/main.go
+++ /dev/null
@@ -1,165 +0,0 @@
-package init0
-
-import (
- "errors"
- "log"
- "os"
- "os/exec"
- "os/signal"
- "syscall"
- "time"
-
- "git.gensokyo.uk/security/fortify/internal"
- "git.gensokyo.uk/security/fortify/internal/fmsg"
- "git.gensokyo.uk/security/fortify/sandbox"
-)
-
-const (
- // time to wait for linger processes after death of initial process
- residualProcessTimeout = 5 * time.Second
-)
-
-// everything beyond this point runs within pid namespace
-// proceed with caution!
-
-func Main() {
- // sharing stdout with shim
- // USE WITH CAUTION
- fmsg.Prepare("init0")
-
- // setting this prevents ptrace
- if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
- log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
- }
-
- if os.Getpid() != 1 {
- log.Fatal("this process must run as pid 1")
- }
-
- // receive setup payload
- var (
- payload Payload
- closeSetup func() error
- )
- if f, err := sandbox.Receive(Env, &payload, nil); err != nil {
- if errors.Is(err, sandbox.ErrInvalid) {
- log.Fatal("invalid config descriptor")
- }
- if errors.Is(err, sandbox.ErrNotSet) {
- log.Fatal("FORTIFY_INIT not set")
- }
-
- log.Fatalf("cannot decode init setup payload: %v", err)
- } else {
- fmsg.Store(payload.Verbose)
- closeSetup = f
-
- // child does not need to see this
- if err = os.Unsetenv(Env); err != nil {
- log.Printf("cannot unset %s: %v", Env, err)
- // not fatal
- } else {
- fmsg.Verbose("received configuration")
- }
- }
-
- // die with parent
- if err := sandbox.SetPdeathsig(syscall.SIGKILL); err != nil {
- log.Fatalf("prctl(PR_SET_PDEATHSIG, SIGKILL): %v", err)
- }
-
- cmd := exec.Command(payload.Argv0)
- cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
- cmd.Args = payload.Argv
- cmd.Env = os.Environ()
-
- if err := cmd.Start(); err != nil {
- log.Fatalf("cannot start %q: %v", payload.Argv0, err)
- }
- fmsg.Suspend()
-
- // close setup pipe as setup is now complete
- if err := closeSetup(); err != nil {
- log.Println("cannot close setup pipe:", err)
- // not fatal
- }
-
- sig := make(chan os.Signal, 2)
- signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
-
- type winfo struct {
- wpid int
- wstatus syscall.WaitStatus
- }
- info := make(chan winfo, 1)
- done := make(chan struct{})
-
- go func() {
- var (
- err error
- wpid = -2
- wstatus syscall.WaitStatus
- )
-
- // keep going until no child process is left
- for wpid != -1 {
- if err != nil {
- break
- }
-
- if wpid != -2 {
- info <- winfo{wpid, wstatus}
- }
-
- err = syscall.EINTR
- for errors.Is(err, syscall.EINTR) {
- wpid, err = syscall.Wait4(-1, &wstatus, 0, nil)
- }
- }
- if !errors.Is(err, syscall.ECHILD) {
- log.Println("unexpected wait4 response:", err)
- }
-
- close(done)
- }()
-
- // closed after residualProcessTimeout has elapsed after initial process death
- timeout := make(chan struct{})
-
- r := 2
- for {
- select {
- case s := <-sig:
- if fmsg.Resume() {
- fmsg.Verbosef("terminating on %s after process start", s.String())
- } else {
- fmsg.Verbosef("terminating on %s", s.String())
- }
- internal.Exit(0)
- case w := <-info:
- if w.wpid == cmd.Process.Pid {
- // initial process exited, output is most likely available again
- fmsg.Resume()
-
- switch {
- case w.wstatus.Exited():
- r = w.wstatus.ExitStatus()
- case w.wstatus.Signaled():
- r = 128 + int(w.wstatus.Signal())
- default:
- r = 255
- }
-
- go func() {
- time.Sleep(residualProcessTimeout)
- close(timeout)
- }()
- }
- case <-done:
- internal.Exit(r)
- case <-timeout:
- log.Println("timeout exceeded waiting for lingering processes")
- internal.Exit(r)
- }
- }
-}
diff --git a/internal/app/init0/payload.go b/internal/app/init0/payload.go
deleted file mode 100644
index d1dc9ec3..00000000
--- a/internal/app/init0/payload.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package init0
-
-const Env = "FORTIFY_INIT"
-
-type Payload struct {
- // target full exec path
- Argv0 string
- // child full argv
- Argv []string
-
- // verbosity pass through
- Verbose bool
-}
diff --git a/internal/app/process.go b/internal/app/process.go
index 2755230c..6c337142 100644
--- a/internal/app/process.go
+++ b/internal/app/process.go
@@ -3,15 +3,12 @@ package app
import (
"context"
"errors"
- "fmt"
"log"
"os/exec"
- "path/filepath"
"strings"
"time"
"git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/app/shim"
"git.gensokyo.uk/security/fortify/internal/fmsg"
@@ -21,7 +18,7 @@ import (
const shimSetupTimeout = 5 * time.Second
-func (seal *outcome) Run(ctx context.Context, rs *fst.RunState) error {
+func (seal *outcome) Run(rs *fst.RunState) error {
if !seal.f.CompareAndSwap(false, true) {
// run does much more than just starting a process; calling it twice, even if the first call fails, will result
// in inconsistent state that is impossible to clean up; return here to limit damage and hopefully give the
@@ -38,32 +35,10 @@ func (seal *outcome) Run(ctx context.Context, rs *fst.RunState) error {
fmsg.Verbosef("setuid helper at %s", internal.MustFsuPath())
/*
- resolve exec paths
- */
-
- shimExec := [2]string{helper.BubblewrapName}
- if len(seal.command) > 0 {
- shimExec[1] = seal.command[0]
- }
- for i, n := range shimExec {
- if len(n) == 0 {
- continue
- }
- if filepath.Base(n) == n {
- if s, err := exec.LookPath(n); err == nil {
- shimExec[i] = s
- } else {
- return fmsg.WrapError(err,
- fmt.Sprintf("executable file %q not found in $PATH", n))
- }
- }
- }
-
- /*
prepare/revert os state
*/
- if err := seal.sys.Commit(ctx); err != nil {
+ if err := seal.sys.Commit(seal.ctx); err != nil {
return err
}
store := state.NewMulti(seal.runDirPath)
@@ -137,7 +112,6 @@ func (seal *outcome) Run(ctx context.Context, rs *fst.RunState) error {
if startTime, err := cmd.Start(
seal.user.aid.String(),
seal.user.supp,
- seal.bwrapSync,
); err != nil {
return err
} else {
@@ -145,7 +119,7 @@ func (seal *outcome) Run(ctx context.Context, rs *fst.RunState) error {
rs.Time = startTime
}
- c, cancel := context.WithTimeout(ctx, shimSetupTimeout)
+ ctx, cancel := context.WithTimeout(seal.ctx, shimSetupTimeout)
defer cancel()
go func() {
@@ -154,11 +128,9 @@ func (seal *outcome) Run(ctx context.Context, rs *fst.RunState) error {
cancel()
}()
- if err := cmd.Serve(c, &shim.Payload{
- Argv: seal.command,
- Exec: shimExec,
- Bwrap: seal.container,
- Home: seal.user.data,
+ if err := cmd.Serve(ctx, &shim.Params{
+ Container: seal.container,
+ Home: seal.user.data,
Verbose: fmsg.Load(),
}); err != nil {
@@ -199,18 +171,22 @@ func (seal *outcome) Run(ctx context.Context, rs *fst.RunState) error {
// this is reached when a fault makes an already running shim impossible to continue execution
// however a kill signal could not be delivered (should actually always happen like that since fsu)
// the effects of this is similar to the alternative exit path and ensures shim death
- case err := <-cmd.WaitFallback():
+ case err := <-cmd.Fallback():
rs.ExitCode = 255
log.Printf("cannot terminate shim on faulted setup: %v", err)
// alternative exit path relying on shim behaviour on monitor process exit
- case <-ctx.Done():
+ case <-seal.ctx.Done():
fmsg.Verbose("alternative exit path selected")
}
fmsg.Resume()
+ if seal.sync != nil {
+ if err := seal.sync.Close(); err != nil {
+ log.Printf("cannot close wayland security context: %v", err)
+ }
+ }
if seal.dbusMsg != nil {
- // dump dbus message buffer
seal.dbusMsg()
}
diff --git a/internal/app/seal.go b/internal/app/seal.go
index 30702124..a25897dc 100644
--- a/internal/app/seal.go
+++ b/internal/app/seal.go
@@ -2,24 +2,28 @@ package app
import (
"bytes"
+ "context"
"encoding/gob"
"errors"
"fmt"
"io"
"io/fs"
+ "maps"
"os"
"path"
"regexp"
+ "slices"
"strings"
"sync/atomic"
+ "syscall"
"git.gensokyo.uk/security/fortify/acl"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper/bwrap"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/sys"
+ "git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/fortify/wl"
)
@@ -65,19 +69,19 @@ type outcome struct {
// copied from [sys.State] response
runDirPath string
- // passed through from [fst.Config]
- command []string
-
// initial [fst.Config] gob stream for state data;
- // this is prepared ahead of time as config is mutated during seal creation
+ // this is prepared ahead of time as config is clobbered during seal creation
ct io.WriterTo
// dump dbus proxy message buffer
dbusMsg func()
- user fsuUser
- sys *system.I
- container *bwrap.Config
- bwrapSync *os.File
+ user fsuUser
+ sys *system.I
+ ctx context.Context
+
+ container *sandbox.Params
+ env map[string]string
+ sync *os.File
f atomic.Bool
}
@@ -100,7 +104,17 @@ type fsuUser struct {
username string
}
-func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
+func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Config) error {
+ if seal.ctx != nil {
+ panic("finalise called twice")
+ }
+ seal.ctx = ctx
+
+ shellPath := "/bin/sh"
+ if s, ok := sys.LookupEnv(shell); ok && path.IsAbs(s) {
+ shellPath = s
+ }
+
{
// encode initial configuration for state tracking
ct := new(bytes.Buffer)
@@ -111,9 +125,6 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
seal.ct = ct
}
- // pass through command slice; this value is never touched in the main process
- seal.command = config.Command
-
// allowed aid range 0 to 9999, this is checked again in fsu
if config.Confinement.AppID < 0 || config.Confinement.AppID > 9999 {
return fmsg.WrapError(ErrUser,
@@ -167,12 +178,24 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
if config.Confinement.Sandbox == nil {
fmsg.Verbose("sandbox configuration not supplied, PROCEED WITH CAUTION")
+ // fsu clears the environment so resolve paths early
+ if !path.IsAbs(config.Path) {
+ if len(config.Args) > 0 {
+ if p, err := sys.LookPath(config.Args[0]); err != nil {
+ return fmsg.WrapError(err, err.Error())
+ } else {
+ config.Path = p
+ }
+ } else {
+ config.Path = shellPath
+ }
+ }
+
conf := &fst.SandboxConfig{
- UserNS: true,
- Net: true,
- Syscall: new(bwrap.SyscallPolicy),
- NoNewSession: true,
- AutoEtc: true,
+ Userns: true,
+ Net: true,
+ Tty: true,
+ AutoEtc: true,
}
// bind entries in /
if d, err := sys.ReadDir("/"); err != nil {
@@ -198,7 +221,7 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
// hide nscd from sandbox if present
nscd := "/var/run/nscd"
if _, err := sys.Stat(nscd); !errors.Is(err, fs.ErrNotExist) {
- conf.Override = append(conf.Override, nscd)
+ conf.Cover = append(conf.Cover, nscd)
}
// bind GPU stuff
if config.Confinement.Enablements.Has(system.EX11) || config.Confinement.Enablements.Has(system.EWayland) {
@@ -210,17 +233,29 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
config.Confinement.Sandbox = conf
}
- var mapuid *stringPair[int]
+ var mapuid, mapgid *stringPair[int]
{
- var uid int
+ var uid, gid int
var err error
- seal.container, err = config.Confinement.Sandbox.Bwrap(sys, &uid)
+ seal.container, seal.env, err = config.Confinement.Sandbox.ToContainer(sys, &uid, &gid)
if err != nil {
- return err
+ return fmsg.WrapErrorSuffix(err,
+ "cannot initialise container configuration:")
+ }
+ if !path.IsAbs(config.Path) {
+ return fmsg.WrapError(syscall.EINVAL,
+ "invalid program path")
}
+ if len(config.Args) == 0 {
+ config.Args = []string{config.Path}
+ }
+ seal.container.Path = config.Path
+ seal.container.Args = config.Args
+
mapuid = newInt(uid)
- if seal.container.SetEnv == nil {
- seal.container.SetEnv = make(map[string]string)
+ mapgid = newInt(gid)
+ if seal.env == nil {
+ seal.env = make(map[string]string)
}
}
@@ -255,35 +290,27 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
// inner XDG_RUNTIME_DIR default formatting of `/run/user/%d` as post-fsu user
innerRuntimeDir := path.Join("/run/user", mapuid.String())
- seal.container.Tmpfs("/run/user", 1*1024*1024)
- seal.container.Tmpfs(innerRuntimeDir, 8*1024*1024)
- seal.container.SetEnv[xdgRuntimeDir] = innerRuntimeDir
- seal.container.SetEnv[xdgSessionClass] = "user"
- seal.container.SetEnv[xdgSessionType] = "tty"
+ seal.container.Tmpfs("/run/user", 1<<12, 0755)
+ seal.container.Tmpfs(innerRuntimeDir, 1<<23, 0755)
+ seal.env[xdgRuntimeDir] = innerRuntimeDir
+ seal.env[xdgSessionClass] = "user"
+ seal.env[xdgSessionType] = "tty"
// outer path for inner /tmp
{
tmpdir := path.Join(sc.SharePath, "tmpdir")
seal.sys.Ensure(tmpdir, 0700)
seal.sys.UpdatePermType(system.User, tmpdir, acl.Execute)
- tmpdirProc := path.Join(tmpdir, seal.user.aid.String())
- seal.sys.Ensure(tmpdirProc, 01700)
- seal.sys.UpdatePermType(system.User, tmpdirProc, acl.Read, acl.Write, acl.Execute)
- seal.container.Bind(tmpdirProc, "/tmp", false, true)
+ tmpdirInst := path.Join(tmpdir, seal.user.aid.String())
+ seal.sys.Ensure(tmpdirInst, 01700)
+ seal.sys.UpdatePermType(system.User, tmpdirInst, acl.Read, acl.Write, acl.Execute)
+ seal.container.Bind(tmpdirInst, "/tmp", sandbox.BindWritable)
}
/*
Passwd database
*/
- // look up shell
- sh := "/bin/sh"
- if s, ok := sys.LookupEnv(shell); ok {
- seal.container.SetEnv[shell] = s
- sh = s
- }
-
- // bind home directory
homeDir := "/var/empty"
if seal.user.home != "" {
homeDir = seal.user.home
@@ -292,27 +319,25 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
if seal.user.username != "" {
username = seal.user.username
}
- seal.container.Bind(seal.user.data, homeDir, false, true)
- seal.container.Chdir = homeDir
- seal.container.SetEnv["HOME"] = homeDir
- seal.container.SetEnv["USER"] = username
+ seal.container.Bind(seal.user.data, homeDir, sandbox.BindWritable)
+ seal.container.Dir = homeDir
+ seal.env["HOME"] = homeDir
+ seal.env["USER"] = username
- // generate /etc/passwd and /etc/group
- seal.container.CopyBind("/etc/passwd",
- []byte(username+":x:"+mapuid.String()+":"+mapuid.String()+":Fortify:"+homeDir+":"+sh+"\n"))
- seal.container.CopyBind("/etc/group",
- []byte("fortify:x:"+mapuid.String()+":\n"))
+ seal.container.Place("/etc/passwd",
+ []byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Fortify:"+homeDir+":"+shellPath+"\n"))
+ seal.container.Place("/etc/group",
+ []byte("fortify:x:"+mapgid.String()+":\n"))
/*
Display servers
*/
- // pass $TERM to launcher
+ // pass $TERM for proper terminal I/O in shell
if t, ok := sys.LookupEnv(term); ok {
- seal.container.SetEnv[term] = t
+ seal.env[term] = t
}
- // set up wayland
if config.Confinement.Enablements.Has(system.EWayland) {
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
var socketPath string
@@ -326,7 +351,7 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
}
innerPath := path.Join(innerRuntimeDir, wl.FallbackName)
- seal.container.SetEnv[wl.WaylandDisplay] = wl.FallbackName
+ seal.env[wl.WaylandDisplay] = wl.FallbackName
if !config.Confinement.Sandbox.DirectWayland { // set up security-context-v1
socketDir := path.Join(sc.SharePath, "wayland")
@@ -337,25 +362,23 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
// use instance ID in case app id is not set
appID = "uk.gensokyo.fortify." + seal.id.String()
}
- seal.sys.Wayland(&seal.bwrapSync, outerPath, socketPath, appID, seal.id.String())
- seal.container.Bind(outerPath, innerPath)
+ seal.sys.Wayland(&seal.sync, outerPath, socketPath, appID, seal.id.String())
+ seal.container.Bind(outerPath, innerPath, 0)
} else { // bind mount wayland socket (insecure)
fmsg.Verbose("direct wayland access, PROCEED WITH CAUTION")
- seal.container.Bind(socketPath, innerPath)
+ seal.container.Bind(socketPath, innerPath, 0)
seal.sys.UpdatePermType(system.EWayland, socketPath, acl.Read, acl.Write, acl.Execute)
}
}
- // set up X11
if config.Confinement.Enablements.Has(system.EX11) {
- // discover X11 and grant user permission via the `ChangeHosts` command
if d, ok := sys.LookupEnv(display); !ok {
return fmsg.WrapError(ErrXDisplay,
"DISPLAY is not set")
} else {
seal.sys.ChangeHosts("#" + seal.user.uid.String())
- seal.container.SetEnv[display] = d
- seal.container.Bind("/tmp/.X11-unix", "/tmp/.X11-unix")
+ seal.env[display] = d
+ seal.container.Bind("/tmp/.X11-unix", "/tmp/.X11-unix", 0)
}
}
@@ -396,8 +419,8 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
innerPulseRuntimeDir := path.Join(sharePathLocal, "pulse")
innerPulseSocket := path.Join(innerRuntimeDir, "pulse", "native")
seal.sys.Link(pulseSocket, innerPulseRuntimeDir)
- seal.container.Bind(innerPulseRuntimeDir, innerPulseSocket)
- seal.container.SetEnv[pulseServer] = "unix:" + innerPulseSocket
+ seal.container.Bind(innerPulseRuntimeDir, innerPulseSocket, 0)
+ seal.env[pulseServer] = "unix:" + innerPulseSocket
// publish current user's pulse cookie for target user
if src, err := discoverPulseCookie(sys); err != nil {
@@ -405,9 +428,9 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
fmsg.Verbose(strings.TrimSpace(err.(*fmsg.BaseError).Message()))
} else {
innerDst := fst.Tmp + "/pulse-cookie"
- seal.container.SetEnv[pulseCookie] = innerDst
- payload := new([]byte)
- seal.container.CopyBindRef(innerDst, &payload)
+ seal.env[pulseCookie] = innerDst
+ var payload *[]byte
+ seal.container.PlaceP(innerDst, &payload)
seal.sys.CopyFile(payload, src, 256, 256)
}
}
@@ -437,13 +460,13 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
// share proxy sockets
sessionInner := path.Join(innerRuntimeDir, "bus")
- seal.container.SetEnv[dbusSessionBusAddress] = "unix:path=" + sessionInner
- seal.container.Bind(sessionPath, sessionInner)
+ seal.env[dbusSessionBusAddress] = "unix:path=" + sessionInner
+ seal.container.Bind(sessionPath, sessionInner, 0)
seal.sys.UpdatePerm(sessionPath, acl.Read, acl.Write)
if config.Confinement.SystemBus != nil {
systemInner := "/run/dbus/system_bus_socket"
- seal.container.SetEnv[dbusSystemBusAddress] = "unix:path=" + systemInner
- seal.container.Bind(systemPath, systemInner)
+ seal.env[dbusSystemBusAddress] = "unix:path=" + systemInner
+ seal.container.Bind(systemPath, systemInner, 0)
seal.sys.UpdatePerm(systemPath, acl.Read, acl.Write)
}
}
@@ -452,9 +475,8 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
Miscellaneous
*/
- // queue overriding tmpfs at the end of seal.container.Filesystem
- for _, dest := range config.Confinement.Sandbox.Override {
- seal.container.Tmpfs(dest, 8*1024)
+ for _, dest := range config.Confinement.Sandbox.Cover {
+ seal.container.Tmpfs(dest, 1<<13, 0755)
}
// append ExtraPerms last
@@ -480,12 +502,13 @@ func (seal *outcome) finalise(sys sys.State, config *fst.Config) error {
seal.sys.UpdatePermType(system.User, p.Path, perms...)
}
- // mount fortify in sandbox for init
- seal.container.Bind(sys.MustExecutable(), path.Join(fst.Tmp, "sbin/fortify"))
- seal.container.Symlink("fortify", path.Join(fst.Tmp, "sbin/init0"))
+ // flatten and sort env for deterministic behaviour
+ seal.container.Env = make([]string, 0, len(seal.env))
+ maps.All(seal.env)(func(k string, v string) bool { seal.container.Env = append(seal.container.Env, k+"="+v); return true })
+ slices.Sort(seal.container.Env)
- fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, command: %s",
- seal.user.uid, seal.user.username, config.Confinement.Groups, config.Command)
+ fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, argv: %s",
+ seal.user.uid, seal.user.username, config.Confinement.Groups, seal.container.Args)
return nil
}
diff --git a/internal/app/shim/main.go b/internal/app/shim/main.go
index 5634be4c..17f346a2 100644
--- a/internal/app/shim/main.go
+++ b/internal/app/shim/main.go
@@ -7,18 +7,26 @@ import (
"os"
"os/exec"
"os/signal"
- "path"
- "strconv"
"syscall"
+ "time"
- "git.gensokyo.uk/security/fortify/fst"
- "git.gensokyo.uk/security/fortify/helper"
"git.gensokyo.uk/security/fortify/internal"
- "git.gensokyo.uk/security/fortify/internal/app/init0"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/sandbox"
)
+const Env = "FORTIFY_SHIM"
+
+type Params struct {
+ // finalised container params
+ Container *sandbox.Params
+ // path to outer home directory
+ Home string
+
+ // verbosity pass through
+ Verbose bool
+}
+
// everything beyond this point runs as unconstrained target user
// proceed with caution!
@@ -27,17 +35,15 @@ func Main() {
// USE WITH CAUTION
fmsg.Prepare("shim")
- // setting this prevents ptrace
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
}
- // receive setup payload
var (
- payload Payload
+ params Params
closeSetup func() error
)
- if f, err := sandbox.Receive(Env, &payload, nil); err != nil {
+ if f, err := sandbox.Receive(Env, &params, nil); err != nil {
if errors.Is(err, sandbox.ErrInvalid) {
log.Fatal("invalid config descriptor")
}
@@ -45,32 +51,26 @@ func Main() {
log.Fatal("FORTIFY_SHIM not set")
}
- log.Fatalf("cannot decode shim setup payload: %v", err)
+ log.Fatalf("cannot receive shim setup params: %v", err)
} else {
- internal.InstallFmsg(payload.Verbose)
+ internal.InstallFmsg(params.Verbose)
closeSetup = f
}
- if payload.Bwrap == nil {
- log.Fatal("bwrap config not supplied")
- }
-
- // restore bwrap sync fd
- var syncFd *os.File
- if payload.Sync != nil {
- syncFd = os.NewFile(*payload.Sync, "sync")
+ if params.Container == nil || params.Container.Ops == nil {
+ log.Fatal("invalid container params")
}
// close setup socket
if err := closeSetup(); err != nil {
- log.Println("cannot close setup pipe:", err)
+ log.Printf("cannot close setup pipe: %v", err)
// not fatal
}
// ensure home directory as target user
- if s, err := os.Stat(payload.Home); err != nil {
+ if s, err := os.Stat(params.Home); err != nil {
if os.IsNotExist(err) {
- if err = os.Mkdir(payload.Home, 0700); err != nil {
+ if err = os.Mkdir(params.Home, 0700); err != nil {
log.Fatalf("cannot create home directory: %v", err)
}
} else {
@@ -79,72 +79,37 @@ func Main() {
// home directory is created, proceed
} else if !s.IsDir() {
- log.Fatalf("data path %q is not a directory", payload.Home)
+ log.Fatalf("path %q is not a directory", params.Home)
}
- var ic init0.Payload
-
- // resolve argv0
- ic.Argv = payload.Argv
- if len(ic.Argv) > 0 {
- // looked up from $PATH by parent
- ic.Argv0 = payload.Exec[1]
- } else {
- // no argv, look up shell instead
- var ok bool
- if payload.Bwrap.SetEnv == nil {
- log.Fatal("no command was specified and environment is unset")
- }
- if ic.Argv0, ok = payload.Bwrap.SetEnv["SHELL"]; !ok {
- log.Fatal("no command was specified and $SHELL was unset")
- }
-
- ic.Argv = []string{ic.Argv0}
+ var name string
+ if len(params.Container.Args) > 0 {
+ name = params.Container.Args[0]
}
-
- conf := payload.Bwrap
-
- var extraFiles []*os.File
-
- // serve setup payload
- if fd, encoder, err := sandbox.Setup(&extraFiles); err != nil {
- log.Fatalf("cannot pipe: %v", err)
- } else {
- conf.SetEnv[init0.Env] = strconv.Itoa(fd)
- go func() {
- fmsg.Verbose("transmitting config to init")
- if err = encoder.Encode(&ic); err != nil {
- log.Fatalf("cannot transmit init config: %v", err)
- }
- }()
- }
-
- helper.BubblewrapName = payload.Exec[0] // resolved bwrap path by parent
-
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop() // unreachable
- if b, err := helper.NewBwrap(
- ctx, path.Join(fst.Tmp, "sbin/init0"),
- nil, false,
- func(int, int) []string { return make([]string, 0) },
- func(cmd *exec.Cmd) { cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr },
- extraFiles,
- conf, syncFd,
- ); err != nil {
- log.Fatalf("malformed sandbox config: %v", err)
- } else {
- // run and pass through exit code
- if err = b.Start(); err != nil {
- log.Fatalf("cannot start target process: %v", err)
- } else if err = b.Wait(); err != nil {
- var exitError *exec.ExitError
- if !errors.As(err, &exitError) {
- log.Printf("wait: %v", err)
- internal.Exit(127)
- panic("unreachable")
+ container := sandbox.New(ctx, name)
+ container.Params = *params.Container
+ container.Stdin, container.Stdout, container.Stderr = os.Stdin, os.Stdout, os.Stderr
+ container.Cancel = func(cmd *exec.Cmd) error { return cmd.Process.Signal(os.Interrupt) }
+ container.WaitDelay = 2 * time.Second
+
+ if err := container.Start(); err != nil {
+ fmsg.PrintBaseError(err, "cannot start container:")
+ os.Exit(1)
+ }
+ if err := container.Serve(); err != nil {
+ fmsg.PrintBaseError(err, "cannot configure container:")
+ }
+ if err := container.Wait(); err != nil {
+ var exitError *exec.ExitError
+ if !errors.As(err, &exitError) {
+ if errors.Is(err, context.Canceled) {
+ os.Exit(2)
}
- internal.Exit(exitError.ExitCode())
- panic("unreachable")
+ log.Printf("wait: %v", err)
+ os.Exit(127)
}
+ os.Exit(exitError.ExitCode())
}
}
diff --git a/internal/app/shim/payload.go b/internal/app/shim/payload.go
deleted file mode 100644
index e659e3fd..00000000
--- a/internal/app/shim/payload.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package shim
-
-import (
- "git.gensokyo.uk/security/fortify/helper/bwrap"
-)
-
-const Env = "FORTIFY_SHIM"
-
-type Payload struct {
- // child full argv
- Argv []string
- // bwrap, target full exec path
- Exec [2]string
- // bwrap config
- Bwrap *bwrap.Config
- // path to outer home directory
- Home string
- // sync fd
- Sync *uintptr
-
- // verbosity pass through
- Verbose bool
-}
diff --git a/internal/app/shim/manager.go b/internal/app/shim/proc.go
index 4ed75e53..8c73e697 100644
--- a/internal/app/shim/manager.go
+++ b/internal/app/shim/proc.go
@@ -8,9 +8,9 @@ import (
"os/exec"
"strconv"
"strings"
+ "syscall"
"time"
- "git.gensokyo.uk/security/fortify/helper/proc"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/sandbox"
@@ -25,10 +25,11 @@ type Shim struct {
killFallback chan error
// monitor to shim encoder
encoder *gob.Encoder
- // bwrap --sync-fd value
- sync *uintptr
}
+func (s *Shim) Unwrap() *exec.Cmd { return s.cmd }
+func (s *Shim) Fallback() chan error { return s.killFallback }
+
func (s *Shim) String() string {
if s.cmd == nil {
return "(unused shim manager)"
@@ -36,21 +37,9 @@ func (s *Shim) String() string {
return s.cmd.String()
}
-func (s *Shim) Unwrap() *exec.Cmd {
- return s.cmd
-}
-
-func (s *Shim) WaitFallback() chan error {
- return s.killFallback
-}
-
func (s *Shim) Start(
- // string representation of application id
aid string,
- // string representation of supplementary group ids
supp []string,
- // bwrap --sync-fd
- syncFd *os.File,
) (*time.Time, error) {
// prepare user switcher invocation
fsuPath := internal.MustFsuPath()
@@ -76,12 +65,6 @@ func (s *Shim) Start(
s.cmd.Stdin, s.cmd.Stdout, s.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
s.cmd.Dir = "/"
- // pass sync fd if set
- if syncFd != nil {
- fd := proc.ExtraFile(s.cmd, syncFd)
- s.sync = &fd
- }
-
fmsg.Verbose("starting shim via fsu:", s.cmd)
// withhold messages to stderr
fmsg.Suspend()
@@ -90,10 +73,11 @@ func (s *Shim) Start(
"cannot start fsu:")
}
startTime := time.Now().UTC()
+
return &startTime, nil
}
-func (s *Shim) Serve(ctx context.Context, payload *Payload) error {
+func (s *Shim) Serve(ctx context.Context, params *Params) error {
// kill shim if something goes wrong and an error is returned
s.killFallback = make(chan error, 1)
killShim := func() {
@@ -103,9 +87,8 @@ func (s *Shim) Serve(ctx context.Context, payload *Payload) error {
}
defer func() { killShim() }()
- payload.Sync = s.sync
encodeErr := make(chan error)
- go func() { encodeErr <- s.encoder.Encode(payload) }()
+ go func() { encodeErr <- s.encoder.Encode(params) }()
select {
// encode return indicates setup completion
@@ -121,11 +104,11 @@ func (s *Shim) Serve(ctx context.Context, payload *Payload) error {
case <-ctx.Done():
err := ctx.Err()
if errors.Is(err, context.Canceled) {
- return fmsg.WrapError(errors.New("shim setup canceled"),
+ return fmsg.WrapError(syscall.ECANCELED,
"shim setup canceled")
}
if errors.Is(err, context.DeadlineExceeded) {
- return fmsg.WrapError(errors.New("deadline exceeded waiting for shim"),
+ return fmsg.WrapError(syscall.ETIMEDOUT,
"deadline exceeded waiting for shim")
}
// unreachable