diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-03-25 01:52:49 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-03-25 01:52:49 +0900 |
| commit | 5c4058d5ac7e7944973ca8216c258fc50c194e22 (patch) | |
| tree | c06597903233c75eca5a1edae8b06d93f0f81774 /internal | |
| parent | e732dca7629edb503df0c65df5f37a99600d567d (diff) | |
app: run in native sandbox
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/app/app.go | 11 | ||||
| -rw-r--r-- | internal/app/app_nixos_test.go | 267 | ||||
| -rw-r--r-- | internal/app/app_pd_test.go | 516 | ||||
| -rw-r--r-- | internal/app/app_stub_test.go | 6 | ||||
| -rw-r--r-- | internal/app/app_test.go | 28 | ||||
| -rw-r--r-- | internal/app/export_test.go | 4 | ||||
| -rw-r--r-- | internal/app/init0/early.go | 18 | ||||
| -rw-r--r-- | internal/app/init0/main.go | 165 | ||||
| -rw-r--r-- | internal/app/init0/payload.go | 13 | ||||
| -rw-r--r-- | internal/app/process.go | 50 | ||||
| -rw-r--r-- | internal/app/seal.go | 181 | ||||
| -rw-r--r-- | internal/app/shim/main.go | 129 | ||||
| -rw-r--r-- | internal/app/shim/payload.go | 23 | ||||
| -rw-r--r-- | internal/app/shim/proc.go (renamed from internal/app/shim/manager.go) | 35 | ||||
| -rw-r--r-- | internal/state/state_test.go | 2 |
15 files changed, 582 insertions, 866 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, ¶ms, 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 diff --git a/internal/state/state_test.go b/internal/state/state_test.go index ee2a88cc..22fd3cd6 100644 --- a/internal/state/state_test.go +++ b/internal/state/state_test.go @@ -96,7 +96,7 @@ func testStore(t *testing.T, s state.Store) { } else { slices.Sort(aids) want := []int{0, 1} - if slices.Compare(aids, want) != 0 { + if !slices.Equal(aids, want) { t.Fatalf("List() = %#v, want %#v", aids, want) } } |
