treewide: rename to hakurei
All checks were successful
Test / Create distribution (push) Successful in 43s
Test / Sandbox (push) Successful in 2m18s
Test / Hakurei (push) Successful in 3m10s
Test / Sandbox (race detector) (push) Successful in 3m30s
Test / Hakurei (race detector) (push) Successful in 4m43s
Test / Fpkg (push) Successful in 5m4s
Test / Flake checks (push) Successful in 1m12s

Fortify makes little sense for a container tool.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-06-25 03:59:52 +09:00
parent 3992073212
commit 87e008d56d
137 changed files with 1044 additions and 1098 deletions

View File

@@ -5,7 +5,7 @@ import (
"syscall"
"time"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/hakurei/hst"
)
type App interface {
@@ -14,7 +14,7 @@ type App interface {
// Seal determines the outcome of config as a [SealedApp].
// The value of config might be overwritten and must not be used again.
Seal(config *fst.Config) (SealedApp, error)
Seal(config *hst.Config) (SealedApp, error)
String() string
}
@@ -48,12 +48,12 @@ func (rs *RunState) SetStart() {
rs.Time = &now
}
// Paths contains environment-dependent paths used by fortify.
// Paths contains environment-dependent paths used by hakurei.
type Paths struct {
// path to shared directory (usually `/tmp/fortify.%d`)
// path to shared directory (usually `/tmp/hakurei.%d`)
SharePath string `json:"share_path"`
// XDG_RUNTIME_DIR value (usually `/run/user/%d`)
RuntimePath string `json:"runtime_path"`
// application runtime directory (usually `/run/user/%d/fortify`)
// application runtime directory (usually `/run/user/%d/hakurei`)
RunDirPath string `json:"run_dir_path"`
}

View File

@@ -4,7 +4,7 @@ import (
"errors"
"testing"
. "git.gensokyo.uk/security/fortify/internal/app"
. "git.gensokyo.uk/security/hakurei/internal/app"
)
func TestParseAppID(t *testing.T) {

View File

@@ -8,20 +8,20 @@ import (
"path"
"syscall"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/sys"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
)
// in practice there should be less than 30 entries added by the runtime;
// allocating slightly more as a margin for future expansion
const preallocateOpsCount = 1 << 5
// NewContainer initialises [sandbox.Params] via [fst.ContainerConfig].
// NewContainer initialises [sandbox.Params] via [hst.ContainerConfig].
// Note that remaining container setup must be queued by the caller.
func NewContainer(s *fst.ContainerConfig, os sys.State, uid, gid *int) (*sandbox.Params, map[string]string, error) {
func NewContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*sandbox.Params, map[string]string, error) {
if s == nil {
return nil, nil, syscall.EBADE
}
@@ -67,7 +67,7 @@ func NewContainer(s *fst.ContainerConfig, os sys.State, uid, gid *int) (*sandbox
container.
Proc("/proc").
Tmpfs(fst.Tmp, 1<<12, 0755)
Tmpfs(hst.Tmp, 1<<12, 0755)
if !s.Device {
container.Dev("/dev").Mqueue("/dev/mqueue")

View File

@@ -3,8 +3,8 @@ package instance
import (
"syscall"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
)
func PrintRunStateErr(whence int, rs *app.RunState, runErr error) (code int) {

View File

@@ -6,9 +6,9 @@ import (
"log"
"syscall"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
"git.gensokyo.uk/security/fortify/internal/sys"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
"git.gensokyo.uk/security/hakurei/internal/sys"
)
const (

View File

@@ -1,6 +1,6 @@
package instance
import "git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
import "git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
func ShimMain() { setuid.ShimMain() }

View File

@@ -5,10 +5,10 @@ import (
"fmt"
"sync"
"git.gensokyo.uk/security/fortify/fst"
. "git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/sys"
"git.gensokyo.uk/security/hakurei/hst"
. "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/internal/sys"
)
func New(ctx context.Context, os sys.State) (App, error) {
@@ -52,7 +52,7 @@ func (a *app) String() string {
return fmt.Sprintf("(unsealed app %s)", a.id)
}
func (a *app) Seal(config *fst.Config) (SealedApp, error) {
func (a *app) Seal(config *hst.Config) (SealedApp, error) {
a.mu.Lock()
defer a.mu.Unlock()
@@ -60,7 +60,7 @@ func (a *app) Seal(config *fst.Config) (SealedApp, error) {
panic("app sealed twice")
}
if config == nil {
return nil, fmsg.WrapError(ErrConfig,
return nil, hlog.WrapErr(ErrConfig,
"attempted to seal app with nil config")
}

View File

@@ -1,25 +1,25 @@
package setuid_test
import (
"git.gensokyo.uk/security/fortify/acl"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/acl"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/system"
)
var testCasesNixos = []sealTestCase{
{
"nixos chromium direct wayland", new(stubNixOS),
&fst.Config{
&hst.Config{
ID: "org.chromium.Chromium",
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
Enablements: system.EWayland | system.EDBus | system.EPulse,
Container: &fst.ContainerConfig{
Container: &hst.ContainerConfig{
Userns: true, Net: true, MapRealUID: true, Env: nil, AutoEtc: true,
Filesystem: []*fst.FilesystemConfig{
Filesystem: []*hst.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"},
@@ -48,7 +48,7 @@ var testCasesNixos = []sealTestCase{
DirectWayland: true,
Username: "u0_a1",
Data: "/var/lib/persist/module/fortify/0/1",
Data: "/var/lib/persist/module/hakurei/0/1",
Identity: 1, Groups: []string{},
},
app.ID{
@@ -58,19 +58,19 @@ var testCasesNixos = []sealTestCase{
0xb4, 0x6e, 0xb5, 0xc1,
},
system.New(1000001).
Ensure("/tmp/fortify.1971", 0711).
Ensure("/tmp/fortify.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime", acl.Execute).
Ensure("/tmp/fortify.1971/runtime/1", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime/1", acl.Read, acl.Write, acl.Execute).
Ensure("/tmp/fortify.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir", acl.Execute).
Ensure("/tmp/fortify.1971/tmpdir/1", 01700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir/1", acl.Read, acl.Write, acl.Execute).
Ensure("/run/user/1971/fortify", 0700).UpdatePermType(system.User, "/run/user/1971/fortify", acl.Execute).
Ensure("/tmp/hakurei.1971", 0711).
Ensure("/tmp/hakurei.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime", acl.Execute).
Ensure("/tmp/hakurei.1971/runtime/1", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime/1", acl.Read, acl.Write, acl.Execute).
Ensure("/tmp/hakurei.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir", acl.Execute).
Ensure("/tmp/hakurei.1971/tmpdir/1", 01700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir/1", acl.Read, acl.Write, acl.Execute).
Ensure("/run/user/1971/hakurei", 0700).UpdatePermType(system.User, "/run/user/1971/hakurei", acl.Execute).
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
UpdatePermType(system.EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute).
Ephemeral(system.Process, "/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1", 0700).UpdatePermType(system.Process, "/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1", acl.Execute).
Link("/run/user/1971/pulse/native", "/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1/pulse").
Ephemeral(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", 0700).UpdatePermType(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", acl.Execute).
Link("/run/user/1971/pulse/native", "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse").
CopyFile(nil, "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
Ephemeral(system.Process, "/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1", 0711).
MustProxyDBus("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", &dbus.Config{
Ephemeral(system.Process, "/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1", 0711).
MustProxyDBus("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", &dbus.Config{
Talk: []string{
"org.freedesktop.FileManager1", "org.freedesktop.Notifications",
"org.freedesktop.ScreenSaver", "org.freedesktop.secrets",
@@ -83,7 +83,7 @@ var testCasesNixos = []sealTestCase{
},
Call: map[string]string{}, Broadcast: map[string]string{},
Filter: true,
}, "/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", &dbus.Config{
}, "/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", &dbus.Config{
Talk: []string{
"org.bluez",
"org.freedesktop.Avahi",
@@ -91,20 +91,20 @@ var testCasesNixos = []sealTestCase{
},
Filter: true,
}).
UpdatePerm("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", acl.Read, acl.Write).
UpdatePerm("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", acl.Read, acl.Write),
UpdatePerm("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", acl.Read, acl.Write).
UpdatePerm("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", acl.Read, acl.Write),
&sandbox.Params{
Uid: 1971,
Gid: 100,
Flags: sandbox.FAllowNet | sandbox.FAllowUserns,
Dir: "/var/lib/persist/module/fortify/0/1",
Dir: "/var/lib/persist/module/hakurei/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",
"HOME=/var/lib/persist/module/hakurei/0/1",
"PULSE_COOKIE=" + hst.Tmp + "/pulse-cookie",
"PULSE_SERVER=unix:/run/user/1971/pulse/native",
"SHELL=/run/current-system/sw/bin/zsh",
"TERM=xterm-256color",
@@ -116,7 +116,7 @@ var testCasesNixos = []sealTestCase{
},
Ops: new(sandbox.Ops).
Proc("/proc").
Tmpfs(fst.Tmp, 4096, 0755).
Tmpfs(hst.Tmp, 4096, 0755).
Dev("/dev").Mqueue("/dev/mqueue").
Bind("/bin", "/bin", 0).
Bind("/usr/bin", "/usr/bin", 0).
@@ -131,16 +131,16 @@ var testCasesNixos = []sealTestCase{
Bind("/dev/dri", "/dev/dri", sandbox.BindDevice|sandbox.BindWritable|sandbox.BindOptional).
Etc("/etc", "8e2c76b066dabe574cf073bdb46eb5c1").
Tmpfs("/run/user", 4096, 0755).
Bind("/tmp/fortify.1971/runtime/1", "/run/user/1971", sandbox.BindWritable).
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("/tmp/hakurei.1971/runtime/1", "/run/user/1971", sandbox.BindWritable).
Bind("/tmp/hakurei.1971/tmpdir/1", "/tmp", sandbox.BindWritable).
Bind("/var/lib/persist/module/hakurei/0/1", "/var/lib/persist/module/hakurei/0/1", sandbox.BindWritable).
Place("/etc/passwd", []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
Place("/etc/group", []byte("hakurei: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).
Bind("/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse", "/run/user/1971/pulse/native", 0).
Place(hst.Tmp+"/pulse-cookie", nil).
Bind("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", "/run/user/1971/bus", 0).
Bind("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", "/run/dbus/system_bus_socket", 0).
Tmpfs("/var/run/nscd", 8192, 0755),
},
},

View File

@@ -3,18 +3,18 @@ package setuid_test
import (
"os"
"git.gensokyo.uk/security/fortify/acl"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/acl"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/system"
)
var testCasesPd = []sealTestCase{
{
"nixos permissive defaults no enablements", new(stubNixOS),
&fst.Config{Username: "chronos", Data: "/home/chronos"},
&hst.Config{Username: "chronos", Data: "/home/chronos"},
app.ID{
0x4a, 0x45, 0x0b, 0x65,
0x96, 0xd7, 0xbc, 0x15,
@@ -22,11 +22,11 @@ var testCasesPd = []sealTestCase{
0xb9, 0xa6, 0x07, 0xac,
},
system.New(1000000).
Ensure("/tmp/fortify.1971", 0711).
Ensure("/tmp/fortify.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime", acl.Execute).
Ensure("/tmp/fortify.1971/runtime/0", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime/0", acl.Read, acl.Write, 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),
Ensure("/tmp/hakurei.1971", 0711).
Ensure("/tmp/hakurei.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime", acl.Execute).
Ensure("/tmp/hakurei.1971/runtime/0", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime/0", acl.Read, acl.Write, acl.Execute).
Ensure("/tmp/hakurei.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir", acl.Execute).
Ensure("/tmp/hakurei.1971/tmpdir/0", 01700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir/0", acl.Read, acl.Write, acl.Execute),
&sandbox.Params{
Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
Dir: "/home/chronos",
@@ -43,7 +43,7 @@ var testCasesPd = []sealTestCase{
},
Ops: new(sandbox.Ops).
Proc("/proc").
Tmpfs(fst.Tmp, 4096, 0755).
Tmpfs(hst.Tmp, 4096, 0755).
Dev("/dev").Mqueue("/dev/mqueue").
Bind("/bin", "/bin", sandbox.BindWritable).
Bind("/boot", "/boot", sandbox.BindWritable).
@@ -62,17 +62,17 @@ var testCasesPd = []sealTestCase{
Tmpfs("/run/dbus", 8192, 0755).
Etc("/etc", "4a450b6596d7bc15bd01780eb9a607ac").
Tmpfs("/run/user", 4096, 0755).
Bind("/tmp/fortify.1971/runtime/0", "/run/user/65534", sandbox.BindWritable).
Bind("/tmp/fortify.1971/tmpdir/0", "/tmp", sandbox.BindWritable).
Bind("/tmp/hakurei.1971/runtime/0", "/run/user/65534", sandbox.BindWritable).
Bind("/tmp/hakurei.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")).
Place("/etc/passwd", []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
Place("/etc/group", []byte("hakurei:x:65534:\n")).
Tmpfs("/var/run/nscd", 8192, 0755),
},
},
{
"nixos permissive defaults chromium", new(stubNixOS),
&fst.Config{
&hst.Config{
ID: "org.chromium.Chromium",
Args: []string{"zsh", "-c", "exec chromium "},
Identity: 9,
@@ -119,19 +119,19 @@ var testCasesPd = []sealTestCase{
0x9b, 0x64, 0xce, 0x7c,
},
system.New(1000009).
Ensure("/tmp/fortify.1971", 0711).
Ensure("/tmp/fortify.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime", acl.Execute).
Ensure("/tmp/fortify.1971/runtime/9", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime/9", acl.Read, acl.Write, acl.Execute).
Ensure("/tmp/fortify.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir", acl.Execute).
Ensure("/tmp/fortify.1971/tmpdir/9", 01700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir/9", acl.Read, acl.Write, acl.Execute).
Ephemeral(system.Process, "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c", 0711).
Wayland(new(*os.File), "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/1971/wayland-0", "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
Ensure("/run/user/1971/fortify", 0700).UpdatePermType(system.User, "/run/user/1971/fortify", acl.Execute).
Ensure("/tmp/hakurei.1971", 0711).
Ensure("/tmp/hakurei.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime", acl.Execute).
Ensure("/tmp/hakurei.1971/runtime/9", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime/9", acl.Read, acl.Write, acl.Execute).
Ensure("/tmp/hakurei.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir", acl.Execute).
Ensure("/tmp/hakurei.1971/tmpdir/9", 01700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir/9", acl.Read, acl.Write, acl.Execute).
Ephemeral(system.Process, "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c", 0711).
Wayland(new(*os.File), "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/1971/wayland-0", "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
Ensure("/run/user/1971/hakurei", 0700).UpdatePermType(system.User, "/run/user/1971/hakurei", acl.Execute).
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
Ephemeral(system.Process, "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c", 0700).UpdatePermType(system.Process, "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c", acl.Execute).
Link("/run/user/1971/pulse/native", "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/pulse").
Ephemeral(system.Process, "/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c", 0700).UpdatePermType(system.Process, "/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c", acl.Execute).
Link("/run/user/1971/pulse/native", "/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c/pulse").
CopyFile(new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
MustProxyDBus("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", &dbus.Config{
MustProxyDBus("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", &dbus.Config{
Talk: []string{
"org.freedesktop.Notifications",
"org.freedesktop.FileManager1",
@@ -153,7 +153,7 @@ var testCasesPd = []sealTestCase{
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*",
},
Filter: true,
}, "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", &dbus.Config{
}, "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", &dbus.Config{
Talk: []string{
"org.bluez",
"org.freedesktop.Avahi",
@@ -161,8 +161,8 @@ var testCasesPd = []sealTestCase{
},
Filter: true,
}).
UpdatePerm("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", acl.Read, acl.Write).
UpdatePerm("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", acl.Read, acl.Write),
UpdatePerm("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", acl.Read, acl.Write).
UpdatePerm("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", acl.Read, acl.Write),
&sandbox.Params{
Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
Dir: "/home/chronos",
@@ -172,7 +172,7 @@ var testCasesPd = []sealTestCase{
"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_COOKIE=" + hst.Tmp + "/pulse-cookie",
"PULSE_SERVER=unix:/run/user/65534/pulse/native",
"SHELL=/run/current-system/sw/bin/zsh",
"TERM=xterm-256color",
@@ -184,7 +184,7 @@ var testCasesPd = []sealTestCase{
},
Ops: new(sandbox.Ops).
Proc("/proc").
Tmpfs(fst.Tmp, 4096, 0755).
Tmpfs(hst.Tmp, 4096, 0755).
Dev("/dev").Mqueue("/dev/mqueue").
Bind("/bin", "/bin", sandbox.BindWritable).
Bind("/boot", "/boot", sandbox.BindWritable).
@@ -204,16 +204,16 @@ var testCasesPd = []sealTestCase{
Tmpfs("/run/dbus", 8192, 0755).
Etc("/etc", "ebf083d1b175911782d413369b64ce7c").
Tmpfs("/run/user", 4096, 0755).
Bind("/tmp/fortify.1971/runtime/9", "/run/user/65534", sandbox.BindWritable).
Bind("/tmp/fortify.1971/tmpdir/9", "/tmp", sandbox.BindWritable).
Bind("/tmp/hakurei.1971/runtime/9", "/run/user/65534", sandbox.BindWritable).
Bind("/tmp/hakurei.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/ebf083d1b175911782d413369b64ce7c/wayland", "/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).
Place("/etc/passwd", []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
Place("/etc/group", []byte("hakurei:x:65534:\n")).
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/65534/wayland-0", 0).
Bind("/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c/pulse", "/run/user/65534/pulse/native", 0).
Place(hst.Tmp+"/pulse-cookie", nil).
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", "/run/user/65534/bus", 0).
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", "/run/dbus/system_bus_socket", 0).
Tmpfs("/var/run/nscd", 8192, 0755),
},
},

View File

@@ -7,7 +7,7 @@ import (
"os/user"
"strconv"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/hakurei/internal/app"
)
// fs methods are not implemented using a real FS
@@ -20,7 +20,7 @@ type stubNixOS struct {
func (s *stubNixOS) Getuid() int { return 1971 }
func (s *stubNixOS) Getgid() int { return 100 }
func (s *stubNixOS) TempDir() string { return "/tmp" }
func (s *stubNixOS) MustExecutable() string { return "/run/wrappers/bin/fortify" }
func (s *stubNixOS) MustExecutable() string { return "/run/wrappers/bin/hakurei" }
func (s *stubNixOS) Exit(code int) { panic("called exit on stub with code " + strconv.Itoa(code)) }
func (s *stubNixOS) EvalSymlinks(path string) (string, error) { return path, nil }
func (s *stubNixOS) Uid(aid int) (int, error) { return 1000000 + 0*10000 + aid, nil }
@@ -127,8 +127,8 @@ func (s *stubNixOS) Open(name string) (fs.File, error) {
func (s *stubNixOS) Paths() app.Paths {
return app.Paths{
SharePath: "/tmp/fortify.1971",
SharePath: "/tmp/hakurei.1971",
RuntimePath: "/run/user/1971",
RunDirPath: "/run/user/1971/fortify",
RunDirPath: "/run/user/1971/hakurei",
}
}

View File

@@ -7,18 +7,18 @@ import (
"testing"
"time"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
"git.gensokyo.uk/security/fortify/internal/sys"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
"git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/system"
)
type sealTestCase struct {
name string
os sys.State
config *fst.Config
config *hst.Config
id app.ID
wantSys *system.I
wantContainer *sandbox.Params
@@ -80,70 +80,25 @@ func stubDirEntries(names ...string) (e []fs.DirEntry, err error) {
type stubDirEntryPath string
func (p stubDirEntryPath) Name() string {
return string(p)
}
func (p stubDirEntryPath) IsDir() bool {
panic("attempted to call IsDir")
}
func (p stubDirEntryPath) Type() fs.FileMode {
panic("attempted to call Type")
}
func (p stubDirEntryPath) Info() (fs.FileInfo, error) {
panic("attempted to call Info")
}
func (p stubDirEntryPath) Name() string { return string(p) }
func (p stubDirEntryPath) IsDir() bool { panic("attempted to call IsDir") }
func (p stubDirEntryPath) Type() fs.FileMode { panic("attempted to call Type") }
func (p stubDirEntryPath) Info() (fs.FileInfo, error) { panic("attempted to call Info") }
type stubFileInfoMode fs.FileMode
func (s stubFileInfoMode) Name() string {
panic("attempted to call Name")
}
func (s stubFileInfoMode) Size() int64 {
panic("attempted to call Size")
}
func (s stubFileInfoMode) Mode() fs.FileMode {
return fs.FileMode(s)
}
func (s stubFileInfoMode) ModTime() time.Time {
panic("attempted to call ModTime")
}
func (s stubFileInfoMode) IsDir() bool {
panic("attempted to call IsDir")
}
func (s stubFileInfoMode) Sys() any {
panic("attempted to call Sys")
}
func (s stubFileInfoMode) Name() string { panic("attempted to call Name") }
func (s stubFileInfoMode) Size() int64 { panic("attempted to call Size") }
func (s stubFileInfoMode) Mode() fs.FileMode { return fs.FileMode(s) }
func (s stubFileInfoMode) ModTime() time.Time { panic("attempted to call ModTime") }
func (s stubFileInfoMode) IsDir() bool { panic("attempted to call IsDir") }
func (s stubFileInfoMode) Sys() any { panic("attempted to call Sys") }
type stubFileInfoIsDir bool
func (s stubFileInfoIsDir) Name() string {
panic("attempted to call Name")
}
func (s stubFileInfoIsDir) Size() int64 {
panic("attempted to call Size")
}
func (s stubFileInfoIsDir) Mode() fs.FileMode {
panic("attempted to call Mode")
}
func (s stubFileInfoIsDir) ModTime() time.Time {
panic("attempted to call ModTime")
}
func (s stubFileInfoIsDir) IsDir() bool {
return bool(s)
}
func (s stubFileInfoIsDir) Sys() any {
panic("attempted to call Sys")
}
func (s stubFileInfoIsDir) Name() string { panic("attempted to call Name") }
func (s stubFileInfoIsDir) Size() int64 { panic("attempted to call Size") }
func (s stubFileInfoIsDir) Mode() fs.FileMode { panic("attempted to call Mode") }
func (s stubFileInfoIsDir) ModTime() time.Time { panic("attempted to call ModTime") }
func (s stubFileInfoIsDir) IsDir() bool { return bool(s) }
func (s stubFileInfoIsDir) Sys() any { panic("attempted to call Sys") }

View File

@@ -4,8 +4,8 @@ import (
"errors"
"log"
. "git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg"
. "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/hlog"
)
func PrintRunStateErr(rs *RunState, runErr error) (code int) {
@@ -13,10 +13,10 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
if runErr != nil {
if rs.Time == nil {
fmsg.PrintBaseError(runErr, "cannot start app:")
hlog.PrintBaseError(runErr, "cannot start app:")
} else {
var e *fmsg.BaseError
if !fmsg.AsBaseError(runErr, &e) {
var e *hlog.BaseError
if !hlog.AsBaseError(runErr, &e) {
log.Println("wait failed:", runErr)
} else {
// Wait only returns either *app.ProcessError or *app.StateStoreError wrapped in a *app.BaseError
@@ -37,7 +37,7 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
// every error here is wrapped in *app.BaseError
for _, ei := range errs {
var eb *fmsg.BaseError
var eb *hlog.BaseError
if !errors.As(ei, &eb) {
// unreachable
log.Println("invalid error type returned by revert:", ei)
@@ -59,7 +59,7 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
if rs.RevertErr != nil {
var stateStoreError *StateStoreError
if !errors.As(rs.RevertErr, &stateStoreError) || stateStoreError == nil {
fmsg.PrintBaseError(rs.RevertErr, "generic fault during cleanup:")
hlog.PrintBaseError(rs.RevertErr, "generic fault during cleanup:")
goto out
}
@@ -67,11 +67,11 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
if len(stateStoreError.Err) == 2 {
if stateStoreError.Err[0] != nil {
if joinedErrs, ok := stateStoreError.Err[0].(interface{ Unwrap() []error }); !ok {
fmsg.PrintBaseError(stateStoreError.Err[0], "generic fault during revert:")
hlog.PrintBaseError(stateStoreError.Err[0], "generic fault during revert:")
} else {
for _, err := range joinedErrs.Unwrap() {
if err != nil {
fmsg.PrintBaseError(err, "fault during revert:")
hlog.PrintBaseError(err, "fault during revert:")
}
}
}
@@ -91,11 +91,11 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
}
if stateStoreError.DoErr != nil {
fmsg.PrintBaseError(stateStoreError.DoErr, "state store operation unsuccessful:")
hlog.PrintBaseError(stateStoreError.DoErr, "state store operation unsuccessful:")
}
if stateStoreError.Inner && stateStoreError.InnerErr != nil {
fmsg.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:")
hlog.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:")
}
out:
@@ -104,7 +104,7 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
}
}
if rs.WaitErr != nil {
fmsg.Verbosef("wait: %v", rs.WaitErr)
hlog.Verbosef("wait: %v", rs.WaitErr)
}
return
}
@@ -135,7 +135,7 @@ func (e *StateStoreError) equiv(a ...any) error {
if e.Inner && e.InnerErr == nil && e.DoErr == nil && e.OpErr == nil && errors.Join(e.Err...) == nil {
return nil
} else {
return fmsg.WrapErrorSuffix(e, a...)
return hlog.WrapErrSuffix(e, a...)
}
}

View File

@@ -1,10 +1,10 @@
package setuid
import (
. "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"
. "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/system"
)
func NewWithID(id ID, os sys.State) App {

View File

@@ -12,12 +12,12 @@ import (
"syscall"
"time"
"git.gensokyo.uk/security/fortify/internal"
. "git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/internal"
. "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/internal/state"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/system"
)
const shimWaitTimeout = 5 * time.Second
@@ -35,7 +35,7 @@ func (seal *outcome) Run(rs *RunState) error {
}
// read comp value early to allow for early failure
fsuPath := internal.MustFsuPath()
hsuPath := internal.MustHsuPath()
if err := seal.sys.Commit(seal.ctx); err != nil {
return err
@@ -59,7 +59,7 @@ func (seal *outcome) Run(rs *RunState) error {
if l := len(states); l == 0 {
ec |= system.User
} else {
fmsg.Verbosef("found %d instances, cleaning up without user-scoped operations", l)
hlog.Verbosef("found %d instances, cleaning up without user-scoped operations", l)
}
// accumulate enablements of remaining launchers
@@ -72,9 +72,9 @@ func (seal *outcome) Run(rs *RunState) error {
}
}
ec |= rt ^ (system.EWayland | system.EX11 | system.EDBus | system.EPulse)
if fmsg.Load() {
if hlog.Load() {
if ec > 0 {
fmsg.Verbose("reverting operations scope", system.TypeString(ec))
hlog.Verbose("reverting operations scope", system.TypeString(ec))
}
}
@@ -87,7 +87,7 @@ func (seal *outcome) Run(rs *RunState) error {
ctx, cancel := context.WithCancel(seal.ctx)
defer cancel()
cmd := exec.CommandContext(ctx, fsuPath)
cmd := exec.CommandContext(ctx, hsuPath)
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
cmd.Dir = "/" // container init enters final working directory
// shim runs in the same session as monitor; see shim.go for behaviour
@@ -95,28 +95,28 @@ func (seal *outcome) Run(rs *RunState) error {
var e *gob.Encoder
if fd, encoder, err := sandbox.Setup(&cmd.ExtraFiles); err != nil {
return fmsg.WrapErrorSuffix(err,
return hlog.WrapErrSuffix(err,
"cannot create shim setup pipe:")
} else {
e = encoder
cmd.Env = []string{
// passed through to shim by fsu
// passed through to shim by hsu
shimEnv + "=" + strconv.Itoa(fd),
// interpreted by fsu
"FORTIFY_APP_ID=" + seal.user.aid.String(),
// interpreted by hsu
"HAKUREI_APP_ID=" + seal.user.aid.String(),
}
}
if len(seal.user.supp) > 0 {
fmsg.Verbosef("attaching supplementary group ids %s", seal.user.supp)
// interpreted by fsu
cmd.Env = append(cmd.Env, "FORTIFY_GROUPS="+strings.Join(seal.user.supp, " "))
hlog.Verbosef("attaching supplementary group ids %s", seal.user.supp)
// interpreted by hsu
cmd.Env = append(cmd.Env, "HAKUREI_GROUPS="+strings.Join(seal.user.supp, " "))
}
fmsg.Verbosef("setuid helper at %s", fsuPath)
fmsg.Suspend()
hlog.Verbosef("setuid helper at %s", hsuPath)
hlog.Suspend()
if err := cmd.Start(); err != nil {
return fmsg.WrapErrorSuffix(err,
return hlog.WrapErrSuffix(err,
"cannot start setuid wrapper:")
}
rs.SetStart()
@@ -124,19 +124,19 @@ func (seal *outcome) Run(rs *RunState) error {
// this prevents blocking forever on an early failure
waitErr, setupErr := make(chan error, 1), make(chan error, 1)
go func() { waitErr <- cmd.Wait(); cancel() }()
go func() { setupErr <- e.Encode(&shimParams{os.Getpid(), seal.container, seal.user.data, fmsg.Load()}) }()
go func() { setupErr <- e.Encode(&shimParams{os.Getpid(), seal.container, seal.user.data, hlog.Load()}) }()
select {
case err := <-setupErr:
if err != nil {
fmsg.Resume()
return fmsg.WrapErrorSuffix(err,
hlog.Resume()
return hlog.WrapErrSuffix(err,
"cannot transmit shim config:")
}
case <-ctx.Done():
fmsg.Resume()
return fmsg.WrapError(syscall.ECANCELED,
hlog.Resume()
return hlog.WrapErr(syscall.ECANCELED,
"shim setup canceled")
}
@@ -163,25 +163,25 @@ func (seal *outcome) Run(rs *RunState) error {
select {
case rs.WaitErr = <-waitErr:
rs.WaitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
if fmsg.Load() {
if hlog.Load() {
switch {
case rs.Exited():
fmsg.Verbosef("process %d exited with code %d", cmd.Process.Pid, rs.ExitStatus())
hlog.Verbosef("process %d exited with code %d", cmd.Process.Pid, rs.ExitStatus())
case rs.CoreDump():
fmsg.Verbosef("process %d dumped core", cmd.Process.Pid)
hlog.Verbosef("process %d dumped core", cmd.Process.Pid)
case rs.Signaled():
fmsg.Verbosef("process %d got %s", cmd.Process.Pid, rs.Signal())
hlog.Verbosef("process %d got %s", cmd.Process.Pid, rs.Signal())
default:
fmsg.Verbosef("process %d exited with status %#x", cmd.Process.Pid, rs.WaitStatus)
hlog.Verbosef("process %d exited with status %#x", cmd.Process.Pid, rs.WaitStatus)
}
}
case <-waitTimeout:
rs.WaitErr = syscall.ETIMEDOUT
fmsg.Resume()
hlog.Resume()
log.Printf("process %d did not terminate", cmd.Process.Pid)
}
fmsg.Resume()
hlog.Resume()
if seal.sync != nil {
if err := seal.sync.Close(); err != nil {
log.Printf("cannot close wayland security context: %v", err)

View File

@@ -16,17 +16,17 @@ import (
"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/internal"
. "git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/instance/common"
"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/sandbox/wl"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/acl"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal"
. "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/app/instance/common"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/sandbox/wl"
"git.gensokyo.uk/security/hakurei/system"
)
const (
@@ -63,20 +63,20 @@ var (
var posixUsername = regexp.MustCompilePOSIX("^[a-z_]([A-Za-z0-9_-]{0,31}|[A-Za-z0-9_-]{0,30}\\$)$")
// outcome stores copies of various parts of [fst.Config]
// outcome stores copies of various parts of [hst.Config]
type outcome struct {
// copied from initialising [app]
id *stringPair[ID]
// copied from [sys.State] response
runDirPath string
// initial [fst.Config] gob stream for state data;
// initial [hst.Config] gob stream for state data;
// 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
user hsuUser
sys *system.I
ctx context.Context
@@ -89,7 +89,7 @@ type outcome struct {
// shareHost holds optional share directory state that must not be accessed directly
type shareHost struct {
// whether XDG_RUNTIME_DIR is used post fsu
// whether XDG_RUNTIME_DIR is used post hsu
useRuntimeDir bool
// process-specific directory in tmpdir, empty if unused
sharePath string
@@ -134,8 +134,8 @@ func (share *shareHost) runtime() string {
return share.runtimeSharePath
}
// fsuUser stores post-fsu credentials and metadata
type fsuUser struct {
// hsuUser stores post-hsu credentials and metadata
type hsuUser struct {
// application id
aid *stringPair[int]
// target uid resolved by fid:aid
@@ -152,7 +152,7 @@ type fsuUser struct {
username string
}
func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Config) error {
func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Config) error {
if seal.ctx != nil {
panic("finalise called twice")
}
@@ -162,19 +162,19 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
// encode initial configuration for state tracking
ct := new(bytes.Buffer)
if err := gob.NewEncoder(ct).Encode(config); err != nil {
return fmsg.WrapErrorSuffix(err,
return hlog.WrapErrSuffix(err,
"cannot encode initial config:")
}
seal.ct = ct
}
// allowed aid range 0 to 9999, this is checked again in fsu
// allowed aid range 0 to 9999, this is checked again in hsu
if config.Identity < 0 || config.Identity > 9999 {
return fmsg.WrapError(ErrUser,
return hlog.WrapErr(ErrUser,
fmt.Sprintf("identity %d out of range", config.Identity))
}
seal.user = fsuUser{
seal.user = hsuUser{
aid: newInt(config.Identity),
data: config.Data,
home: config.Dir,
@@ -184,11 +184,11 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
seal.user.username = "chronos"
} else if !posixUsername.MatchString(seal.user.username) ||
len(seal.user.username) >= internal.Sysconf_SC_LOGIN_NAME_MAX() {
return fmsg.WrapError(ErrName,
return hlog.WrapErr(ErrName,
fmt.Sprintf("invalid user name %q", seal.user.username))
}
if seal.user.data == "" || !path.IsAbs(seal.user.data) {
return fmsg.WrapError(ErrHome,
return hlog.WrapErr(ErrHome,
fmt.Sprintf("invalid home directory %q", seal.user.data))
}
if seal.user.home == "" {
@@ -202,7 +202,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
seal.user.supp = make([]string, len(config.Groups))
for i, name := range config.Groups {
if g, err := sys.LookupGroup(name); err != nil {
return fmsg.WrapError(err,
return hlog.WrapErr(err,
fmt.Sprintf("unknown group %q", name))
} else {
seal.user.supp[i] = g.Gid
@@ -220,13 +220,13 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
// permissive defaults
if config.Container == nil {
fmsg.Verbose("container configuration not supplied, PROCEED WITH CAUTION")
hlog.Verbose("container configuration not supplied, PROCEED WITH CAUTION")
// fsu clears the environment so resolve paths early
// hsu 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())
return hlog.WrapErr(err, err.Error())
} else {
config.Path = p
}
@@ -235,7 +235,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
}
}
conf := &fst.ContainerConfig{
conf := &hst.ContainerConfig{
Userns: true,
Net: true,
Tty: true,
@@ -245,7 +245,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
if d, err := sys.ReadDir("/"); err != nil {
return err
} else {
b := make([]*fst.FilesystemConfig, 0, len(d))
b := make([]*hst.FilesystemConfig, 0, len(d))
for _, ent := range d {
p := "/" + ent.Name()
switch p {
@@ -256,7 +256,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
case "/etc":
default:
b = append(b, &fst.FilesystemConfig{Src: p, Write: true, Must: true})
b = append(b, &hst.FilesystemConfig{Src: p, Write: true, Must: true})
}
}
conf.Filesystem = append(conf.Filesystem, b...)
@@ -269,10 +269,10 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
}
// bind GPU stuff
if config.Enablements&(system.EX11|system.EWayland) != 0 {
conf.Filesystem = append(conf.Filesystem, &fst.FilesystemConfig{Src: "/dev/dri", Device: true})
conf.Filesystem = append(conf.Filesystem, &hst.FilesystemConfig{Src: "/dev/dri", Device: true})
}
// opportunistically bind kvm
conf.Filesystem = append(conf.Filesystem, &fst.FilesystemConfig{Src: "/dev/kvm", Device: true})
conf.Filesystem = append(conf.Filesystem, &hst.FilesystemConfig{Src: "/dev/kvm", Device: true})
config.Container = conf
}
@@ -283,11 +283,11 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
var err error
seal.container, seal.env, err = common.NewContainer(config.Container, sys, &uid, &gid)
if err != nil {
return fmsg.WrapErrorSuffix(err,
return hlog.WrapErrSuffix(err,
"cannot initialise container configuration:")
}
if !path.IsAbs(config.Path) {
return fmsg.WrapError(syscall.EINVAL,
return hlog.WrapErr(syscall.EINVAL,
"invalid program path")
}
if len(config.Args) == 0 {
@@ -364,9 +364,9 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
seal.env[shell] = config.Shell
seal.container.Place("/etc/passwd",
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Fortify:"+homeDir+":"+config.Shell+"\n"))
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Hakurei:"+homeDir+":"+config.Shell+"\n"))
seal.container.Place("/etc/group",
[]byte("fortify:x:"+mapgid.String()+":\n"))
[]byte("hakurei:x:"+mapgid.String()+":\n"))
}
// pass TERM for proper terminal I/O in initial process
@@ -378,7 +378,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
var socketPath string
if name, ok := sys.LookupEnv(wl.WaylandDisplay); !ok {
fmsg.Verbose(wl.WaylandDisplay + " is not set, assuming " + wl.FallbackName)
hlog.Verbose(wl.WaylandDisplay + " is not set, assuming " + wl.FallbackName)
socketPath = path.Join(share.sc.RuntimePath, wl.FallbackName)
} else if !path.IsAbs(name) {
socketPath = path.Join(share.sc.RuntimePath, name)
@@ -393,14 +393,14 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
appID := config.ID
if appID == "" {
// use instance ID in case app id is not set
appID = "uk.gensokyo.fortify." + seal.id.String()
appID = "uk.gensokyo.hakurei." + seal.id.String()
}
// downstream socket paths
outerPath := path.Join(share.instance(), "wayland")
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")
hlog.Verbose("direct wayland access, PROCEED WITH CAUTION")
share.ensureRuntimeDir()
seal.container.Bind(socketPath, innerPath, 0)
seal.sys.UpdatePermType(system.EWayland, socketPath, acl.Read, acl.Write, acl.Execute)
@@ -409,7 +409,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
if config.Enablements&system.EX11 != 0 {
if d, ok := sys.LookupEnv(display); !ok {
return fmsg.WrapError(ErrXDisplay,
return hlog.WrapErr(ErrXDisplay,
"DISPLAY is not set")
} else {
seal.sys.ChangeHosts("#" + seal.user.uid.String())
@@ -426,23 +426,23 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
if _, err := sys.Stat(pulseRuntimeDir); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return fmsg.WrapErrorSuffix(err,
return hlog.WrapErrSuffix(err,
fmt.Sprintf("cannot access PulseAudio directory %q:", pulseRuntimeDir))
}
return fmsg.WrapError(ErrPulseSocket,
return hlog.WrapErr(ErrPulseSocket,
fmt.Sprintf("PulseAudio directory %q not found", pulseRuntimeDir))
}
if s, err := sys.Stat(pulseSocket); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return fmsg.WrapErrorSuffix(err,
return hlog.WrapErrSuffix(err,
fmt.Sprintf("cannot access PulseAudio socket %q:", pulseSocket))
}
return fmsg.WrapError(ErrPulseSocket,
return hlog.WrapErr(ErrPulseSocket,
fmt.Sprintf("PulseAudio directory %q found but socket does not exist", pulseRuntimeDir))
} else {
if m := s.Mode(); m&0o006 != 0o006 {
return fmsg.WrapError(ErrPulseMode,
return hlog.WrapErr(ErrPulseMode,
fmt.Sprintf("unexpected permissions on %q:", pulseSocket), m)
}
}
@@ -457,9 +457,9 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
// publish current user's pulse cookie for target user
if src, err := discoverPulseCookie(sys); err != nil {
// not fatal
fmsg.Verbose(strings.TrimSpace(err.(*fmsg.BaseError).Message()))
hlog.Verbose(strings.TrimSpace(err.(*hlog.BaseError).Message()))
} else {
innerDst := fst.Tmp + "/pulse-cookie"
innerDst := hst.Tmp + "/pulse-cookie"
seal.env[pulseCookie] = innerDst
var payload *[]byte
seal.container.PlaceP(innerDst, &payload)
@@ -531,15 +531,15 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
seal.container.Env = make([]string, 0, len(seal.env))
for k, v := range seal.env {
if strings.IndexByte(k, '=') != -1 {
return fmsg.WrapError(syscall.EINVAL,
return hlog.WrapErr(syscall.EINVAL,
fmt.Sprintf("invalid environment variable %s", k))
}
seal.container.Env = append(seal.container.Env, k+"="+v)
}
slices.Sort(seal.container.Env)
if fmsg.Load() {
fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, argv: %s, ops: %d",
if hlog.Load() {
hlog.Verbosef("created application seal for uid %s (%s) groups: %v, argv: %s, ops: %d",
seal.user.uid, seal.user.username, config.Groups, seal.container.Args, len(*seal.container.Ops))
}
@@ -557,7 +557,7 @@ func discoverPulseCookie(sys sys.State) (string, error) {
p = path.Join(p, ".pulse-cookie")
if s, err := sys.Stat(p); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return p, fmsg.WrapErrorSuffix(err,
return p, hlog.WrapErrSuffix(err,
fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
}
// not found, try next method
@@ -571,7 +571,7 @@ func discoverPulseCookie(sys sys.State) (string, error) {
p = path.Join(p, "pulse", "cookie")
if s, err := sys.Stat(p); err != nil {
if !errors.Is(err, fs.ErrNotExist) {
return p, fmsg.WrapErrorSuffix(err,
return p, hlog.WrapErrSuffix(err,
fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
}
// not found, try next method
@@ -580,7 +580,7 @@ func discoverPulseCookie(sys sys.State) (string, error) {
}
}
return "", fmsg.WrapError(ErrPulseCookie,
return "", hlog.WrapErr(ErrPulseCookie,
fmt.Sprintf("cannot locate PulseAudio cookie (tried $%s, $%s/pulse/cookie, $%s/.pulse-cookie)",
pulseCookie, xdgConfigHome, home))
}

View File

@@ -10,10 +10,10 @@ import (
"syscall"
"time"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
"git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
)
/*
@@ -23,10 +23,10 @@ import (
#include <errno.h>
#include <signal.h>
static pid_t f_shim_param_ppid = -1;
static pid_t hakurei_shim_param_ppid = -1;
// this cannot unblock fmsg since Go code is not async-signal-safe
static void f_shim_sigaction(int sig, siginfo_t *si, void *ucontext) {
// this cannot unblock hlog since Go code is not async-signal-safe
static void hakurei_shim_sigaction(int sig, siginfo_t *si, void *ucontext) {
if (sig != SIGCONT || si == NULL) {
// unreachable
fprintf(stderr, "sigaction: sa_sigaction got invalid siginfo\n");
@@ -34,17 +34,17 @@ static void f_shim_sigaction(int sig, siginfo_t *si, void *ucontext) {
}
// monitor requests shim exit
if (si->si_pid == f_shim_param_ppid)
if (si->si_pid == hakurei_shim_param_ppid)
exit(254);
fprintf(stderr, "sigaction: got SIGCONT from process %d\n", si->si_pid);
// shim orphaned before monitor delivers a signal
if (getppid() != f_shim_param_ppid)
if (getppid() != hakurei_shim_param_ppid)
exit(3);
}
void f_shim_setup_cont_signal(pid_t ppid) {
void hakurei_shim_setup_cont_signal(pid_t ppid) {
struct sigaction new_action = {0}, old_action = {0};
if (sigaction(SIGCONT, NULL, &old_action) != 0)
return;
@@ -53,7 +53,7 @@ void f_shim_setup_cont_signal(pid_t ppid) {
return;
}
new_action.sa_sigaction = f_shim_sigaction;
new_action.sa_sigaction = hakurei_shim_sigaction;
if (sigemptyset(&new_action.sa_mask) != 0)
return;
new_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
@@ -62,12 +62,12 @@ void f_shim_setup_cont_signal(pid_t ppid) {
return;
errno = 0;
f_shim_param_ppid = ppid;
hakurei_shim_param_ppid = ppid;
}
*/
import "C"
const shimEnv = "FORTIFY_SHIM"
const shimEnv = "HAKUREI_SHIM"
type shimParams struct {
// monitor pid, checked against ppid in signal handler
@@ -84,7 +84,7 @@ type shimParams struct {
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
func ShimMain() {
fmsg.Prepare("shim")
hlog.Prepare("shim")
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
@@ -99,7 +99,7 @@ func ShimMain() {
log.Fatal("invalid config descriptor")
}
if errors.Is(err, sandbox.ErrNotSet) {
log.Fatal("FORTIFY_SHIM not set")
log.Fatal("HAKUREI_SHIM not set")
}
log.Fatalf("cannot receive shim setup params: %v", err)
@@ -108,7 +108,7 @@ func ShimMain() {
closeSetup = f
// the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
if _, err = C.f_shim_setup_cont_signal(C.pid_t(params.Monitor)); err != nil {
if _, err = C.hakurei_shim_setup_cont_signal(C.pid_t(params.Monitor)); err != nil {
log.Fatalf("cannot install SIGCONT handler: %v", err)
}
@@ -156,11 +156,11 @@ func ShimMain() {
container.WaitDelay = 2 * time.Second
if err := container.Start(); err != nil {
fmsg.PrintBaseError(err, "cannot start container:")
hlog.PrintBaseError(err, "cannot start container:")
os.Exit(1)
}
if err := container.Serve(); err != nil {
fmsg.PrintBaseError(err, "cannot configure container:")
hlog.PrintBaseError(err, "cannot configure container:")
}
if err := seccomp.Load(seccomp.PresetCommon); err != nil {

View File

@@ -3,7 +3,7 @@ package setuid
import (
"strconv"
. "git.gensokyo.uk/security/fortify/internal/app"
. "git.gensokyo.uk/security/hakurei/internal/app"
)
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }

View File

@@ -3,7 +3,7 @@ package internal
import (
"os"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/hakurei/internal/hlog"
)
func Exit(code int) { fmsg.BeforeExit(); os.Exit(code) }
func Exit(code int) { hlog.BeforeExit(); os.Exit(code) }

View File

@@ -1,4 +1,4 @@
package fmsg
package hlog
import (
"fmt"
@@ -12,13 +12,8 @@ type baseError struct {
Err error
}
func (e *baseError) Error() string {
return e.Err.Error()
}
func (e *baseError) Unwrap() error {
return e.Err
}
func (e *baseError) Error() string { return e.Err.Error() }
func (e *baseError) Unwrap() error { return e.Err }
// BaseError implements an error container with a user-facing message
type BaseError struct {
@@ -27,35 +22,33 @@ type BaseError struct {
}
// Message returns a user-facing error message
func (e *BaseError) Message() string {
return e.message
}
func (e *BaseError) Message() string { return e.message }
// WrapError wraps an error with a corresponding message.
func WrapError(err error, a ...any) error {
// WrapErr wraps an error with a corresponding message.
func WrapErr(err error, a ...any) error {
if err == nil {
return nil
}
return wrapError(err, fmt.Sprintln(a...))
return wrapErr(err, fmt.Sprintln(a...))
}
// WrapErrorSuffix wraps an error with a corresponding message with err at the end of the message.
func WrapErrorSuffix(err error, a ...any) error {
// WrapErrSuffix wraps an error with a corresponding message with err at the end of the message.
func WrapErrSuffix(err error, a ...any) error {
if err == nil {
return nil
}
return wrapError(err, fmt.Sprintln(append(a, err)...))
return wrapErr(err, fmt.Sprintln(append(a, err)...))
}
// WrapErrorFunc wraps an error with a corresponding message returned by f.
func WrapErrorFunc(err error, f func(err error) string) error {
// WrapErrFunc wraps an error with a corresponding message returned by f.
func WrapErrFunc(err error, f func(err error) string) error {
if err == nil {
return nil
}
return wrapError(err, f(err))
return wrapErr(err, f(err))
}
func wrapError(err error, message string) *BaseError {
func wrapErr(err error, message string) *BaseError {
return &BaseError{message, baseError{err}}
}

View File

@@ -1,5 +1,5 @@
// Package fmsg provides various functions for output messages.
package fmsg
// Package hlog provides various functions for output messages.
package hlog
import (
"bytes"

View File

@@ -1,11 +1,11 @@
package fmsg
package hlog
type Output struct{}
func (Output) IsVerbose() bool { return Load() }
func (Output) Verbose(v ...any) { Verbose(v...) }
func (Output) Verbosef(format string, v ...any) { Verbosef(format, v...) }
func (Output) WrapErr(err error, a ...any) error { return WrapError(err, a...) }
func (Output) WrapErr(err error, a ...any) error { return WrapErr(err, a...) }
func (Output) PrintBaseErr(err error, fallback string) { PrintBaseError(err, fallback) }
func (Output) Suspend() { Suspend() }
func (Output) Resume() bool { return Resume() }

View File

@@ -1,4 +1,4 @@
package fmsg
package hlog
import (
"log"

View File

@@ -1,17 +1,17 @@
package internal
import (
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
"git.gensokyo.uk/security/hakurei/system"
)
func InstallFmsg(verbose bool) {
fmsg.Store(verbose)
sandbox.SetOutput(fmsg.Output{})
system.SetOutput(fmsg.Output{})
hlog.Store(verbose)
sandbox.SetOutput(hlog.Output{})
system.SetOutput(hlog.Output{})
if verbose {
seccomp.SetOutput(fmsg.Verbose)
seccomp.SetOutput(hlog.Verbose)
}
}

View File

@@ -4,19 +4,19 @@ import (
"log"
"path"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/hakurei/internal/hlog"
)
var (
fsu = compPoison
hsu = compPoison
)
func MustFsuPath() string {
if name, ok := checkPath(fsu); ok {
func MustHsuPath() string {
if name, ok := checkPath(hsu); ok {
return name
}
fmsg.BeforeExit()
log.Fatal("invalid fsu path, this program is compiled incorrectly")
hlog.BeforeExit()
log.Fatal("invalid hsu path, this program is compiled incorrectly")
return compPoison
}

View File

@@ -13,9 +13,9 @@ import (
"sync"
"syscall"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/hlog"
)
// fine-grained locking and access
@@ -86,17 +86,17 @@ func (s *multiStore) List() ([]int, error) {
for _, e := range entries {
// skip non-directories
if !e.IsDir() {
fmsg.Verbosef("skipped non-directory entry %q", e.Name())
hlog.Verbosef("skipped non-directory entry %q", e.Name())
continue
}
// skip non-numerical names
if v, err := strconv.Atoi(e.Name()); err != nil {
fmsg.Verbosef("skipped non-aid entry %q", e.Name())
hlog.Verbosef("skipped non-aid entry %q", e.Name())
continue
} else {
if v < 0 || v > 9999 {
fmsg.Verbosef("skipped out of bounds entry %q", e.Name())
hlog.Verbosef("skipped out of bounds entry %q", e.Name())
continue
}
@@ -232,7 +232,7 @@ func (b *multiBackend) load(decode bool) (Entries, error) {
}
// state file consists of an eight byte header, followed by concatenated gobs
// of [fst.Config] and [State], if [State.Config] is not nil or offset < 0,
// of [hst.Config] and [State], if [State.Config] is not nil or offset < 0,
// the first gob is skipped
func (b *multiBackend) decodeState(r io.ReadSeeker, state *State) error {
offset := make([]byte, 8)
@@ -269,7 +269,7 @@ func (b *multiBackend) decodeState(r io.ReadSeeker, state *State) error {
return ErrNoConfig
}
state.Config = new(fst.Config)
state.Config = new(hst.Config)
if _, err := r.Seek(8, io.SeekStart); err != nil {
return err
}

View File

@@ -3,7 +3,7 @@ package state_test
import (
"testing"
"git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/hakurei/internal/state"
)
func TestMulti(t *testing.T) {

View File

@@ -5,8 +5,8 @@ import (
"io"
"time"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
)
var ErrNoConfig = errors.New("state does not contain config")
@@ -35,14 +35,14 @@ type Cursor interface {
Len() (int, error)
}
// State is a fortify process's state
// State is an instance state
type State struct {
// fortify instance id
// hakurei instance id
ID app.ID `json:"instance"`
// child process PID value
PID int `json:"pid"`
// sealed app configuration
Config *fst.Config `json:"config"`
Config *hst.Config `json:"config"`
// process start time
Time time.Time `json:"time"`

View File

@@ -10,9 +10,9 @@ import (
"testing"
"time"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/state"
)
func testStore(t *testing.T, s state.Store) {
@@ -63,7 +63,7 @@ func testStore(t *testing.T, s state.Store) {
&tc[i].state.ID)
} else {
got.Time = tc[i].state.Time
tc[i].state.Config = fst.Template()
tc[i].state.Config = hst.Template()
if !reflect.DeepEqual(got, &tc[i].state) {
t.Fatalf("Load: entry %s got %#v, want %#v",
&tc[i].state.ID, got, &tc[i].state)
@@ -137,7 +137,7 @@ func makeState(t *testing.T, s *state.State, ct io.Writer) {
if err := app.NewAppID(&s.ID); err != nil {
t.Fatalf("cannot create dummy state: %v", err)
}
if err := gob.NewEncoder(ct).Encode(fst.Template()); err != nil {
if err := gob.NewEncoder(ct).Encode(hst.Template()); err != nil {
t.Fatalf("cannot encode dummy config: %v", err)
}
s.PID = rand.Int()

View File

@@ -6,8 +6,8 @@ import (
"path"
"strconv"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/hlog"
)
// State provides safe interaction with operating system state.
@@ -42,25 +42,25 @@ type State interface {
// Paths returns a populated [Paths] struct.
Paths() app.Paths
// Uid invokes fsu and returns target uid.
// Uid invokes hsu and returns target uid.
// Any errors returned by Uid is already wrapped [fmsg.BaseError].
Uid(aid int) (int, error)
}
// CopyPaths is a generic implementation of [fst.Paths].
// CopyPaths is a generic implementation of [hst.Paths].
func CopyPaths(os State, v *app.Paths) {
v.SharePath = path.Join(os.TempDir(), "fortify."+strconv.Itoa(os.Getuid()))
v.SharePath = path.Join(os.TempDir(), "hakurei."+strconv.Itoa(os.Getuid()))
fmsg.Verbosef("process share directory at %q", v.SharePath)
hlog.Verbosef("process share directory at %q", v.SharePath)
if r, ok := os.LookupEnv(xdgRuntimeDir); !ok || r == "" || !path.IsAbs(r) {
// fall back to path in share since fortify has no hard XDG dependency
// fall back to path in share since hakurei has no hard XDG dependency
v.RunDirPath = path.Join(v.SharePath, "run")
v.RuntimePath = path.Join(v.RunDirPath, "compat")
} else {
v.RuntimePath = r
v.RunDirPath = path.Join(v.RuntimePath, "fortify")
v.RunDirPath = path.Join(v.RuntimePath, "hakurei")
}
fmsg.Verbosef("runtime directory at %q", v.RunDirPath)
hlog.Verbosef("runtime directory at %q", v.RunDirPath)
}

View File

@@ -12,10 +12,10 @@ import (
"sync"
"syscall"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/sandbox"
)
// Std implements System using the standard library.
@@ -43,8 +43,8 @@ func (s *Std) Stat(name string) (fs.FileInfo, error) { return os.Stat(nam
func (s *Std) Open(name string) (fs.File, error) { return os.Open(name) }
func (s *Std) EvalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }
func (s *Std) Exit(code int) { internal.Exit(code) }
func (s *Std) Println(v ...any) { fmsg.Verbose(v...) }
func (s *Std) Printf(format string, v ...any) { fmsg.Verbosef(format, v...) }
func (s *Std) Println(v ...any) { hlog.Verbose(v...) }
func (s *Std) Printf(format string, v ...any) { hlog.Verbosef(format, v...) }
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
@@ -80,12 +80,12 @@ func (s *Std) Uid(aid int) (int, error) {
defer func() { s.uidCopy[aid] = u }()
u.uid = -1
fsuPath := internal.MustFsuPath()
hsuPath := internal.MustHsuPath()
cmd := exec.Command(fsuPath)
cmd.Path = fsuPath
cmd := exec.Command(hsuPath)
cmd.Path = hsuPath
cmd.Stderr = os.Stderr // pass through fatal messages
cmd.Env = []string{"FORTIFY_APP_ID=" + strconv.Itoa(aid)}
cmd.Env = []string{"HAKUREI_APP_ID=" + strconv.Itoa(aid)}
cmd.Dir = "/"
var (
p []byte
@@ -95,12 +95,12 @@ func (s *Std) Uid(aid int) (int, error) {
if p, u.err = cmd.Output(); u.err == nil {
u.uid, u.err = strconv.Atoi(string(p))
if u.err != nil {
u.err = fmsg.WrapErrorSuffix(u.err, "cannot parse uid from fsu:")
u.err = hlog.WrapErrSuffix(u.err, "cannot parse uid from hsu:")
}
} else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
u.err = fmsg.WrapError(syscall.EACCES, "") // fsu prints to stderr in this case
u.err = hlog.WrapErr(syscall.EACCES, "") // hsu prints to stderr in this case
} else if os.IsNotExist(u.err) {
u.err = fmsg.WrapError(os.ErrNotExist, fmt.Sprintf("the setuid helper is missing: %s", fsuPath))
u.err = hlog.WrapErr(os.ErrNotExist, fmt.Sprintf("the setuid helper is missing: %s", hsuPath))
}
return u.uid, u.err
}