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:
Ophestra 2025-06-25 03:59:52 +09:00
parent 3992073212
commit 87e008d56d
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
137 changed files with 1044 additions and 1098 deletions

View File

@ -20,5 +20,5 @@ jobs:
uses: https://gitea.com/actions/release-action@main uses: https://gitea.com/actions/release-action@main
with: with:
files: |- files: |-
result/fortify-** result/hakurei-**
api_key: '${{secrets.RELEASE_TOKEN}}' api_key: '${{secrets.RELEASE_TOKEN}}'

View File

@ -5,25 +5,25 @@ on:
- pull_request - pull_request
jobs: jobs:
fortify: hakurei:
name: Fortify name: Hakurei
runs-on: nix runs-on: nix
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
- name: Run NixOS test - name: Run NixOS test
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.fortify run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.hakurei
- name: Upload test output - name: Upload test output
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: "fortify-vm-output" name: "hakurei-vm-output"
path: result/* path: result/*
retention-days: 1 retention-days: 1
race: race:
name: Fortify (race detector) name: Hakurei (race detector)
runs-on: nix runs-on: nix
steps: steps:
- name: Checkout - name: Checkout
@ -35,7 +35,7 @@ jobs:
- name: Upload test output - name: Upload test output
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: "fortify-race-vm-output" name: "hakurei-race-vm-output"
path: result/* path: result/*
retention-days: 1 retention-days: 1
@ -93,7 +93,7 @@ jobs:
check: check:
name: Flake checks name: Flake checks
needs: needs:
- fortify - hakurei
- race - race
- sandbox - sandbox
- sandbox-race - sandbox-race
@ -116,15 +116,15 @@ jobs:
- name: Build for test - name: Build for test
id: build-test id: build-test
run: >- run: >-
export FORTIFY_REV="$(git rev-parse --short HEAD)" && export HAKUREI_REV="$(git rev-parse --short HEAD)" &&
sed -i.old 's/version = /version = "0.0.0-'$FORTIFY_REV'"; # version = /' package.nix && sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' package.nix &&
nix build --print-out-paths --print-build-logs .#dist && nix build --print-out-paths --print-build-logs .#dist &&
mv package.nix.old package.nix && mv package.nix.old package.nix &&
echo "rev=$FORTIFY_REV" >> $GITHUB_OUTPUT echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
- name: Upload test build - name: Upload test build
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: "fortify-${{ steps.build-test.outputs.rev }}" name: "hakurei-${{ steps.build-test.outputs.rev }}"
path: result/* path: result/*
retention-days: 1 retention-days: 1

4
.gitignore vendored
View File

@ -5,7 +5,7 @@
*.so *.so
*.dylib *.dylib
*.pkg *.pkg
/fortify /hakurei
# Test binary, built with `go test -c` # Test binary, built with `go test -c`
*.test *.test
@ -29,4 +29,4 @@ go.work.sum
security-context-v1-protocol.* security-context-v1-protocol.*
# release # release
/dist/fortify-* /dist/hakurei-*

View File

@ -1,8 +1,8 @@
Fortify Hakurei
======= =======
[![Go Reference](https://pkg.go.dev/badge/git.gensokyo.uk/security/fortify.svg)](https://pkg.go.dev/git.gensokyo.uk/security/fortify) [![Go Reference](https://pkg.go.dev/badge/git.gensokyo.uk/security/hakurei.svg)](https://pkg.go.dev/git.gensokyo.uk/security/hakurei)
[![Go Report Card](https://goreportcard.com/badge/git.gensokyo.uk/security/fortify)](https://goreportcard.com/report/git.gensokyo.uk/security/fortify) [![Go Report Card](https://goreportcard.com/badge/git.gensokyo.uk/security/hakurei)](https://goreportcard.com/report/git.gensokyo.uk/security/hakurei)
Lets you run graphical applications as another user in a confined environment with a nice NixOS Lets you run graphical applications as another user in a confined environment with a nice NixOS
module to configure target users and provide launchers and desktop files for your privileged user. module to configure target users and provide launchers and desktop files for your privileged user.
@ -18,7 +18,7 @@ Why would you want this?
If you have a flakes-enabled nix environment, you can try out the tool by running: If you have a flakes-enabled nix environment, you can try out the tool by running:
```shell ```shell
nix run git+https://git.gensokyo.uk/security/fortify -- help nix run git+https://git.gensokyo.uk/security/hakurei -- help
``` ```
## Module usage ## Module usage
@ -34,35 +34,35 @@ To use the module, import it into your configuration with
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
fortify = { hakurei = {
url = "git+https://git.gensokyo.uk/security/fortify"; url = "git+https://git.gensokyo.uk/security/hakurei";
# Optional but recommended to limit the size of your system closure. # Optional but recommended to limit the size of your system closure.
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
}; };
outputs = { self, nixpkgs, fortify, ... }: outputs = { self, nixpkgs, hakurei, ... }:
{ {
nixosConfigurations.fortify = nixpkgs.lib.nixosSystem { nixosConfigurations.hakurei = nixpkgs.lib.nixosSystem {
system = "x86_64-linux"; system = "x86_64-linux";
modules = [ modules = [
fortify.nixosModules.fortify hakurei.nixosModules.hakurei
]; ];
}; };
}; };
} }
``` ```
This adds the `environment.fortify` option: This adds the `environment.hakurei` option:
```nix ```nix
{ pkgs, ... }: { pkgs, ... }:
{ {
environment.fortify = { environment.hakurei = {
enable = true; enable = true;
stateDir = "/var/lib/fortify"; stateDir = "/var/lib/hakurei";
users = { users = {
alice = 0; alice = 0;
nixos = 10; nixos = 10;

View File

@ -4,7 +4,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <sys/acl.h> #include <sys/acl.h>
int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms, int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
size_t plen) { size_t plen) {
int ret = -1; int ret = -1;
bool v; bool v;

View File

@ -1,4 +1,4 @@
#include <sys/acl.h> #include <sys/acl.h>
int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms, int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
size_t plen); size_t plen);

View File

@ -23,7 +23,7 @@ func Update(name string, uid int, perms ...Perm) error {
p = &perms[0] p = &perms[0]
} }
r, err := C.f_acl_update_file_by_uid( r, err := C.hakurei_acl_update_file_by_uid(
C.CString(name), C.CString(name),
C.uid_t(uid), C.uid_t(uid),
(*C.acl_perm_t)(p), (*C.acl_perm_t)(p),

View File

@ -7,7 +7,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"git.gensokyo.uk/security/fortify/acl" "git.gensokyo.uk/security/hakurei/acl"
) )
const testFileName = "acl.test" const testFileName = "acl.test"

View File

@ -6,46 +6,46 @@ import (
"os" "os"
"path" "path"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
"git.gensokyo.uk/security/fortify/system" "git.gensokyo.uk/security/hakurei/system"
) )
type appInfo struct { type appInfo struct {
Name string `json:"name"` Name string `json:"name"`
Version string `json:"version"` Version string `json:"version"`
// passed through to [fst.Config] // passed through to [hst.Config]
ID string `json:"id"` ID string `json:"id"`
// passed through to [fst.Config] // passed through to [hst.Config]
Identity int `json:"identity"` Identity int `json:"identity"`
// passed through to [fst.Config] // passed through to [hst.Config]
Groups []string `json:"groups,omitempty"` Groups []string `json:"groups,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
Devel bool `json:"devel,omitempty"` Devel bool `json:"devel,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
Userns bool `json:"userns,omitempty"` Userns bool `json:"userns,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
Net bool `json:"net,omitempty"` Net bool `json:"net,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
Device bool `json:"dev,omitempty"` Device bool `json:"dev,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
Tty bool `json:"tty,omitempty"` Tty bool `json:"tty,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
MapRealUID bool `json:"map_real_uid,omitempty"` MapRealUID bool `json:"map_real_uid,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
DirectWayland bool `json:"direct_wayland,omitempty"` DirectWayland bool `json:"direct_wayland,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
SystemBus *dbus.Config `json:"system_bus,omitempty"` SystemBus *dbus.Config `json:"system_bus,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
SessionBus *dbus.Config `json:"session_bus,omitempty"` SessionBus *dbus.Config `json:"session_bus,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
Enablements system.Enablement `json:"enablements"` Enablements system.Enablement `json:"enablements"`
// passed through to [fst.Config] // passed through to [hst.Config]
Multiarch bool `json:"multiarch,omitempty"` Multiarch bool `json:"multiarch,omitempty"`
// passed through to [fst.Config] // passed through to [hst.Config]
Bluetooth bool `json:"bluetooth,omitempty"` Bluetooth bool `json:"bluetooth,omitempty"`
// allow gpu access within sandbox // allow gpu access within sandbox
@ -62,8 +62,8 @@ type appInfo struct {
ActivationPackage string `json:"activation_package"` ActivationPackage string `json:"activation_package"`
} }
func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool) *fst.Config { func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool) *hst.Config {
config := &fst.Config{ config := &hst.Config{
ID: app.ID, ID: app.ID,
Path: argv[0], Path: argv[0],
@ -75,7 +75,7 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
SessionBus: app.SessionBus, SessionBus: app.SessionBus,
DirectWayland: app.DirectWayland, DirectWayland: app.DirectWayland,
Username: "fortify", Username: "hakurei",
Shell: shellPath, Shell: shellPath,
Data: pathSet.homeDir, Data: pathSet.homeDir,
Dir: path.Join("/data/data", app.ID), Dir: path.Join("/data/data", app.ID),
@ -83,7 +83,7 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
Identity: app.Identity, Identity: app.Identity,
Groups: app.Groups, Groups: app.Groups,
Container: &fst.ContainerConfig{ Container: &hst.ContainerConfig{
Hostname: formatHostname(app.Name), Hostname: formatHostname(app.Name),
Devel: app.Devel, Devel: app.Devel,
Userns: app.Userns, Userns: app.Userns,
@ -91,9 +91,9 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
Device: app.Device, Device: app.Device,
Tty: app.Tty || flagDropShell, Tty: app.Tty || flagDropShell,
MapRealUID: app.MapRealUID, MapRealUID: app.MapRealUID,
Filesystem: []*fst.FilesystemConfig{ Filesystem: []*hst.FilesystemConfig{
{Src: path.Join(pathSet.nixPath, "store"), Dst: "/nix/store", Must: true}, {Src: path.Join(pathSet.nixPath, "store"), Dst: "/nix/store", Must: true},
{Src: pathSet.metaPath, Dst: path.Join(fst.Tmp, "app"), Must: true}, {Src: pathSet.metaPath, Dst: path.Join(hst.Tmp, "app"), Must: true},
{Src: "/etc/resolv.conf"}, {Src: "/etc/resolv.conf"},
{Src: "/sys/block"}, {Src: "/sys/block"},
{Src: "/sys/bus"}, {Src: "/sys/bus"},
@ -109,7 +109,7 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
Etc: path.Join(pathSet.cacheDir, "etc"), Etc: path.Join(pathSet.cacheDir, "etc"),
AutoEtc: true, AutoEtc: true,
}, },
ExtraPerms: []*fst.ExtraPermConfig{ ExtraPerms: []*hst.ExtraPermConfig{
{Path: dataHome, Execute: true}, {Path: dataHome, Execute: true},
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true}, {Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
}, },
@ -147,7 +147,7 @@ func loadAppInfo(name string, beforeFail func()) *appInfo {
func formatHostname(name string) string { func formatHostname(name string) string {
if h, err := os.Hostname(); err != nil { if h, err := os.Hostname(); err != nil {
log.Printf("cannot get hostname: %v", err) log.Printf("cannot get hostname: %v", err)
return "fortify-" + name return "hakurei-" + name
} else { } else {
return h + "-" + name return h + "-" + name
} }

View File

@ -57,7 +57,7 @@ let
modules = modules ++ [ modules = modules ++ [
{ {
home = { home = {
username = "fortify"; username = "hakurei";
homeDirectory = "/data/data/${id}"; homeDirectory = "/data/data/${id}";
stateVersion = "22.11"; stateVersion = "22.11";
}; };
@ -65,7 +65,7 @@ let
]; ];
}; };
launcher = writeScript "fortify-${pname}" '' launcher = writeScript "hakurei-${pname}" ''
#!${runtimeShell} -el #!${runtimeShell} -el
${script} ${script}
''; '';

View File

@ -10,13 +10,13 @@ import (
"path" "path"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/command" "git.gensokyo.uk/security/hakurei/command"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/fortify/internal/app/instance" "git.gensokyo.uk/security/hakurei/internal/app/instance"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/internal/sys" "git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
) )
const shellPath = "/run/current-system/sw/bin/bash" const shellPath = "/run/current-system/sw/bin/bash"
@ -28,7 +28,7 @@ var (
) )
func init() { func init() {
fmsg.Prepare("fpkg") hlog.Prepare("fpkg")
if err := os.Setenv("SHELL", shellPath); err != nil { if err := os.Setenv("SHELL", shellPath); err != nil {
log.Fatalf("cannot set $SHELL: %v", err) log.Fatalf("cannot set $SHELL: %v", err)
} }
@ -36,7 +36,7 @@ func init() {
func main() { func main() {
// early init path, skips root check and duplicate PR_SET_DUMPABLE // early init path, skips root check and duplicate PR_SET_DUMPABLE
sandbox.TryArgv0(fmsg.Output{}, fmsg.Prepare, internal.InstallFmsg) sandbox.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallFmsg)
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil { if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err) log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
@ -60,7 +60,7 @@ func main() {
return nil return nil
}). }).
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console"). Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
Flag(&flagDropShell, "s", command.BoolFlag(false), "Drop to a shell in place of next fortify action") Flag(&flagDropShell, "s", command.BoolFlag(false), "Drop to a shell in place of next hakurei action")
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess }) c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
@ -166,10 +166,10 @@ func main() {
} }
// sec: should compare version string // sec: should compare version string
fmsg.Verbosef("installing application %q version %q over local %q", hlog.Verbosef("installing application %q version %q over local %q",
bundle.ID, bundle.Version, a.Version) bundle.ID, bundle.Version, a.Version)
} else { } else {
fmsg.Verbosef("application %q clean installation", bundle.ID) hlog.Verbosef("application %q clean installation", bundle.ID)
// sec: should install credentials // sec: should install credentials
} }
@ -179,7 +179,7 @@ func main() {
withCacheDir(ctx, "install", []string{ withCacheDir(ctx, "install", []string{
// export inner bundle path in the environment // export inner bundle path in the environment
"export BUNDLE=" + fst.Tmp + "/bundle", "export BUNDLE=" + hst.Tmp + "/bundle",
// replace inner /etc // replace inner /etc
"mkdir -p etc", "mkdir -p etc",
"chmod -R +w etc", "chmod -R +w etc",
@ -218,7 +218,7 @@ func main() {
"rm -rf .local/state/{nix,home-manager}", "rm -rf .local/state/{nix,home-manager}",
// run activation script // run activation script
bundle.ActivationPackage + "/activate", bundle.ActivationPackage + "/activate",
}, false, func(config *fst.Config) *fst.Config { return config }, }, false, func(config *hst.Config) *hst.Config { return config },
bundle, pathSet, flagDropShellActivate, cleanup) bundle, pathSet, flagDropShellActivate, cleanup)
/* /*
@ -291,8 +291,8 @@ func main() {
"--out-link /nix/.nixGL/auto/vulkan " + "--out-link /nix/.nixGL/auto/vulkan " +
"--override-input nixpkgs path:/etc/nixpkgs " + "--override-input nixpkgs path:/etc/nixpkgs " +
"path:" + a.NixGL + "#nixVulkanNvidia", "path:" + a.NixGL + "#nixVulkanNvidia",
}, true, func(config *fst.Config) *fst.Config { }, true, func(config *hst.Config) *hst.Config {
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{ config.Container.Filesystem = append(config.Container.Filesystem, []*hst.FilesystemConfig{
{Src: "/etc/resolv.conf"}, {Src: "/etc/resolv.conf"},
{Src: "/sys/block"}, {Src: "/sys/block"},
{Src: "/sys/bus"}, {Src: "/sys/bus"},
@ -325,7 +325,7 @@ func main() {
if a.GPU { if a.GPU {
config.Container.Filesystem = append(config.Container.Filesystem, config.Container.Filesystem = append(config.Container.Filesystem,
&fst.FilesystemConfig{Src: path.Join(pathSet.nixPath, ".nixGL"), Dst: path.Join(fst.Tmp, "nixGL")}) &hst.FilesystemConfig{Src: path.Join(pathSet.nixPath, ".nixGL"), Dst: path.Join(hst.Tmp, "nixGL")})
appendGPUFilesystem(config) appendGPUFilesystem(config)
} }
@ -341,9 +341,9 @@ func main() {
} }
c.MustParse(os.Args[1:], func(err error) { c.MustParse(os.Args[1:], func(err error) {
fmsg.Verbosef("command returned %v", err) hlog.Verbosef("command returned %v", err)
if errors.Is(err, errSuccess) { if errors.Is(err, errSuccess) {
fmsg.BeforeExit() hlog.BeforeExit()
os.Exit(0) os.Exit(0)
} }
}) })

View File

@ -8,8 +8,8 @@ import (
"strconv" "strconv"
"sync/atomic" "sync/atomic"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
) )
var ( var (
@ -18,10 +18,10 @@ var (
func init() { func init() {
// dataHome // dataHome
if p, ok := os.LookupEnv("FORTIFY_DATA_HOME"); ok { if p, ok := os.LookupEnv("HAKUREI_DATA_HOME"); ok {
dataHome = p dataHome = p
} else { } else {
dataHome = "/var/lib/fortify/" + strconv.Itoa(os.Getuid()) dataHome = "/var/lib/hakurei/" + strconv.Itoa(os.Getuid())
} }
} }
@ -37,7 +37,7 @@ func lookPath(file string) string {
var beforeRunFail = new(atomic.Pointer[func()]) var beforeRunFail = new(atomic.Pointer[func()])
func mustRun(name string, arg ...string) { func mustRun(name string, arg ...string) {
fmsg.Verbosef("spawning process: %q %q", name, arg) hlog.Verbosef("spawning process: %q %q", name, arg)
cmd := exec.Command(name, arg...) cmd := exec.Command(name, arg...)
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
@ -71,8 +71,8 @@ func pathSetByApp(id string) *appPathSet {
return pathSet return pathSet
} }
func appendGPUFilesystem(config *fst.Config) { func appendGPUFilesystem(config *hst.Config) {
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{ config.Container.Filesystem = append(config.Container.Filesystem, []*hst.FilesystemConfig{
// flatpak commit 763a686d874dd668f0236f911de00b80766ffe79 // flatpak commit 763a686d874dd668f0236f911de00b80766ffe79
{Src: "/dev/dri", Device: true}, {Src: "/dev/dri", Device: true},
// mali // mali

View File

@ -4,19 +4,19 @@ import (
"context" "context"
"os" "os"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal/app" "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/instance" "git.gensokyo.uk/security/hakurei/internal/app/instance"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
) )
func mustRunApp(ctx context.Context, config *fst.Config, beforeFail func()) { func mustRunApp(ctx context.Context, config *hst.Config, beforeFail func()) {
rs := new(app.RunState) rs := new(app.RunState)
a := instance.MustNew(instance.ISetuid, ctx, std) a := instance.MustNew(instance.ISetuid, ctx, std)
var code int var code int
if sa, err := a.Seal(config); err != nil { if sa, err := a.Seal(config); err != nil {
fmsg.PrintBaseError(err, "cannot seal app:") hlog.PrintBaseError(err, "cannot seal app:")
code = 1 code = 1
} else { } else {
code = instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs)) code = instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs))

View File

@ -50,9 +50,9 @@
]; ];
}; };
environment.fortify = { environment.hakurei = {
enable = true; enable = true;
stateDir = "/var/lib/fortify"; stateDir = "/var/lib/hakurei";
users.alice = 0; users.alice = 0;
extraHomeConfig = { extraHomeConfig = {

View File

@ -18,7 +18,7 @@ nixosTest {
imports = [ imports = [
./configuration.nix ./configuration.nix
self.nixosModules.fortify self.nixosModules.hakurei
self.inputs.home-manager.nixosModules.home-manager self.inputs.home-manager.nixosModules.home-manager
]; ];
}; };

View File

@ -47,22 +47,22 @@ def wait_for_window(pattern):
def collect_state_ui(name): def collect_state_ui(name):
swaymsg(f"exec fortify ps > '/tmp/{name}.ps'") swaymsg(f"exec hakurei ps > '/tmp/{name}.ps'")
machine.copy_from_vm(f"/tmp/{name}.ps", "") machine.copy_from_vm(f"/tmp/{name}.ps", "")
swaymsg(f"exec fortify --json ps > '/tmp/{name}.json'") swaymsg(f"exec hakurei --json ps > '/tmp/{name}.json'")
machine.copy_from_vm(f"/tmp/{name}.json", "") machine.copy_from_vm(f"/tmp/{name}.json", "")
machine.screenshot(name) machine.screenshot(name)
def check_state(name, enablements): def check_state(name, enablements):
instances = json.loads(machine.succeed("sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 fortify --json ps")) instances = json.loads(machine.succeed("sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 hakurei --json ps"))
if len(instances) != 1: if len(instances) != 1:
raise Exception(f"unexpected state length {len(instances)}") raise Exception(f"unexpected state length {len(instances)}")
instance = next(iter(instances.values())) instance = next(iter(instances.values()))
config = instance['config'] config = instance['config']
if len(config['args']) != 1 or not (config['args'][0].startswith("/nix/store/")) or f"fortify-{name}-" not in (config['args'][0]): if len(config['args']) != 1 or not (config['args'][0].startswith("/nix/store/")) or f"hakurei-{name}-" not in (config['args'][0]):
raise Exception(f"unexpected args {instance['config']['args']}") raise Exception(f"unexpected args {instance['config']['args']}")
if config['enablements'] != enablements: if config['enablements'] != enablements:
@ -72,15 +72,15 @@ def check_state(name, enablements):
start_all() start_all()
machine.wait_for_unit("multi-user.target") machine.wait_for_unit("multi-user.target")
# To check fortify's version: # To check hakurei's version:
print(machine.succeed("sudo -u alice -i fortify version")) print(machine.succeed("sudo -u alice -i hakurei version"))
# Wait for Sway to complete startup: # Wait for Sway to complete startup:
machine.wait_for_file("/run/user/1000/wayland-1") machine.wait_for_file("/run/user/1000/wayland-1")
machine.wait_for_file("/tmp/sway-ipc.sock") machine.wait_for_file("/tmp/sway-ipc.sock")
# Prepare fpkg directory: # Prepare fpkg directory:
machine.succeed("install -dm 0700 -o alice -g users /var/lib/fortify/1000") machine.succeed("install -dm 0700 -o alice -g users /var/lib/hakurei/1000")
# Install fpkg app: # Install fpkg app:
swaymsg("exec fpkg -v install /etc/foot.pkg && touch /tmp/fpkg-install-done") swaymsg("exec fpkg -v install /etc/foot.pkg && touch /tmp/fpkg-install-done")
@ -88,9 +88,9 @@ machine.wait_for_file("/tmp/fpkg-install-done")
# Start app (foot) with Wayland enablement: # Start app (foot) with Wayland enablement:
swaymsg("exec fpkg -v start org.codeberg.dnkl.foot") swaymsg("exec fpkg -v start org.codeberg.dnkl.foot")
wait_for_window("fortify@machine-foot") wait_for_window("hakurei@machine-foot")
machine.send_chars("clear; wayland-info && touch /tmp/success-client\n") machine.send_chars("clear; wayland-info && touch /tmp/success-client\n")
machine.wait_for_file("/tmp/fortify.1000/tmpdir/2/success-client") machine.wait_for_file("/tmp/hakurei.1000/tmpdir/2/success-client")
collect_state_ui("app_wayland") collect_state_ui("app_wayland")
check_state("foot", 13) check_state("foot", 13)
# Verify acl on XDG_RUNTIME_DIR: # Verify acl on XDG_RUNTIME_DIR:
@ -104,5 +104,5 @@ machine.wait_until_fails("getfacl --absolute-names --omit-header --numeric /run/
swaymsg("exit", succeed=False) swaymsg("exit", succeed=False)
machine.wait_for_file("/tmp/sway-exit-ok") machine.wait_for_file("/tmp/sway-exit-ok")
# Print fortify runDir contents: # Print hakurei runDir contents:
print(machine.succeed("find /run/user/1000/fortify")) print(machine.succeed("find /run/user/1000/hakurei"))

View File

@ -5,17 +5,17 @@ import (
"path" "path"
"strings" "strings"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
) )
func withNixDaemon( func withNixDaemon(
ctx context.Context, ctx context.Context,
action string, command []string, net bool, updateConfig func(config *fst.Config) *fst.Config, action string, command []string, net bool, updateConfig func(config *hst.Config) *hst.Config,
app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func(), app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func(),
) { ) {
mustRunAppDropShell(ctx, updateConfig(&fst.Config{ mustRunAppDropShell(ctx, updateConfig(&hst.Config{
ID: app.ID, ID: app.ID,
Path: shellPath, Path: shellPath,
@ -31,24 +31,24 @@ func withNixDaemon(
" && pkill nix-daemon", " && pkill nix-daemon",
}, },
Username: "fortify", Username: "hakurei",
Shell: shellPath, Shell: shellPath,
Data: pathSet.homeDir, Data: pathSet.homeDir,
Dir: path.Join("/data/data", app.ID), Dir: path.Join("/data/data", app.ID),
ExtraPerms: []*fst.ExtraPermConfig{ ExtraPerms: []*hst.ExtraPermConfig{
{Path: dataHome, Execute: true}, {Path: dataHome, Execute: true},
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true}, {Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
}, },
Identity: app.Identity, Identity: app.Identity,
Container: &fst.ContainerConfig{ Container: &hst.ContainerConfig{
Hostname: formatHostname(app.Name) + "-" + action, Hostname: formatHostname(app.Name) + "-" + action,
Userns: true, // nix sandbox requires userns Userns: true, // nix sandbox requires userns
Net: net, Net: net,
Seccomp: seccomp.FilterMultiarch, Seccomp: seccomp.FilterMultiarch,
Tty: dropShell, Tty: dropShell,
Filesystem: []*fst.FilesystemConfig{ Filesystem: []*hst.FilesystemConfig{
{Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true}, {Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true},
}, },
Link: [][2]string{ Link: [][2]string{
@ -66,7 +66,7 @@ func withCacheDir(
ctx context.Context, ctx context.Context,
action string, command []string, workDir string, action string, command []string, workDir string,
app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) { app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) {
mustRunAppDropShell(ctx, &fst.Config{ mustRunAppDropShell(ctx, &hst.Config{
ID: app.ID, ID: app.ID,
Path: shellPath, Path: shellPath,
@ -76,7 +76,7 @@ func withCacheDir(
Shell: shellPath, Shell: shellPath,
Data: pathSet.cacheDir, // this also ensures cacheDir via shim Data: pathSet.cacheDir, // this also ensures cacheDir via shim
Dir: path.Join("/data/data", app.ID, "cache"), Dir: path.Join("/data/data", app.ID, "cache"),
ExtraPerms: []*fst.ExtraPermConfig{ ExtraPerms: []*hst.ExtraPermConfig{
{Path: dataHome, Execute: true}, {Path: dataHome, Execute: true},
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true}, {Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
{Path: workDir, Execute: true}, {Path: workDir, Execute: true},
@ -84,13 +84,13 @@ func withCacheDir(
Identity: app.Identity, Identity: app.Identity,
Container: &fst.ContainerConfig{ Container: &hst.ContainerConfig{
Hostname: formatHostname(app.Name) + "-" + action, Hostname: formatHostname(app.Name) + "-" + action,
Seccomp: seccomp.FilterMultiarch, Seccomp: seccomp.FilterMultiarch,
Tty: dropShell, Tty: dropShell,
Filesystem: []*fst.FilesystemConfig{ Filesystem: []*hst.FilesystemConfig{
{Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true}, {Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true},
{Src: workDir, Dst: path.Join(fst.Tmp, "bundle"), Must: true}, {Src: workDir, Dst: path.Join(hst.Tmp, "bundle"), Must: true},
}, },
Link: [][2]string{ Link: [][2]string{
{app.CurrentSystem, "/run/current-system"}, {app.CurrentSystem, "/run/current-system"},
@ -103,7 +103,7 @@ func withCacheDir(
}, dropShell, beforeFail) }, dropShell, beforeFail)
} }
func mustRunAppDropShell(ctx context.Context, config *fst.Config, dropShell bool, beforeFail func()) { func mustRunAppDropShell(ctx context.Context, config *hst.Config, dropShell bool, beforeFail func()) {
if dropShell { if dropShell {
config.Args = []string{shellPath, "-l"} config.Args = []string{shellPath, "-l"}
mustRunApp(ctx, config, beforeFail) mustRunApp(ctx, config, beforeFail)

View File

@ -13,17 +13,17 @@ import (
) )
const ( const (
fsuConfFile = "/etc/fsurc" hsuConfFile = "/etc/hsurc"
envShim = "FORTIFY_SHIM" envShim = "HAKUREI_SHIM"
envAID = "FORTIFY_APP_ID" envAID = "HAKUREI_APP_ID"
envGroups = "FORTIFY_GROUPS" envGroups = "HAKUREI_GROUPS"
PR_SET_NO_NEW_PRIVS = 0x26 PR_SET_NO_NEW_PRIVS = 0x26
) )
func main() { func main() {
log.SetFlags(0) log.SetFlags(0)
log.SetPrefix("fsu: ") log.SetPrefix("hsu: ")
log.SetOutput(os.Stderr) log.SetOutput(os.Stderr)
if os.Geteuid() != 0 { if os.Geteuid() != 0 {
@ -40,9 +40,9 @@ func main() {
if p, err := os.Readlink(pexe); err != nil { if p, err := os.Readlink(pexe); err != nil {
log.Fatalf("cannot read parent executable path: %v", err) log.Fatalf("cannot read parent executable path: %v", err)
} else if strings.HasSuffix(p, " (deleted)") { } else if strings.HasSuffix(p, " (deleted)") {
log.Fatal("fortify executable has been deleted") log.Fatal("hakurei executable has been deleted")
} else if p != mustCheckPath(fmain) && p != mustCheckPath(fpkg) { } else if p != mustCheckPath(hmain) && p != mustCheckPath(fpkg) {
log.Fatal("this program must be started by fortify") log.Fatal("this program must be started by hakurei")
} else { } else {
toolPath = p toolPath = p
} }
@ -52,27 +52,27 @@ func main() {
// aid // aid
uid := 1000000 uid := 1000000
// refuse to run if fsurc is not protected correctly // refuse to run if hsurc is not protected correctly
if s, err := os.Stat(fsuConfFile); err != nil { if s, err := os.Stat(hsuConfFile); err != nil {
log.Fatal(err) log.Fatal(err)
} else if s.Mode().Perm() != 0400 { } else if s.Mode().Perm() != 0400 {
log.Fatal("bad fsurc perm") log.Fatal("bad hsurc perm")
} else if st := s.Sys().(*syscall.Stat_t); st.Uid != 0 || st.Gid != 0 { } else if st := s.Sys().(*syscall.Stat_t); st.Uid != 0 || st.Gid != 0 {
log.Fatal("fsurc must be owned by uid 0") log.Fatal("hsurc must be owned by uid 0")
} }
// authenticate before accepting user input // authenticate before accepting user input
if f, err := os.Open(fsuConfFile); err != nil { if f, err := os.Open(hsuConfFile); err != nil {
log.Fatal(err) log.Fatal(err)
} else if fid, ok := mustParseConfig(f, puid); !ok { } else if fid, ok := mustParseConfig(f, puid); !ok {
log.Fatalf("uid %d is not in the fsurc file", puid) log.Fatalf("uid %d is not in the hsurc file", puid)
} else { } else {
uid += fid * 10000 uid += fid * 10000
} }
// allowed aid range 0 to 9999 // allowed aid range 0 to 9999
if as, ok := os.LookupEnv(envAID); !ok { if as, ok := os.LookupEnv(envAID); !ok {
log.Fatal("FORTIFY_APP_ID not set") log.Fatal("HAKUREI_APP_ID not set")
} else if aid, err := parseUint32Fast(as); err != nil || aid < 0 || aid > 9999 { } else if aid, err := parseUint32Fast(as); err != nil || aid < 0 || aid > 9999 {
log.Fatal("invalid aid") log.Fatal("invalid aid")
} else { } else {
@ -82,12 +82,12 @@ func main() {
// pass through setup fd to shim // pass through setup fd to shim
var shimSetupFd string var shimSetupFd string
if s, ok := os.LookupEnv(envShim); !ok { if s, ok := os.LookupEnv(envShim); !ok {
// fortify requests target uid // hakurei requests target uid
// print resolved uid and exit // print resolved uid and exit
fmt.Print(uid) fmt.Print(uid)
os.Exit(0) os.Exit(0)
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' { } else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
log.Fatal("FORTIFY_SHIM holds an invalid value") log.Fatal("HAKUREI_SHIM holds an invalid value")
} else { } else {
shimSetupFd = s shimSetupFd = s
} }
@ -124,7 +124,7 @@ func main() {
panic("uid out of bounds") panic("uid out of bounds")
} }
// careful! users in the allowlist is effectively allowed to drop groups via fsu // careful! users in the allowlist is effectively allowed to drop groups via hsu
if err := syscall.Setresgid(uid, uid, uid); err != nil { if err := syscall.Setresgid(uid, uid, uid); err != nil {
log.Fatalf("cannot set gid: %v", err) log.Fatalf("cannot set gid: %v", err)
@ -138,7 +138,7 @@ func main() {
if _, _, errno := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_NO_NEW_PRIVS, 1, 0); errno != 0 { if _, _, errno := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_NO_NEW_PRIVS, 1, 0); errno != 0 {
log.Fatalf("cannot set no_new_privs flag: %s", errno.Error()) log.Fatalf("cannot set no_new_privs flag: %s", errno.Error())
} }
if err := syscall.Exec(toolPath, []string{"fortify", "shim"}, []string{envShim + "=" + shimSetupFd}); err != nil { if err := syscall.Exec(toolPath, []string{"hakurei", "shim"}, []string{envShim + "=" + shimSetupFd}); err != nil {
log.Fatalf("cannot start shim: %v", err) log.Fatalf("cannot start shim: %v", err)
} }

View File

@ -1,19 +1,19 @@
{ {
lib, lib,
buildGoModule, buildGoModule,
fortify ? abort "fortify package required", hakurei ? abort "hakurei package required",
}: }:
buildGoModule { buildGoModule {
pname = "${fortify.pname}-fsu"; pname = "${hakurei.pname}-hsu";
inherit (fortify) version; inherit (hakurei) version;
src = ./.; src = ./.;
inherit (fortify) vendorHash; inherit (hakurei) vendorHash;
env.CGO_ENABLED = 0; env.CGO_ENABLED = 0;
preBuild = '' preBuild = ''
go mod init fsu >& /dev/null go mod init hsu >& /dev/null
''; '';
ldflags = ldflags =
@ -24,7 +24,7 @@ buildGoModule {
) )
[ "-s -w" ] [ "-s -w" ]
{ {
fmain = "${fortify}/libexec/fortify"; hmain = "${hakurei}/libexec/hakurei";
fpkg = "${fortify}/libexec/fpkg"; fpkg = "${hakurei}/libexec/fpkg";
}; };
} }

View File

@ -50,7 +50,7 @@ func parseConfig(r io.Reader, puid int) (fid int, ok bool, err error) {
if ok { if ok {
// allowed fid range 0 to 99 // allowed fid range 0 to 99
if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 { if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 {
return -1, false, fmt.Errorf("invalid fortify uid on line %d", line) return -1, false, fmt.Errorf("invalid identity on line %d", line)
} }
return return
} }

View File

@ -65,7 +65,7 @@ func Test_parseConfig(t *testing.T) {
{"empty", 0, -1, "", ``}, {"empty", 0, -1, "", ``},
{"invalid field", 0, -1, "invalid entry on line 1", `9`}, {"invalid field", 0, -1, "invalid entry on line 1", `9`},
{"invalid puid", 0, -1, "invalid parent uid on line 1", `f 9`}, {"invalid puid", 0, -1, "invalid parent uid on line 1", `f 9`},
{"invalid fid", 1000, -1, "invalid fortify uid on line 1", `1000 f`}, {"invalid fid", 1000, -1, "invalid identity on line 1", `1000 f`},
{"match", 1000, 0, "", `1000 0`}, {"match", 1000, 0, "", `1000 0`},
} }

View File

@ -8,7 +8,7 @@ import (
const compPoison = "INVALIDINVALIDINVALIDINVALIDINVALID" const compPoison = "INVALIDINVALIDINVALIDINVALIDINVALID"
var ( var (
fmain = compPoison hmain = compPoison
fpkg = compPoison fpkg = compPoison
) )

View File

@ -3,7 +3,7 @@ package command_test
import ( import (
"testing" "testing"
"git.gensokyo.uk/security/fortify/command" "git.gensokyo.uk/security/hakurei/command"
) )
func TestBuild(t *testing.T) { func TestBuild(t *testing.T) {

View File

@ -10,7 +10,7 @@ import (
"strings" "strings"
"testing" "testing"
"git.gensokyo.uk/security/fortify/command" "git.gensokyo.uk/security/hakurei/command"
) )
func TestParse(t *testing.T) { func TestParse(t *testing.T) {

View File

@ -5,7 +5,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
) )
func TestParse(t *testing.T) { func TestParse(t *testing.T) {

View File

@ -9,7 +9,7 @@ import (
"strings" "strings"
"testing" "testing"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
) )
func TestConfig_Args(t *testing.T) { func TestConfig_Args(t *testing.T) {

View File

@ -13,11 +13,11 @@ import (
"testing" "testing"
"time" "time"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
) )
func TestFinalise(t *testing.T) { func TestFinalise(t *testing.T) {
@ -208,6 +208,6 @@ func TestHelperInit(t *testing.T) {
if len(os.Args) != 5 || os.Args[4] != "init" { if len(os.Args) != 5 || os.Args[4] != "init" {
return return
} }
sandbox.SetOutput(fmsg.Output{}) sandbox.SetOutput(hlog.Output{})
sandbox.Init(fmsg.Prepare, internal.InstallFmsg) sandbox.Init(hlog.Prepare, internal.InstallFmsg)
} }

View File

@ -11,10 +11,10 @@ import (
"strconv" "strconv"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
"git.gensokyo.uk/security/fortify/ldd" "git.gensokyo.uk/security/hakurei/ldd"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
) )
// Start starts and configures a D-Bus proxy process. // Start starts and configures a D-Bus proxy process.
@ -67,7 +67,7 @@ func (p *Proxy) Start() error {
p.final, true, p.final, true,
argF, func(container *sandbox.Container) { argF, func(container *sandbox.Container) {
container.Seccomp |= seccomp.FilterMultiarch container.Seccomp |= seccomp.FilterMultiarch
container.Hostname = "fortify-dbus" container.Hostname = "hakurei-dbus"
container.CommandContext = p.CommandContext container.CommandContext = p.CommandContext
if p.output != nil { if p.output != nil {
container.Stdout, container.Stderr = p.output, p.output container.Stdout, container.Stderr = p.output, p.output

View File

@ -8,7 +8,7 @@ import (
"sync" "sync"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
) )
// ProxyName is the file name or path to the proxy program. // ProxyName is the file name or path to the proxy program.

View File

@ -3,7 +3,7 @@ package dbus_test
import ( import (
"sync" "sync"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
) )
const ( const (

View File

@ -3,7 +3,7 @@ package dbus_test
import ( import (
"testing" "testing"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
) )
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() } func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }

View File

@ -1,11 +1,11 @@
#compdef fortify #compdef hakurei
_fortify_app() { _hakurei_app() {
__fortify_files __hakurei_files
return $? return $?
} }
_fortify_run() { _hakurei_run() {
_arguments \ _arguments \
'--id[Reverse-DNS style Application identifier, leave empty to inherit instance identifier]:id' \ '--id[Reverse-DNS style Application identifier, leave empty to inherit instance identifier]:id' \
'-a[Application identity]: :_numbers' \ '-a[Application identity]: :_numbers' \
@ -22,26 +22,26 @@ _fortify_run() {
'--dbus-log[Force buffered logging in the D-Bus proxy]' '--dbus-log[Force buffered logging in the D-Bus proxy]'
} }
_fortify_ps() { _hakurei_ps() {
_arguments \ _arguments \
'--short[List instances only]' '--short[List instances only]'
} }
_fortify_show() { _hakurei_show() {
_alternative \ _alternative \
'instances:domains:__fortify_instances' \ 'instances:domains:__hakurei_instances' \
'files:files:__fortify_files' 'files:files:__hakurei_files'
} }
__fortify_files() { __hakurei_files() {
_files -g "*.(json|ftfy)" _files -g "*.(json|hakurei)"
return $? return $?
} }
__fortify_instances() { __hakurei_instances() {
local -a out local -a out
shift -p shift -p
out=( ${(f)"$(_call_program commands fortify ps --short 2>&1)"} ) out=( ${(f)"$(_call_program commands hakurei ps --short 2>&1)"} )
if (( $#out == 0 )); then if (( $#out == 0 )); then
_message "No active instances" _message "No active instances"
else else
@ -50,26 +50,26 @@ __fortify_instances() {
return $? return $?
} }
(( $+functions[_fortify_commands] )) || _fortify_commands() (( $+functions[_hakurei_commands] )) || _hakurei_commands()
{ {
local -a _fortify_cmds local -a _hakurei_cmds
_fortify_cmds=( _hakurei_cmds=(
"app:Launch app defined by the specified config file" "app:Load app from configuration file"
"run:Configure and start a permissive default sandbox" "run:Configure and start a permissive default sandbox"
"show:Show the contents of an app configuration" "show:Show live or local app configuration"
"ps:List active apps and their state" "ps:List active instances"
"version:Show fortify version" "version:Display version information"
"license:Show full license text" "license:Show full license text"
"template:Produce a config template" "template:Produce a config template"
"help:Show help message" "help:Show help message"
) )
if (( CURRENT == 1 )); then if (( CURRENT == 1 )); then
_describe -t commands 'action' _fortify_cmds || compadd "$@" _describe -t commands 'action' _hakurei_cmds || compadd "$@"
else else
local curcontext="$curcontext" local curcontext="$curcontext"
cmd="${${_fortify_cmds[(r)$words[1]:*]%%:*}}" cmd="${${_hakurei_cmds[(r)$words[1]:*]%%:*}}"
if (( $+functions[_fortify_$cmd] )); then if (( $+functions[_hakurei_$cmd] )); then
_fortify_$cmd _hakurei_$cmd
else else
_message "no more options" _message "no more options"
fi fi
@ -77,6 +77,6 @@ __fortify_instances() {
} }
_arguments -C \ _arguments -C \
'-v[Verbose output]' \ '-v[Increase log verbosity]' \
'--json[Serialise output in JSON when applicable]' \ '--json[Serialise output in JSON when applicable]' \
'*::fortify command:_fortify_commands' '*::hakurei command:_hakurei_commands'

12
dist/install.sh vendored
View File

@ -1,12 +1,12 @@
#!/bin/sh #!/bin/sh
cd "$(dirname -- "$0")" || exit 1 cd "$(dirname -- "$0")" || exit 1
install -vDm0755 "bin/fortify" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fortify" install -vDm0755 "bin/hakurei" "${HAKUREI_INSTALL_PREFIX}/usr/bin/hakurei"
install -vDm0755 "bin/fpkg" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fpkg" install -vDm0755 "bin/fpkg" "${HAKUREI_INSTALL_PREFIX}/usr/bin/fpkg"
install -vDm6511 "bin/fsu" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fsu" install -vDm6511 "bin/hsu" "${HAKUREI_INSTALL_PREFIX}/usr/bin/hsu"
if [ ! -f "${FORTIFY_INSTALL_PREFIX}/etc/fsurc" ]; then if [ ! -f "${HAKUREI_INSTALL_PREFIX}/etc/hsurc" ]; then
install -vDm0400 "fsurc.default" "${FORTIFY_INSTALL_PREFIX}/etc/fsurc" install -vDm0400 "hsurc.default" "${HAKUREI_INSTALL_PREFIX}/etc/hsurc"
fi fi
install -vDm0644 "comp/_fortify" "${FORTIFY_INSTALL_PREFIX}/usr/share/zsh/site-functions/_fortify" install -vDm0644 "comp/_hakurei" "${HAKUREI_INSTALL_PREFIX}/usr/share/zsh/site-functions/_hakurei"

12
dist/release.sh vendored
View File

@ -1,18 +1,18 @@
#!/bin/sh -e #!/bin/sh -e
cd "$(dirname -- "$0")/.." cd "$(dirname -- "$0")/.."
VERSION="${FORTIFY_VERSION:-untagged}" VERSION="${HAKUREI_VERSION:-untagged}"
pname="fortify-${VERSION}" pname="hakurei-${VERSION}"
out="dist/${pname}" out="dist/${pname}"
mkdir -p "${out}" mkdir -p "${out}"
cp -v "README.md" "dist/fsurc.default" "dist/install.sh" "${out}" cp -v "README.md" "dist/hsurc.default" "dist/install.sh" "${out}"
cp -rv "dist/comp" "${out}" cp -rv "dist/comp" "${out}"
go generate ./... go generate ./...
go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w -buildid= -extldflags '-static' go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w -buildid= -extldflags '-static'
-X git.gensokyo.uk/security/fortify/internal.version=${VERSION} -X git.gensokyo.uk/security/hakurei/internal.version=${VERSION}
-X git.gensokyo.uk/security/fortify/internal.fsu=/usr/bin/fsu -X git.gensokyo.uk/security/hakurei/internal.hsu=/usr/bin/hsu
-X main.fmain=/usr/bin/fortify -X main.hmain=/usr/bin/hakurei
-X main.fpkg=/usr/bin/fpkg" ./... -X main.fpkg=/usr/bin/fpkg" ./...
rm -f "./${out}.tar.gz" && tar -C dist -czf "${out}.tar.gz" "${pname}" rm -f "./${out}.tar.gz" && tar -C dist -czf "${out}.tar.gz" "${pname}"

View File

@ -1,5 +1,5 @@
{ {
description = "fortify sandbox tool and nixos module"; description = "hakurei container tool and nixos module";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
@ -27,7 +27,7 @@
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; }); nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
in in
{ {
nixosModules.fortify = import ./nixos.nix self.packages; nixosModules.hakurei = import ./nixos.nix self.packages;
buildPackage = forAllSystems ( buildPackage = forAllSystems (
system: system:
@ -57,7 +57,7 @@
; ;
in in
{ {
fortify = callPackage ./test { inherit system self; }; hakurei = callPackage ./test { inherit system self; };
race = callPackage ./test { race = callPackage ./test {
inherit system self; inherit system self;
withRace = true; withRace = true;
@ -105,12 +105,12 @@
packages = forAllSystems ( packages = forAllSystems (
system: system:
let let
inherit (self.packages.${system}) fortify fsu; inherit (self.packages.${system}) hakurei hsu;
pkgs = nixpkgsFor.${system}; pkgs = nixpkgsFor.${system};
in in
{ {
default = fortify; default = hakurei;
fortify = pkgs.pkgsStatic.callPackage ./package.nix { hakurei = pkgs.pkgsStatic.callPackage ./package.nix {
inherit (pkgs) inherit (pkgs)
# passthru.buildInputs # passthru.buildInputs
go go
@ -131,20 +131,20 @@
coreutils coreutils
; ;
}; };
fsu = pkgs.callPackage ./cmd/fsu/package.nix { inherit (self.packages.${system}) fortify; }; hsu = pkgs.callPackage ./cmd/hsu/package.nix { inherit (self.packages.${system}) hakurei; };
dist = pkgs.runCommand "${fortify.name}-dist" { buildInputs = fortify.targetPkgs ++ [ pkgs.pkgsStatic.musl ]; } '' dist = pkgs.runCommand "${hakurei.name}-dist" { buildInputs = hakurei.targetPkgs ++ [ pkgs.pkgsStatic.musl ]; } ''
# go requires XDG_CACHE_HOME for the build cache # go requires XDG_CACHE_HOME for the build cache
export XDG_CACHE_HOME="$(mktemp -d)" export XDG_CACHE_HOME="$(mktemp -d)"
# get a different workdir as go does not like /build # get a different workdir as go does not like /build
cd $(mktemp -d) \ cd $(mktemp -d) \
&& cp -r ${fortify.src}/. . \ && cp -r ${hakurei.src}/. . \
&& chmod +w cmd && cp -r ${fsu.src}/. cmd/fsu/ \ && chmod +w cmd && cp -r ${hsu.src}/. cmd/hsu/ \
&& chmod -R +w . && chmod -R +w .
export FORTIFY_VERSION="v${fortify.version}" export HAKUREI_VERSION="v${hakurei.version}"
./dist/release.sh && mkdir $out && cp -v "dist/fortify-$FORTIFY_VERSION.tar.gz"* $out ./dist/release.sh && mkdir $out && cp -v "dist/hakurei-$HAKUREI_VERSION.tar.gz"* $out
''; '';
} }
); );
@ -152,12 +152,12 @@
devShells = forAllSystems ( devShells = forAllSystems (
system: system:
let let
inherit (self.packages.${system}) fortify; inherit (self.packages.${system}) hakurei;
pkgs = nixpkgsFor.${system}; pkgs = nixpkgsFor.${system};
in in
{ {
default = pkgs.mkShell { buildInputs = fortify.targetPkgs; }; default = pkgs.mkShell { buildInputs = hakurei.targetPkgs; };
withPackage = pkgs.mkShell { buildInputs = [ fortify ] ++ fortify.targetPkgs; }; withPackage = pkgs.mkShell { buildInputs = [ hakurei ] ++ hakurei.targetPkgs; };
generateDoc = generateDoc =
let let
@ -174,7 +174,7 @@
cleanEval = lib.filterAttrsRecursive (n: _: n != "_module") eval; cleanEval = lib.filterAttrsRecursive (n: _: n != "_module") eval;
in in
pkgs.nixosOptionsDoc { inherit (cleanEval) options; }; pkgs.nixosOptionsDoc { inherit (cleanEval) options; };
docText = pkgs.runCommand "fortify-module-docs.md" { } '' docText = pkgs.runCommand "hakurei-module-docs.md" { } ''
cat ${doc.optionsCommonMark} > $out cat ${doc.optionsCommonMark} > $out
sed -i '/*Declared by:*/,+1 d' $out sed -i '/*Declared by:*/,+1 d' $out
''; '';

4
go.mod
View File

@ -1,3 +1,3 @@
module git.gensokyo.uk/security/fortify module git.gensokyo.uk/security/hakurei
go 1.23 go 1.24

View File

@ -7,7 +7,7 @@ import (
"syscall" "syscall"
"testing" "testing"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
) )
func TestArgsString(t *testing.T) { func TestArgsString(t *testing.T) {

View File

@ -10,7 +10,7 @@ import (
"sync" "sync"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/helper/proc" "git.gensokyo.uk/security/hakurei/helper/proc"
) )
// NewDirect initialises a new direct Helper instance with wt as the null-terminated argument writer. // NewDirect initialises a new direct Helper instance with wt as the null-terminated argument writer.
@ -67,17 +67,17 @@ func (h *helperCmd) Start() error {
h.Env = slices.Grow(h.Env, 2) h.Env = slices.Grow(h.Env, 2)
if h.useArgsFd { if h.useArgsFd {
h.Env = append(h.Env, FortifyHelper+"=1") h.Env = append(h.Env, HakureiHelper+"=1")
} else { } else {
h.Env = append(h.Env, FortifyHelper+"=0") h.Env = append(h.Env, HakureiHelper+"=0")
} }
if h.useStatFd { if h.useStatFd {
h.Env = append(h.Env, FortifyStatus+"=1") h.Env = append(h.Env, HakureiStatus+"=1")
// stat is populated on fulfill // stat is populated on fulfill
h.Cancel = func() error { return h.stat.Close() } h.Cancel = func() error { return h.stat.Close() }
} else { } else {
h.Env = append(h.Env, FortifyStatus+"=0") h.Env = append(h.Env, HakureiStatus+"=0")
} }
return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, h.Cmd.Start, h.files, h.extraFiles) return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, h.Cmd.Start, h.files, h.extraFiles)

View File

@ -8,7 +8,7 @@ import (
"os/exec" "os/exec"
"testing" "testing"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
) )
func TestCmd(t *testing.T) { func TestCmd(t *testing.T) {
@ -22,9 +22,9 @@ func TestCmd(t *testing.T) {
}) })
t.Run("valid new helper nil check", func(t *testing.T) { t.Run("valid new helper nil check", func(t *testing.T) {
if got := helper.NewDirect(t.Context(), "fortify", argsWt, false, argF, nil, nil); got == nil { if got := helper.NewDirect(t.Context(), "hakurei", argsWt, false, argF, nil, nil); got == nil {
t.Errorf("NewDirect(%q, %q) got nil", t.Errorf("NewDirect(%q, %q) got nil",
argsWt, "fortify") argsWt, "hakurei")
return return
} }
}) })

View File

@ -9,8 +9,8 @@ import (
"slices" "slices"
"sync" "sync"
"git.gensokyo.uk/security/fortify/helper/proc" "git.gensokyo.uk/security/hakurei/helper/proc"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
) )
// New initialises a Helper instance with wt as the null-terminated argument writer. // New initialises a Helper instance with wt as the null-terminated argument writer.
@ -54,17 +54,17 @@ func (h *helperContainer) Start() error {
h.Env = slices.Grow(h.Env, 2) h.Env = slices.Grow(h.Env, 2)
if h.useArgsFd { if h.useArgsFd {
h.Env = append(h.Env, FortifyHelper+"=1") h.Env = append(h.Env, HakureiHelper+"=1")
} else { } else {
h.Env = append(h.Env, FortifyHelper+"=0") h.Env = append(h.Env, HakureiHelper+"=0")
} }
if h.useStatFd { if h.useStatFd {
h.Env = append(h.Env, FortifyStatus+"=1") h.Env = append(h.Env, HakureiStatus+"=1")
// stat is populated on fulfill // stat is populated on fulfill
h.Cancel = func(*exec.Cmd) error { return h.stat.Close() } h.Cancel = func(*exec.Cmd) error { return h.stat.Close() }
} else { } else {
h.Env = append(h.Env, FortifyStatus+"=0") h.Env = append(h.Env, HakureiStatus+"=0")
} }
return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, func() error { return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, func() error {

View File

@ -7,10 +7,10 @@ import (
"os/exec" "os/exec"
"testing" "testing"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
) )
func TestContainer(t *testing.T) { func TestContainer(t *testing.T) {
@ -25,9 +25,9 @@ func TestContainer(t *testing.T) {
}) })
t.Run("valid new helper nil check", func(t *testing.T) { t.Run("valid new helper nil check", func(t *testing.T) {
if got := helper.New(t.Context(), "fortify", argsWt, false, argF, nil, nil); got == nil { if got := helper.New(t.Context(), "hakurei", argsWt, false, argF, nil, nil); got == nil {
t.Errorf("New(%q, %q) got nil", t.Errorf("New(%q, %q) got nil",
argsWt, "fortify") argsWt, "hakurei")
return return
} }
}) })
@ -52,6 +52,6 @@ func TestHelperInit(t *testing.T) {
if len(os.Args) != 5 || os.Args[4] != "init" { if len(os.Args) != 5 || os.Args[4] != "init" {
return return
} }
sandbox.SetOutput(fmsg.Output{}) sandbox.SetOutput(hlog.Output{})
sandbox.Init(fmsg.Prepare, func(bool) { internal.InstallFmsg(false) }) sandbox.Init(hlog.Prepare, func(bool) { internal.InstallFmsg(false) })
} }

View File

@ -8,16 +8,16 @@ import (
"os" "os"
"time" "time"
"git.gensokyo.uk/security/fortify/helper/proc" "git.gensokyo.uk/security/hakurei/helper/proc"
) )
var WaitDelay = 2 * time.Second var WaitDelay = 2 * time.Second
const ( const (
// FortifyHelper is set to 1 when args fd is enabled and 0 otherwise. // HakureiHelper is set to 1 when args fd is enabled and 0 otherwise.
FortifyHelper = "FORTIFY_HELPER" HakureiHelper = "HAKUREI_HELPER"
// FortifyStatus is set to 1 when stat fd is enabled and 0 otherwise. // HakureiStatus is set to 1 when stat fd is enabled and 0 otherwise.
FortifyStatus = "FORTIFY_STATUS" HakureiStatus = "HAKUREI_STATUS"
) )
type Helper interface { type Helper interface {

View File

@ -11,13 +11,13 @@ import (
"testing" "testing"
"time" "time"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
) )
var ( var (
wantArgs = []string{ wantArgs = []string{
"unix:path=/run/dbus/system_bus_socket", "unix:path=/run/dbus/system_bus_socket",
"/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/system_bus_socket", "/tmp/hakurei.1971/12622d846cc3fe7b4c10359d01f0eb47/system_bus_socket",
"--filter", "--filter",
"--talk=org.bluez", "--talk=org.bluez",
"--talk=org.freedesktop.Avahi", "--talk=org.freedesktop.Avahi",

View File

@ -14,13 +14,13 @@ import (
func InternalHelperStub() { func InternalHelperStub() {
// this test mocks the helper process // this test mocks the helper process
var ap, sp string var ap, sp string
if v, ok := os.LookupEnv(FortifyHelper); !ok { if v, ok := os.LookupEnv(HakureiHelper); !ok {
return return
} else { } else {
ap = v ap = v
} }
if v, ok := os.LookupEnv(FortifyStatus); !ok { if v, ok := os.LookupEnv(HakureiStatus); !ok {
panic(FortifyStatus) panic(HakureiStatus)
} else { } else {
sp = v sp = v
} }

View File

@ -3,7 +3,7 @@ package helper_test
import ( import (
"testing" "testing"
"git.gensokyo.uk/security/fortify/helper" "git.gensokyo.uk/security/hakurei/helper"
) )
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() } func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }

View File

@ -1,12 +1,12 @@
// Package fst exports shared fortify types. // Package hst exports shared types for invoking hakurei.
package fst package hst
import ( import (
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/fortify/system" "git.gensokyo.uk/security/hakurei/system"
) )
const Tmp = "/.fortify" const Tmp = "/.hakurei"
// Config is used to seal an app implementation. // Config is used to seal an app implementation.
type Config struct { type Config struct {

View File

@ -1,7 +1,7 @@
package fst package hst
import ( import (
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
) )
type ( type (

View File

@ -1,4 +1,4 @@
package fst package hst
type Info struct { type Info struct {
User int `json:"user"` User int `json:"user"`

View File

@ -1,9 +1,9 @@
package fst package hst
import ( import (
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
"git.gensokyo.uk/security/fortify/system" "git.gensokyo.uk/security/hakurei/system"
) )
// Template returns a fully populated instance of Config. // Template returns a fully populated instance of Config.
@ -46,11 +46,11 @@ func Template() *Config {
Username: "chronos", Username: "chronos",
Shell: "/run/current-system/sw/bin/zsh", Shell: "/run/current-system/sw/bin/zsh",
Data: "/var/lib/fortify/u0/org.chromium.Chromium", Data: "/var/lib/hakurei/u0/org.chromium.Chromium",
Dir: "/data/data/org.chromium.Chromium", Dir: "/data/data/org.chromium.Chromium",
ExtraPerms: []*ExtraPermConfig{ ExtraPerms: []*ExtraPermConfig{
{Path: "/var/lib/fortify/u0", Ensure: true, Execute: true}, {Path: "/var/lib/hakurei/u0", Ensure: true, Execute: true},
{Path: "/var/lib/fortify/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true}, {Path: "/var/lib/hakurei/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
}, },
Identity: 9, Identity: 9,
@ -78,7 +78,7 @@ func Template() *Config {
{Src: "/run/current-system"}, {Src: "/run/current-system"},
{Src: "/run/opengl-driver"}, {Src: "/run/opengl-driver"},
{Src: "/var/db/nix-channels"}, {Src: "/var/db/nix-channels"},
{Src: "/var/lib/fortify/u0/org.chromium.Chromium", {Src: "/var/lib/hakurei/u0/org.chromium.Chromium",
Dst: "/data/data/org.chromium.Chromium", Write: true, Must: true}, Dst: "/data/data/org.chromium.Chromium", Write: true, Must: true},
{Src: "/dev/dri", Device: true}, {Src: "/dev/dri", Device: true},
}, },

View File

@ -1,10 +1,10 @@
package fst_test package hst_test
import ( import (
"encoding/json" "encoding/json"
"testing" "testing"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
) )
func TestTemplate(t *testing.T) { func TestTemplate(t *testing.T) {
@ -57,16 +57,16 @@ func TestTemplate(t *testing.T) {
}, },
"username": "chronos", "username": "chronos",
"shell": "/run/current-system/sw/bin/zsh", "shell": "/run/current-system/sw/bin/zsh",
"data": "/var/lib/fortify/u0/org.chromium.Chromium", "data": "/var/lib/hakurei/u0/org.chromium.Chromium",
"dir": "/data/data/org.chromium.Chromium", "dir": "/data/data/org.chromium.Chromium",
"extra_perms": [ "extra_perms": [
{ {
"ensure": true, "ensure": true,
"path": "/var/lib/fortify/u0", "path": "/var/lib/hakurei/u0",
"x": true "x": true
}, },
{ {
"path": "/var/lib/fortify/u0/org.chromium.Chromium", "path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true, "r": true,
"w": true, "w": true,
"x": true "x": true
@ -108,7 +108,7 @@ func TestTemplate(t *testing.T) {
}, },
{ {
"dst": "/data/data/org.chromium.Chromium", "dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium", "src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": true, "write": true,
"require": true "require": true
}, },
@ -131,7 +131,7 @@ func TestTemplate(t *testing.T) {
} }
}` }`
if p, err := json.MarshalIndent(fst.Template(), "", "\t"); err != nil { if p, err := json.MarshalIndent(hst.Template(), "", "\t"); err != nil {
t.Fatalf("cannot marshal: %v", err) t.Fatalf("cannot marshal: %v", err)
} else if s := string(p); s != want { } else if s := string(p); s != want {
t.Fatalf("Template:\n%s\nwant:\n%s", t.Fatalf("Template:\n%s\nwant:\n%s",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
package instance 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. // ShimMain is the main function of the shim process and runs as the unconstrained target user.
func ShimMain() { setuid.ShimMain() } func ShimMain() { setuid.ShimMain() }

View File

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

View File

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

View File

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

View File

@ -7,7 +7,7 @@ import (
"os/user" "os/user"
"strconv" "strconv"
"git.gensokyo.uk/security/fortify/internal/app" "git.gensokyo.uk/security/hakurei/internal/app"
) )
// fs methods are not implemented using a real FS // 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) Getuid() int { return 1971 }
func (s *stubNixOS) Getgid() int { return 100 } func (s *stubNixOS) Getgid() int { return 100 }
func (s *stubNixOS) TempDir() string { return "/tmp" } 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) 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) EvalSymlinks(path string) (string, error) { return path, nil }
func (s *stubNixOS) Uid(aid int) (int, error) { return 1000000 + 0*10000 + aid, 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 { func (s *stubNixOS) Paths() app.Paths {
return app.Paths{ return app.Paths{
SharePath: "/tmp/fortify.1971", SharePath: "/tmp/hakurei.1971",
RuntimePath: "/run/user/1971", RuntimePath: "/run/user/1971",
RunDirPath: "/run/user/1971/fortify", RunDirPath: "/run/user/1971/hakurei",
} }
} }

View File

@ -7,18 +7,18 @@ import (
"testing" "testing"
"time" "time"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal/app" "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/internal/setuid" "git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
"git.gensokyo.uk/security/fortify/internal/sys" "git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/fortify/system" "git.gensokyo.uk/security/hakurei/system"
) )
type sealTestCase struct { type sealTestCase struct {
name string name string
os sys.State os sys.State
config *fst.Config config *hst.Config
id app.ID id app.ID
wantSys *system.I wantSys *system.I
wantContainer *sandbox.Params wantContainer *sandbox.Params
@ -80,70 +80,25 @@ func stubDirEntries(names ...string) (e []fs.DirEntry, err error) {
type stubDirEntryPath string type stubDirEntryPath string
func (p stubDirEntryPath) Name() string { func (p stubDirEntryPath) Name() string { return string(p) }
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) 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 type stubFileInfoMode fs.FileMode
func (s stubFileInfoMode) Name() string { func (s stubFileInfoMode) Name() string { panic("attempted to call Name") }
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) Size() int64 { func (s stubFileInfoMode) IsDir() bool { panic("attempted to call IsDir") }
panic("attempted to call Size") func (s stubFileInfoMode) Sys() any { panic("attempted to call Sys") }
}
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 type stubFileInfoIsDir bool
func (s stubFileInfoIsDir) Name() string { func (s stubFileInfoIsDir) Name() string { panic("attempted to call Name") }
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) Size() int64 { func (s stubFileInfoIsDir) IsDir() bool { return bool(s) }
panic("attempted to call Size") func (s stubFileInfoIsDir) Sys() any { panic("attempted to call Sys") }
}
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" "errors"
"log" "log"
. "git.gensokyo.uk/security/fortify/internal/app" . "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
) )
func PrintRunStateErr(rs *RunState, runErr error) (code int) { func PrintRunStateErr(rs *RunState, runErr error) (code int) {
@ -13,10 +13,10 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
if runErr != nil { if runErr != nil {
if rs.Time == nil { if rs.Time == nil {
fmsg.PrintBaseError(runErr, "cannot start app:") hlog.PrintBaseError(runErr, "cannot start app:")
} else { } else {
var e *fmsg.BaseError var e *hlog.BaseError
if !fmsg.AsBaseError(runErr, &e) { if !hlog.AsBaseError(runErr, &e) {
log.Println("wait failed:", runErr) log.Println("wait failed:", runErr)
} else { } else {
// Wait only returns either *app.ProcessError or *app.StateStoreError wrapped in a *app.BaseError // 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 // every error here is wrapped in *app.BaseError
for _, ei := range errs { for _, ei := range errs {
var eb *fmsg.BaseError var eb *hlog.BaseError
if !errors.As(ei, &eb) { if !errors.As(ei, &eb) {
// unreachable // unreachable
log.Println("invalid error type returned by revert:", ei) 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 { if rs.RevertErr != nil {
var stateStoreError *StateStoreError var stateStoreError *StateStoreError
if !errors.As(rs.RevertErr, &stateStoreError) || stateStoreError == nil { 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 goto out
} }
@ -67,11 +67,11 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
if len(stateStoreError.Err) == 2 { if len(stateStoreError.Err) == 2 {
if stateStoreError.Err[0] != nil { if stateStoreError.Err[0] != nil {
if joinedErrs, ok := stateStoreError.Err[0].(interface{ Unwrap() []error }); !ok { 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 { } else {
for _, err := range joinedErrs.Unwrap() { for _, err := range joinedErrs.Unwrap() {
if err != nil { 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 { 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 { if stateStoreError.Inner && stateStoreError.InnerErr != nil {
fmsg.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:") hlog.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:")
} }
out: out:
@ -104,7 +104,7 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
} }
} }
if rs.WaitErr != nil { if rs.WaitErr != nil {
fmsg.Verbosef("wait: %v", rs.WaitErr) hlog.Verbosef("wait: %v", rs.WaitErr)
} }
return 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 { if e.Inner && e.InnerErr == nil && e.DoErr == nil && e.OpErr == nil && errors.Join(e.Err...) == nil {
return nil return nil
} else { } else {
return fmsg.WrapErrorSuffix(e, a...) return hlog.WrapErrSuffix(e, a...)
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@ package setuid
import ( import (
"strconv" "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)} } func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }

View File

@ -3,7 +3,7 @@ package internal
import ( import (
"os" "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 ( import (
"fmt" "fmt"
@ -12,13 +12,8 @@ type baseError struct {
Err error Err error
} }
func (e *baseError) Error() string { func (e *baseError) Error() string { return e.Err.Error() }
return e.Err.Error() func (e *baseError) Unwrap() error { return e.Err }
}
func (e *baseError) Unwrap() error {
return e.Err
}
// BaseError implements an error container with a user-facing message // BaseError implements an error container with a user-facing message
type BaseError struct { type BaseError struct {
@ -27,35 +22,33 @@ type BaseError struct {
} }
// Message returns a user-facing error message // Message returns a user-facing error message
func (e *BaseError) Message() string { func (e *BaseError) Message() string { return e.message }
return e.message
}
// WrapError wraps an error with a corresponding message. // WrapErr wraps an error with a corresponding message.
func WrapError(err error, a ...any) error { func WrapErr(err error, a ...any) error {
if err == nil { if err == nil {
return 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. // WrapErrSuffix wraps an error with a corresponding message with err at the end of the message.
func WrapErrorSuffix(err error, a ...any) error { func WrapErrSuffix(err error, a ...any) error {
if err == nil { if err == nil {
return 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. // WrapErrFunc wraps an error with a corresponding message returned by f.
func WrapErrorFunc(err error, f func(err error) string) error { func WrapErrFunc(err error, f func(err error) string) error {
if err == nil { if err == nil {
return 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}} return &BaseError{message, baseError{err}}
} }

View File

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

View File

@ -1,11 +1,11 @@
package fmsg package hlog
type Output struct{} type Output struct{}
func (Output) IsVerbose() bool { return Load() } func (Output) IsVerbose() bool { return Load() }
func (Output) Verbose(v ...any) { Verbose(v...) } func (Output) Verbose(v ...any) { Verbose(v...) }
func (Output) Verbosef(format string, v ...any) { Verbosef(format, 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) PrintBaseErr(err error, fallback string) { PrintBaseError(err, fallback) }
func (Output) Suspend() { Suspend() } func (Output) Suspend() { Suspend() }
func (Output) Resume() bool { return Resume() } func (Output) Resume() bool { return Resume() }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,8 +6,8 @@ import (
"path" "path"
"strconv" "strconv"
"git.gensokyo.uk/security/fortify/internal/app" "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
) )
// State provides safe interaction with operating system state. // State provides safe interaction with operating system state.
@ -42,25 +42,25 @@ type State interface {
// Paths returns a populated [Paths] struct. // Paths returns a populated [Paths] struct.
Paths() app.Paths 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]. // Any errors returned by Uid is already wrapped [fmsg.BaseError].
Uid(aid int) (int, error) 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) { 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) { 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.RunDirPath = path.Join(v.SharePath, "run")
v.RuntimePath = path.Join(v.RunDirPath, "compat") v.RuntimePath = path.Join(v.RunDirPath, "compat")
} else { } else {
v.RuntimePath = r 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" "sync"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/fortify/internal/app" "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
) )
// Std implements System using the standard library. // 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) 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) EvalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }
func (s *Std) Exit(code int) { internal.Exit(code) } func (s *Std) Exit(code int) { internal.Exit(code) }
func (s *Std) Println(v ...any) { fmsg.Verbose(v...) } func (s *Std) Println(v ...any) { hlog.Verbose(v...) }
func (s *Std) Printf(format string, v ...any) { fmsg.Verbosef(format, v...) } func (s *Std) Printf(format string, v ...any) { hlog.Verbosef(format, v...) }
const xdgRuntimeDir = "XDG_RUNTIME_DIR" const xdgRuntimeDir = "XDG_RUNTIME_DIR"
@ -80,12 +80,12 @@ func (s *Std) Uid(aid int) (int, error) {
defer func() { s.uidCopy[aid] = u }() defer func() { s.uidCopy[aid] = u }()
u.uid = -1 u.uid = -1
fsuPath := internal.MustFsuPath() hsuPath := internal.MustHsuPath()
cmd := exec.Command(fsuPath) cmd := exec.Command(hsuPath)
cmd.Path = fsuPath cmd.Path = hsuPath
cmd.Stderr = os.Stderr // pass through fatal messages 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 = "/" cmd.Dir = "/"
var ( var (
p []byte p []byte
@ -95,12 +95,12 @@ func (s *Std) Uid(aid int) (int, error) {
if p, u.err = cmd.Output(); u.err == nil { if p, u.err = cmd.Output(); u.err == nil {
u.uid, u.err = strconv.Atoi(string(p)) u.uid, u.err = strconv.Atoi(string(p))
if u.err != nil { 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 { } 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) { } 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 return u.uid, u.err
} }

View File

@ -8,7 +8,7 @@ import (
"os/exec" "os/exec"
"time" "time"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
) )
const lddTimeout = 2 * time.Second const lddTimeout = 2 * time.Second
@ -28,7 +28,7 @@ func ExecFilter(ctx context.Context,
defer cancel() defer cancel()
container := sandbox.New(c, "ldd", p) container := sandbox.New(c, "ldd", p)
container.CommandContext = commandContext container.CommandContext = commandContext
container.Hostname = "fortify-ldd" container.Hostname = "hakurei-ldd"
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer) stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
container.Stdout = stdout container.Stdout = stdout
container.Stderr = stderr container.Stderr = stderr

View File

@ -5,7 +5,7 @@ import (
"reflect" "reflect"
"testing" "testing"
"git.gensokyo.uk/security/fortify/ldd" "git.gensokyo.uk/security/hakurei/ldd"
) )
func TestParseError(t *testing.T) { func TestParseError(t *testing.T) {

59
main.go
View File

@ -15,17 +15,17 @@ import (
"syscall" "syscall"
"time" "time"
"git.gensokyo.uk/security/fortify/command" "git.gensokyo.uk/security/hakurei/command"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/fortify/internal/app" "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/instance" "git.gensokyo.uk/security/hakurei/internal/app/instance"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/internal/state" "git.gensokyo.uk/security/hakurei/internal/state"
"git.gensokyo.uk/security/fortify/internal/sys" "git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/fortify/system" "git.gensokyo.uk/security/hakurei/system"
) )
var ( var (
@ -35,13 +35,13 @@ var (
license string license string
) )
func init() { fmsg.Prepare("fortify") } func init() { hlog.Prepare("hakurei") }
var std sys.State = new(sys.Std) var std sys.State = new(sys.Std)
func main() { func main() {
// early init path, skips root check and duplicate PR_SET_DUMPABLE // early init path, skips root check and duplicate PR_SET_DUMPABLE
sandbox.TryArgv0(fmsg.Output{}, fmsg.Prepare, internal.InstallFmsg) sandbox.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallFmsg)
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil { if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err) log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
@ -53,9 +53,9 @@ func main() {
} }
buildCommand(os.Stderr).MustParse(os.Args[1:], func(err error) { buildCommand(os.Stderr).MustParse(os.Args[1:], func(err error) {
fmsg.Verbosef("command returned %v", err) hlog.Verbosef("command returned %v", err)
if errors.Is(err, errSuccess) { if errors.Is(err, errSuccess) {
fmsg.BeforeExit() hlog.BeforeExit()
os.Exit(0) os.Exit(0)
} }
}) })
@ -67,16 +67,13 @@ func buildCommand(out io.Writer) command.Command {
flagVerbose bool flagVerbose bool
flagJSON bool flagJSON bool
) )
c := command.New(out, log.Printf, "fortify", func([]string) error { c := command.New(out, log.Printf, "hakurei", func([]string) error { internal.InstallFmsg(flagVerbose); return nil }).
internal.InstallFmsg(flagVerbose) Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
return nil
}).
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable") Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess }) c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
c.Command("app", "Launch app defined by the specified config file", func(args []string) error { c.Command("app", "Load app from configuration file", func(args []string) error {
if len(args) < 1 { if len(args) < 1 {
log.Fatal("app requires at least 1 argument") log.Fatal("app requires at least 1 argument")
} }
@ -107,7 +104,7 @@ func buildCommand(out io.Writer) command.Command {
c.NewCommand("run", "Configure and start a permissive default sandbox", func(args []string) error { c.NewCommand("run", "Configure and start a permissive default sandbox", func(args []string) error {
// initialise config from flags // initialise config from flags
config := &fst.Config{ config := &hst.Config{
ID: fid, ID: fid,
Args: args, Args: args,
} }
@ -123,19 +120,19 @@ func buildCommand(out io.Writer) command.Command {
passwdFunc = func() { passwdFunc = func() {
var us string var us string
if uid, err := std.Uid(aid); err != nil { if uid, err := std.Uid(aid); err != nil {
fmsg.PrintBaseError(err, "cannot obtain uid from fsu:") hlog.PrintBaseError(err, "cannot obtain uid from setuid wrapper:")
os.Exit(1) os.Exit(1)
} else { } else {
us = strconv.Itoa(uid) us = strconv.Itoa(uid)
} }
if u, err := user.LookupId(us); err != nil { if u, err := user.LookupId(us); err != nil {
fmsg.Verbosef("cannot look up uid %s", us) hlog.Verbosef("cannot look up uid %s", us)
passwd = &user.User{ passwd = &user.User{
Uid: us, Uid: us,
Gid: us, Gid: us,
Username: "chronos", Username: "chronos",
Name: "Fortify", Name: "Hakurei Permissive Default",
HomeDir: "/var/empty", HomeDir: "/var/empty",
} }
} else { } else {
@ -233,7 +230,7 @@ func buildCommand(out io.Writer) command.Command {
} }
var showFlagShort bool var showFlagShort bool
c.NewCommand("show", "Show the contents of an app configuration", func(args []string) error { c.NewCommand("show", "Show live or local app configuration", func(args []string) error {
switch len(args) { switch len(args) {
case 0: // system case 0: // system
printShowSystem(os.Stdout, showFlagShort, flagJSON) printShowSystem(os.Stdout, showFlagShort, flagJSON)
@ -253,12 +250,12 @@ func buildCommand(out io.Writer) command.Command {
}).Flag(&showFlagShort, "short", command.BoolFlag(false), "Omit filesystem information") }).Flag(&showFlagShort, "short", command.BoolFlag(false), "Omit filesystem information")
var psFlagShort bool var psFlagShort bool
c.NewCommand("ps", "List active apps and their state", func(args []string) error { c.NewCommand("ps", "List active instances", func(args []string) error {
printPs(os.Stdout, time.Now().UTC(), state.NewMulti(std.Paths().RunDirPath), psFlagShort, flagJSON) printPs(os.Stdout, time.Now().UTC(), state.NewMulti(std.Paths().RunDirPath), psFlagShort, flagJSON)
return errSuccess return errSuccess
}).Flag(&psFlagShort, "short", command.BoolFlag(false), "Print instance id") }).Flag(&psFlagShort, "short", command.BoolFlag(false), "Print instance id")
c.Command("version", "Show fortify version", func(args []string) error { c.Command("version", "Display version information", func(args []string) error {
fmt.Println(internal.Version()) fmt.Println(internal.Version())
return errSuccess return errSuccess
}) })
@ -269,7 +266,7 @@ func buildCommand(out io.Writer) command.Command {
}) })
c.Command("template", "Produce a config template", func(args []string) error { c.Command("template", "Produce a config template", func(args []string) error {
printJSON(os.Stdout, false, fst.Template()) printJSON(os.Stdout, false, hst.Template())
return errSuccess return errSuccess
}) })
@ -281,7 +278,7 @@ func buildCommand(out io.Writer) command.Command {
return c return c
} }
func runApp(config *fst.Config) { func runApp(config *hst.Config) {
ctx, stop := signal.NotifyContext(context.Background(), ctx, stop := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM) syscall.SIGINT, syscall.SIGTERM)
defer stop() // unreachable defer stop() // unreachable
@ -289,7 +286,7 @@ func runApp(config *fst.Config) {
rs := new(app.RunState) rs := new(app.RunState)
if sa, err := a.Seal(config); err != nil { if sa, err := a.Seal(config); err != nil {
fmsg.PrintBaseError(err, "cannot seal app:") hlog.PrintBaseError(err, "cannot seal app:")
internal.Exit(1) internal.Exit(1)
} else { } else {
internal.Exit(instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs))) internal.Exit(instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs)))

View File

@ -6,7 +6,7 @@ import (
"flag" "flag"
"testing" "testing"
"git.gensokyo.uk/security/fortify/command" "git.gensokyo.uk/security/hakurei/command"
) )
func TestHelp(t *testing.T) { func TestHelp(t *testing.T) {
@ -17,14 +17,14 @@ func TestHelp(t *testing.T) {
}{ }{
{ {
"main", []string{}, ` "main", []string{}, `
Usage: fortify [-h | --help] [-v] [--json] COMMAND [OPTIONS] Usage: hakurei [-h | --help] [-v] [--json] COMMAND [OPTIONS]
Commands: Commands:
app Launch app defined by the specified config file app Load app from configuration file
run Configure and start a permissive default sandbox run Configure and start a permissive default sandbox
show Show the contents of an app configuration show Show live or local app configuration
ps List active apps and their state ps List active instances
version Show fortify version version Display version information
license Show full license text license Show full license text
template Produce a config template template Produce a config template
help Show this help message help Show this help message
@ -33,7 +33,7 @@ Commands:
}, },
{ {
"run", []string{"run", "-h"}, ` "run", []string{"run", "-h"}, `
Usage: fortify run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--wayland] [-X] [--dbus] [--pulse] COMMAND [OPTIONS] Usage: hakurei run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--wayland] [-X] [--dbus] [--pulse] COMMAND [OPTIONS]
Flags: Flags:
-X Enable direct connection to X11 -X Enable direct connection to X11

View File

@ -18,7 +18,7 @@ let
optionals optionals
; ;
cfg = config.environment.fortify; cfg = config.environment.hakurei;
getsubuid = fid: aid: 1000000 + fid * 10000 + aid; getsubuid = fid: aid: 1000000 + fid * 10000 + aid;
getsubname = fid: aid: "u${toString fid}_a${toString aid}"; getsubname = fid: aid: "u${toString fid}_a${toString aid}";
@ -45,20 +45,21 @@ in
in in
{ {
assertion = (lists.length conflictingApps) == 0; assertion = (lists.length conflictingApps) == 0;
message = "the following fortify apps have conflicting identities: " + (builtins.concatStringsSep ", " conflictingApps); message = "the following hakurei apps have conflicting identities: " + (builtins.concatStringsSep ", " conflictingApps);
} }
) )
]; ];
security.wrappers.fsu = { security.wrappers.hsu = {
source = "${cfg.fsuPackage}/bin/fsu";
source = "${cfg.hsuPackage}/bin/hsu";
setuid = true; setuid = true;
owner = "root"; owner = "root";
setgid = true; setgid = true;
group = "root"; group = "root";
}; };
environment.etc.fsurc = { environment.etc.hsurc = {
mode = "0400"; mode = "0400";
text = foldlAttrs ( text = foldlAttrs (
acc: username: fid: acc: username: fid:
@ -200,7 +201,7 @@ in
}; };
in in
pkgs.writeShellScriptBin app.name '' pkgs.writeShellScriptBin app.name ''
exec fortify${if app.verbose then " -v" else ""} app ${pkgs.writeText "fortify-${app.name}.json" (builtins.toJSON conf)} $@ exec hakurei${if app.verbose then " -v" else ""} app ${pkgs.writeText "hakurei-app-${app.name}.json" (builtins.toJSON conf)} $@
'' ''
) )
] ]
@ -281,7 +282,7 @@ in
getuser = fid: aid: { getuser = fid: aid: {
isSystemUser = true; isSystemUser = true;
createHome = true; createHome = true;
description = "Fortify subordinate user ${toString aid} (u${toString fid})"; description = "Hakurei subordinate user ${toString aid} (u${toString fid})";
group = getsubname fid aid; group = getsubname fid aid;
home = getsubhome fid aid; home = getsubhome fid aid;
uid = getsubuid fid aid; uid = getsubuid fid aid;

View File

@ -1,8 +1,8 @@
## environment\.fortify\.enable ## environment\.hakurei\.enable
Whether to enable fortify\. Whether to enable hakurei\.
@ -21,11 +21,11 @@ boolean
## environment\.fortify\.package ## environment\.hakurei\.package
The fortify package to use\. The hakurei package to use\.
@ -35,13 +35,13 @@ package
*Default:* *Default:*
` <derivation fortify-static-x86_64-unknown-linux-musl-0.4.1> ` ` <derivation hakurei-static-x86_64-unknown-linux-musl-0.4.1> `
## environment\.fortify\.apps ## environment\.hakurei\.apps
Declaratively configured fortify apps\. Declaratively configured hakurei apps\.
@ -55,7 +55,7 @@ attribute set of (submodule)
## environment\.fortify\.apps\.\<name>\.packages ## environment\.hakurei\.apps\.\<name>\.packages
@ -73,7 +73,7 @@ list of package
## environment\.fortify\.apps\.\<name>\.args ## environment\.hakurei\.apps\.\<name>\.args
@ -92,7 +92,7 @@ null or (list of string)
## environment\.fortify\.apps\.\<name>\.capability\.dbus ## environment\.hakurei\.apps\.\<name>\.capability\.dbus
@ -110,7 +110,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.capability\.pulse ## environment\.hakurei\.apps\.\<name>\.capability\.pulse
@ -128,7 +128,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.capability\.wayland ## environment\.hakurei\.apps\.\<name>\.capability\.wayland
@ -146,7 +146,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.capability\.x11 ## environment\.hakurei\.apps\.\<name>\.capability\.x11
@ -164,7 +164,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.command ## environment\.hakurei\.apps\.\<name>\.command
@ -184,7 +184,7 @@ null or string
## environment\.fortify\.apps\.\<name>\.dbus\.session ## environment\.hakurei\.apps\.\<name>\.dbus\.session
@ -203,7 +203,7 @@ null or (function that evaluates to a(n) anything)
## environment\.fortify\.apps\.\<name>\.dbus\.system ## environment\.hakurei\.apps\.\<name>\.dbus\.system
@ -222,7 +222,7 @@ null or anything
## environment\.fortify\.apps\.\<name>\.devel ## environment\.hakurei\.apps\.\<name>\.devel
@ -245,7 +245,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.device ## environment\.hakurei\.apps\.\<name>\.device
@ -268,7 +268,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.env ## environment\.hakurei\.apps\.\<name>\.env
@ -286,7 +286,7 @@ null or (attribute set of string)
## environment\.fortify\.apps\.\<name>\.extraConfig ## environment\.hakurei\.apps\.\<name>\.extraConfig
@ -304,7 +304,7 @@ anything
## environment\.fortify\.apps\.\<name>\.extraPaths ## environment\.hakurei\.apps\.\<name>\.extraPaths
@ -322,7 +322,7 @@ list of (submodule)
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.dev ## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.dev
@ -345,7 +345,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.dst ## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.dst
@ -363,7 +363,7 @@ null or string
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.require ## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.require
@ -386,7 +386,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.src ## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.src
@ -399,7 +399,7 @@ string
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.write ## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.write
@ -422,7 +422,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.gpu ## environment\.hakurei\.apps\.\<name>\.gpu
@ -441,7 +441,7 @@ null or boolean
## environment\.fortify\.apps\.\<name>\.groups ## environment\.hakurei\.apps\.\<name>\.groups
@ -459,7 +459,7 @@ list of string
## environment\.fortify\.apps\.\<name>\.identity ## environment\.hakurei\.apps\.\<name>\.identity
@ -472,7 +472,7 @@ integer between 1 and 9999 (both inclusive)
## environment\.fortify\.apps\.\<name>\.insecureWayland ## environment\.hakurei\.apps\.\<name>\.insecureWayland
@ -495,7 +495,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.mapRealUid ## environment\.hakurei\.apps\.\<name>\.mapRealUid
@ -518,7 +518,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.multiarch ## environment\.hakurei\.apps\.\<name>\.multiarch
@ -541,7 +541,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.name ## environment\.hakurei\.apps\.\<name>\.name
@ -554,7 +554,7 @@ string
## environment\.fortify\.apps\.\<name>\.net ## environment\.hakurei\.apps\.\<name>\.net
@ -577,7 +577,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.nix ## environment\.hakurei\.apps\.\<name>\.nix
@ -600,7 +600,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.path ## environment\.hakurei\.apps\.\<name>\.path
@ -619,7 +619,7 @@ null or string
## environment\.fortify\.apps\.\<name>\.script ## environment\.hakurei\.apps\.\<name>\.script
@ -637,7 +637,7 @@ null or string
## environment\.fortify\.apps\.\<name>\.share ## environment\.hakurei\.apps\.\<name>\.share
@ -656,7 +656,7 @@ null or package
## environment\.fortify\.apps\.\<name>\.shareUid ## environment\.hakurei\.apps\.\<name>\.shareUid
@ -679,7 +679,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.tty ## environment\.hakurei\.apps\.\<name>\.tty
@ -702,7 +702,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.useCommonPaths ## environment\.hakurei\.apps\.\<name>\.useCommonPaths
@ -725,7 +725,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.userns ## environment\.hakurei\.apps\.\<name>\.userns
@ -748,7 +748,7 @@ boolean
## environment\.fortify\.apps\.\<name>\.verbose ## environment\.hakurei\.apps\.\<name>\.verbose
@ -771,7 +771,7 @@ boolean
## environment\.fortify\.commonPaths ## environment\.hakurei\.commonPaths
@ -789,7 +789,7 @@ list of (submodule)
## environment\.fortify\.commonPaths\.\*\.dev ## environment\.hakurei\.commonPaths\.\*\.dev
@ -812,7 +812,7 @@ boolean
## environment\.fortify\.commonPaths\.\*\.dst ## environment\.hakurei\.commonPaths\.\*\.dst
@ -830,7 +830,7 @@ null or string
## environment\.fortify\.commonPaths\.\*\.require ## environment\.hakurei\.commonPaths\.\*\.require
@ -853,7 +853,7 @@ boolean
## environment\.fortify\.commonPaths\.\*\.src ## environment\.hakurei\.commonPaths\.\*\.src
@ -866,7 +866,7 @@ string
## environment\.fortify\.commonPaths\.\*\.write ## environment\.hakurei\.commonPaths\.\*\.write
@ -889,7 +889,7 @@ boolean
## environment\.fortify\.extraHomeConfig ## environment\.hakurei\.extraHomeConfig
@ -902,11 +902,11 @@ anything
## environment\.fortify\.fsuPackage ## environment\.hakurei\.hsuPackage
The fsu package to use\. The hsu package to use\.
@ -916,11 +916,11 @@ package
*Default:* *Default:*
` <derivation fortify-fsu-0.4.1> ` ` <derivation hakurei-hsu-0.4.1> `
## environment\.fortify\.stateDir ## environment\.hakurei\.stateDir
@ -933,11 +933,11 @@ string
## environment\.fortify\.users ## environment\.hakurei\.users
Users allowed to spawn fortify apps and their corresponding fortify fid\. Users allowed to spawn hakurei apps and their corresponding hakurei identity\.

View File

@ -39,19 +39,19 @@ in
{ {
options = { options = {
environment.fortify = { environment.hakurei = {
enable = mkEnableOption "fortify"; enable = mkEnableOption "hakurei";
package = mkOption { package = mkOption {
type = types.package; type = types.package;
default = packages.${pkgs.system}.fortify; default = packages.${pkgs.system}.hakurei;
description = "The fortify package to use."; description = "The hakurei package to use.";
}; };
fsuPackage = mkOption { hsuPackage = mkOption {
type = types.package; type = types.package;
default = packages.${pkgs.system}.fsu; default = packages.${pkgs.system}.hsu;
description = "The fsu package to use."; description = "The hsu package to use.";
}; };
users = mkOption { users = mkOption {
@ -61,7 +61,7 @@ in
in in
attrsOf (ints.between 0 99); attrsOf (ints.between 0 99);
description = '' description = ''
Users allowed to spawn fortify apps and their corresponding fortify fid. Users allowed to spawn hakurei apps and their corresponding hakurei identity.
''; '';
}; };
@ -276,7 +276,7 @@ in
}); });
default = { }; default = { };
description = '' description = ''
Declaratively configured fortify apps. Declaratively configured hakurei apps.
''; '';
}; };

View File

@ -30,13 +30,13 @@
}: }:
buildGoModule rec { buildGoModule rec {
pname = "fortify"; pname = "hakurei";
version = "0.4.1"; version = "0.4.1";
srcFiltered = builtins.path { srcFiltered = builtins.path {
name = "${pname}-src"; name = "${pname}-src";
path = lib.cleanSource ./.; path = lib.cleanSource ./.;
filter = path: type: !(type == "regular" && (lib.hasSuffix ".nix" path || lib.hasSuffix ".py" path)) && !(type == "directory" && lib.hasSuffix "/test" path) && !(type == "directory" && lib.hasSuffix "/cmd/fsu" path); filter = path: type: !(type == "regular" && (lib.hasSuffix ".nix" path || lib.hasSuffix ".py" path)) && !(type == "directory" && lib.hasSuffix "/test" path) && !(type == "directory" && lib.hasSuffix "/cmd/hsu" path);
}; };
vendorHash = null; vendorHash = null;
@ -65,7 +65,7 @@ buildGoModule rec {
lib.attrsets.foldlAttrs lib.attrsets.foldlAttrs
( (
ldflags: name: value: ldflags: name: value:
ldflags ++ [ "-X git.gensokyo.uk/security/fortify/internal.${name}=${value}" ] ldflags ++ [ "-X git.gensokyo.uk/security/hakurei/internal.${name}=${value}" ]
) )
( (
[ "-s -w" ] [ "-s -w" ]
@ -76,7 +76,7 @@ buildGoModule rec {
) )
{ {
version = "v${version}"; version = "v${version}";
fsu = "/run/wrappers/bin/fsu"; hsu = "/run/wrappers/bin/hsu";
}; };
# nix build environment does not allow acls # nix build environment does not allow acls
@ -113,7 +113,7 @@ buildGoModule rec {
mkdir "$out/libexec" mkdir "$out/libexec"
mv "$out"/bin/* "$out/libexec/" mv "$out"/bin/* "$out/libexec/"
makeBinaryWrapper "$out/libexec/fortify" "$out/bin/fortify" \ makeBinaryWrapper "$out/libexec/hakurei" "$out/bin/hakurei" \
--inherit-argv0 --prefix PATH : ${lib.makeBinPath appPackages} --inherit-argv0 --prefix PATH : ${lib.makeBinPath appPackages}
makeBinaryWrapper "$out/libexec/fpkg" "$out/bin/fpkg" \ makeBinaryWrapper "$out/libexec/fpkg" "$out/bin/fpkg" \

View File

@ -10,19 +10,19 @@ import (
"strings" "strings"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/internal/state" "git.gensokyo.uk/security/hakurei/internal/state"
) )
func tryPath(name string) (config *fst.Config) { func tryPath(name string) (config *hst.Config) {
var r io.Reader var r io.Reader
config = new(fst.Config) config = new(hst.Config)
if name != "-" { if name != "-" {
r = tryFd(name) r = tryFd(name)
if r == nil { if r == nil {
fmsg.Verbose("load configuration from file") hlog.Verbose("load configuration from file")
if f, err := os.Open(name); err != nil { if f, err := os.Open(name); err != nil {
log.Fatalf("cannot access configuration file %q: %s", name, err) log.Fatalf("cannot access configuration file %q: %s", name, err)
@ -51,11 +51,11 @@ func tryPath(name string) (config *fst.Config) {
func tryFd(name string) io.ReadCloser { func tryFd(name string) io.ReadCloser {
if v, err := strconv.Atoi(name); err != nil { if v, err := strconv.Atoi(name); err != nil {
if !errors.Is(err, strconv.ErrSyntax) { if !errors.Is(err, strconv.ErrSyntax) {
fmsg.Verbosef("name cannot be interpreted as int64: %v", err) hlog.Verbosef("name cannot be interpreted as int64: %v", err)
} }
return nil return nil
} else { } else {
fmsg.Verbosef("trying config stream from %d", v) hlog.Verbosef("trying config stream from %d", v)
fd := uintptr(v) fd := uintptr(v)
if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_GETFD, 0); errno != 0 { if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_GETFD, 0); errno != 0 {
if errors.Is(errno, syscall.EBADF) { if errors.Is(errno, syscall.EBADF) {
@ -67,7 +67,7 @@ func tryFd(name string) io.ReadCloser {
} }
} }
func tryShort(name string) (config *fst.Config, entry *state.State) { func tryShort(name string) (config *hst.Config, entry *state.State) {
likePrefix := false likePrefix := false
if len(name) <= 32 { if len(name) <= 32 {
likePrefix = true likePrefix = true
@ -85,7 +85,7 @@ func tryShort(name string) (config *fst.Config, entry *state.State) {
// try to match from state store // try to match from state store
if likePrefix && len(name) >= 8 { if likePrefix && len(name) >= 8 {
fmsg.Verbose("argument looks like prefix") hlog.Verbose("argument looks like prefix")
s := state.NewMulti(std.Paths().RunDirPath) s := state.NewMulti(std.Paths().RunDirPath)
if entries, err := state.Join(s); err != nil { if entries, err := state.Join(s); err != nil {
@ -101,7 +101,7 @@ func tryShort(name string) (config *fst.Config, entry *state.State) {
break break
} }
fmsg.Verbosef("instance %s skipped", v) hlog.Verbosef("instance %s skipped", v)
} }
} }
} }

View File

@ -12,21 +12,21 @@ import (
"text/tabwriter" "text/tabwriter"
"time" "time"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/internal/state" "git.gensokyo.uk/security/hakurei/internal/state"
) )
func printShowSystem(output io.Writer, short, flagJSON bool) { func printShowSystem(output io.Writer, short, flagJSON bool) {
t := newPrinter(output) t := newPrinter(output)
defer t.MustFlush() defer t.MustFlush()
info := new(fst.Info) info := new(hst.Info)
// get fid by querying uid of aid 0 // get fid by querying uid of aid 0
if uid, err := std.Uid(0); err != nil { if uid, err := std.Uid(0); err != nil {
fmsg.PrintBaseError(err, "cannot obtain uid from fsu:") hlog.PrintBaseError(err, "cannot obtain uid from setuid wrapper:")
os.Exit(1) os.Exit(1)
} else { } else {
info.User = (uid / 10000) - 100 info.User = (uid / 10000) - 100
@ -42,7 +42,7 @@ func printShowSystem(output io.Writer, short, flagJSON bool) {
func printShowInstance( func printShowInstance(
output io.Writer, now time.Time, output io.Writer, now time.Time,
instance *state.State, config *fst.Config, instance *state.State, config *hst.Config,
short, flagJSON bool) { short, flagJSON bool) {
if flagJSON { if flagJSON {
if instance != nil { if instance != nil {
@ -69,9 +69,9 @@ func printShowInstance(
t.Printf("App\n") t.Printf("App\n")
if config.ID != "" { if config.ID != "" {
t.Printf(" ID:\t%d (%s)\n", config.Identity, config.ID) t.Printf(" Identity:\t%d (%s)\n", config.Identity, config.ID)
} else { } else {
t.Printf(" ID:\t%d\n", config.Identity) t.Printf(" Identity:\t%d\n", config.Identity)
} }
t.Printf(" Enablements:\t%s\n", config.Enablements.String()) t.Printf(" Enablements:\t%s\n", config.Enablements.String())
if len(config.Groups) > 0 { if len(config.Groups) > 0 {
@ -264,7 +264,7 @@ func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON boo
as = strconv.Itoa(e.Config.Identity) as = strconv.Itoa(e.Config.Identity)
id := e.Config.ID id := e.Config.ID
if id == "" { if id == "" {
id = "uk.gensokyo.fortify." + e.s[:8] id = "uk.gensokyo.hakurei." + e.s[:8]
} }
as += " (" + id + ")" as += " (" + id + ")"
} }

View File

@ -5,10 +5,10 @@ import (
"testing" "testing"
"time" "time"
"git.gensokyo.uk/security/fortify/dbus" "git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal/app" "git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/fortify/internal/state" "git.gensokyo.uk/security/hakurei/internal/state"
) )
var ( var (
@ -21,7 +21,7 @@ var (
testState = &state.State{ testState = &state.State{
ID: testID, ID: testID,
PID: 0xDEADBEEF, PID: 0xDEADBEEF,
Config: fst.Template(), Config: hst.Template(),
Time: testAppTime, Time: testAppTime,
} }
testTime = time.Unix(3752, 1).UTC() testTime = time.Unix(3752, 1).UTC()
@ -32,15 +32,15 @@ func Test_printShowInstance(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
instance *state.State instance *state.State
config *fst.Config config *hst.Config
short, json bool short, json bool
want string want string
}{ }{
{"config", nil, fst.Template(), false, false, `App {"config", nil, hst.Template(), false, false, `App
ID: 9 (org.chromium.Chromium) Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pulseaudio Enablements: wayland, dbus, pulseaudio
Groups: video, dialout, plugdev Groups: video, dialout, plugdev
Data: /var/lib/fortify/u0/org.chromium.Chromium Data: /var/lib/hakurei/u0/org.chromium.Chromium
Hostname: localhost Hostname: localhost
Flags: userns devel net device tty mapuid autoetc Flags: userns devel net device tty mapuid autoetc
Etc: /etc Etc: /etc
@ -53,12 +53,12 @@ Filesystem
+/run/current-system +/run/current-system
+/run/opengl-driver +/run/opengl-driver
+/var/db/nix-channels +/var/db/nix-channels
w*/var/lib/fortify/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium w*/var/lib/hakurei/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium
d+/dev/dri d+/dev/dri
Extra ACL Extra ACL
--x+:/var/lib/fortify/u0 --x+:/var/lib/hakurei/u0
rwx:/var/lib/fortify/u0/org.chromium.Chromium rwx:/var/lib/hakurei/u0/org.chromium.Chromium
Session bus Session bus
Filter: true Filter: true
@ -72,23 +72,23 @@ System bus
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"] Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
`}, `},
{"config pd", nil, new(fst.Config), false, false, `Warning: this configuration uses permissive defaults! {"config pd", nil, new(hst.Config), false, false, `Warning: this configuration uses permissive defaults!
App App
ID: 0 Identity: 0
Enablements: (no enablements) Enablements: (no enablements)
`}, `},
{"config flag none", nil, &fst.Config{Container: new(fst.ContainerConfig)}, false, false, `App {"config flag none", nil, &hst.Config{Container: new(hst.ContainerConfig)}, false, false, `App
ID: 0 Identity: 0
Enablements: (no enablements) Enablements: (no enablements)
Flags: none Flags: none
Etc: /etc Etc: /etc
Path: Path:
`}, `},
{"config nil entries", nil, &fst.Config{Container: &fst.ContainerConfig{Filesystem: make([]*fst.FilesystemConfig, 1)}, ExtraPerms: make([]*fst.ExtraPermConfig, 1)}, false, false, `App {"config nil entries", nil, &hst.Config{Container: &hst.ContainerConfig{Filesystem: make([]*hst.FilesystemConfig, 1)}, ExtraPerms: make([]*hst.ExtraPermConfig, 1)}, false, false, `App
ID: 0 Identity: 0
Enablements: (no enablements) Enablements: (no enablements)
Flags: none Flags: none
Etc: /etc Etc: /etc
@ -99,10 +99,10 @@ Filesystem
Extra ACL Extra ACL
`}, `},
{"config pd dbus see", nil, &fst.Config{SessionBus: &dbus.Config{See: []string{"org.example.test"}}}, false, false, `Warning: this configuration uses permissive defaults! {"config pd dbus see", nil, &hst.Config{SessionBus: &dbus.Config{See: []string{"org.example.test"}}}, false, false, `Warning: this configuration uses permissive defaults!
App App
ID: 0 Identity: 0
Enablements: (no enablements) Enablements: (no enablements)
Session bus Session bus
@ -111,15 +111,15 @@ Session bus
`}, `},
{"instance", testState, fst.Template(), false, false, `State {"instance", testState, hst.Template(), false, false, `State
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559) Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
Uptime: 1h2m32s Uptime: 1h2m32s
App App
ID: 9 (org.chromium.Chromium) Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pulseaudio Enablements: wayland, dbus, pulseaudio
Groups: video, dialout, plugdev Groups: video, dialout, plugdev
Data: /var/lib/fortify/u0/org.chromium.Chromium Data: /var/lib/hakurei/u0/org.chromium.Chromium
Hostname: localhost Hostname: localhost
Flags: userns devel net device tty mapuid autoetc Flags: userns devel net device tty mapuid autoetc
Etc: /etc Etc: /etc
@ -132,12 +132,12 @@ Filesystem
+/run/current-system +/run/current-system
+/run/opengl-driver +/run/opengl-driver
+/var/db/nix-channels +/var/db/nix-channels
w*/var/lib/fortify/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium w*/var/lib/hakurei/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium
d+/dev/dri d+/dev/dri
Extra ACL Extra ACL
--x+:/var/lib/fortify/u0 --x+:/var/lib/hakurei/u0
rwx:/var/lib/fortify/u0/org.chromium.Chromium rwx:/var/lib/hakurei/u0/org.chromium.Chromium
Session bus Session bus
Filter: true Filter: true
@ -151,14 +151,14 @@ System bus
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"] Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
`}, `},
{"instance pd", testState, new(fst.Config), false, false, `Warning: this configuration uses permissive defaults! {"instance pd", testState, new(hst.Config), false, false, `Warning: this configuration uses permissive defaults!
State State
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559) Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
Uptime: 1h2m32s Uptime: 1h2m32s
App App
ID: 0 Identity: 0
Enablements: (no enablements) Enablements: (no enablements)
`}, `},
@ -234,16 +234,16 @@ App
}, },
"username": "chronos", "username": "chronos",
"shell": "/run/current-system/sw/bin/zsh", "shell": "/run/current-system/sw/bin/zsh",
"data": "/var/lib/fortify/u0/org.chromium.Chromium", "data": "/var/lib/hakurei/u0/org.chromium.Chromium",
"dir": "/data/data/org.chromium.Chromium", "dir": "/data/data/org.chromium.Chromium",
"extra_perms": [ "extra_perms": [
{ {
"ensure": true, "ensure": true,
"path": "/var/lib/fortify/u0", "path": "/var/lib/hakurei/u0",
"x": true "x": true
}, },
{ {
"path": "/var/lib/fortify/u0/org.chromium.Chromium", "path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true, "r": true,
"w": true, "w": true,
"x": true "x": true
@ -285,7 +285,7 @@ App
}, },
{ {
"dst": "/data/data/org.chromium.Chromium", "dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium", "src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": true, "write": true,
"require": true "require": true
}, },
@ -310,7 +310,7 @@ App
"time": "1970-01-01T00:00:00.000000009Z" "time": "1970-01-01T00:00:00.000000009Z"
} }
`}, `},
{"json config", nil, fst.Template(), false, true, `{ {"json config", nil, hst.Template(), false, true, `{
"id": "org.chromium.Chromium", "id": "org.chromium.Chromium",
"path": "/run/current-system/sw/bin/chromium", "path": "/run/current-system/sw/bin/chromium",
"args": [ "args": [
@ -359,16 +359,16 @@ App
}, },
"username": "chronos", "username": "chronos",
"shell": "/run/current-system/sw/bin/zsh", "shell": "/run/current-system/sw/bin/zsh",
"data": "/var/lib/fortify/u0/org.chromium.Chromium", "data": "/var/lib/hakurei/u0/org.chromium.Chromium",
"dir": "/data/data/org.chromium.Chromium", "dir": "/data/data/org.chromium.Chromium",
"extra_perms": [ "extra_perms": [
{ {
"ensure": true, "ensure": true,
"path": "/var/lib/fortify/u0", "path": "/var/lib/hakurei/u0",
"x": true "x": true
}, },
{ {
"path": "/var/lib/fortify/u0/org.chromium.Chromium", "path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true, "r": true,
"w": true, "w": true,
"x": true "x": true
@ -410,7 +410,7 @@ App
}, },
{ {
"dst": "/data/data/org.chromium.Chromium", "dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium", "src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": true, "write": true,
"require": true "require": true
}, },
@ -460,8 +460,8 @@ func Test_printPs(t *testing.T) {
{"nil instance", state.Entries{testID: nil}, false, false, " Instance PID Application Uptime\n"}, {"nil instance", state.Entries{testID: nil}, false, false, " Instance PID Application Uptime\n"},
{"state corruption", state.Entries{app.ID{}: testState}, false, false, " Instance PID Application Uptime\n"}, {"state corruption", state.Entries{app.ID{}: testState}, false, false, " Instance PID Application Uptime\n"},
{"valid pd", state.Entries{testID: &state.State{ID: testID, PID: 1 << 8, Config: new(fst.Config), Time: testAppTime}}, false, false, ` Instance PID Application Uptime {"valid pd", state.Entries{testID: &state.State{ID: testID, PID: 1 << 8, Config: new(hst.Config), Time: testAppTime}}, false, false, ` Instance PID Application Uptime
8e2c76b0 256 0 (uk.gensokyo.fortify.8e2c76b0) 1h2m32s 8e2c76b0 256 0 (uk.gensokyo.hakurei.8e2c76b0) 1h2m32s
`}, `},
{"valid", state.Entries{testID: testState}, false, false, ` Instance PID Application Uptime {"valid", state.Entries{testID: testState}, false, false, ` Instance PID Application Uptime
@ -538,16 +538,16 @@ func Test_printPs(t *testing.T) {
}, },
"username": "chronos", "username": "chronos",
"shell": "/run/current-system/sw/bin/zsh", "shell": "/run/current-system/sw/bin/zsh",
"data": "/var/lib/fortify/u0/org.chromium.Chromium", "data": "/var/lib/hakurei/u0/org.chromium.Chromium",
"dir": "/data/data/org.chromium.Chromium", "dir": "/data/data/org.chromium.Chromium",
"extra_perms": [ "extra_perms": [
{ {
"ensure": true, "ensure": true,
"path": "/var/lib/fortify/u0", "path": "/var/lib/hakurei/u0",
"x": true "x": true
}, },
{ {
"path": "/var/lib/fortify/u0/org.chromium.Chromium", "path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true, "r": true,
"w": true, "w": true,
"x": true "x": true
@ -589,7 +589,7 @@ func Test_printPs(t *testing.T) {
}, },
{ {
"dst": "/data/data/org.chromium.Chromium", "dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium", "src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": true, "write": true,
"require": true "require": true
}, },

View File

@ -14,7 +14,7 @@ import (
"syscall" "syscall"
"time" "time"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
) )
type HardeningFlags uintptr type HardeningFlags uintptr

View File

@ -12,13 +12,13 @@ import (
"testing" "testing"
"time" "time"
"git.gensokyo.uk/security/fortify/fst" "git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/fortify/internal" "git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg" "git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/fortify/ldd" "git.gensokyo.uk/security/hakurei/ldd"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
"git.gensokyo.uk/security/fortify/sandbox/vfs" "git.gensokyo.uk/security/hakurei/sandbox/vfs"
) )
const ( const (
@ -28,10 +28,10 @@ const (
func TestContainer(t *testing.T) { func TestContainer(t *testing.T) {
{ {
oldVerbose := fmsg.Load() oldVerbose := hlog.Load()
oldOutput := sandbox.GetOutput() oldOutput := sandbox.GetOutput()
internal.InstallFmsg(true) internal.InstallFmsg(true)
t.Cleanup(func() { fmsg.Store(oldVerbose) }) t.Cleanup(func() { hlog.Store(oldVerbose) })
t.Cleanup(func() { sandbox.SetOutput(oldOutput) }) t.Cleanup(func() { sandbox.SetOutput(oldOutput) })
} }
@ -47,9 +47,9 @@ func TestContainer(t *testing.T) {
new(sandbox.Ops), nil, "test-minimal"}, new(sandbox.Ops), nil, "test-minimal"},
{"tmpfs", 0, {"tmpfs", 0,
new(sandbox.Ops). new(sandbox.Ops).
Tmpfs(fst.Tmp, 0, 0755), Tmpfs(hst.Tmp, 0, 0755),
[]*vfs.MountInfoEntry{ []*vfs.MountInfoEntry{
e("/", fst.Tmp, "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore), e("/", hst.Tmp, "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
}, "test-tmpfs"}, }, "test-tmpfs"},
{"dev", sandbox.FAllowTTY, // go test output is not a tty {"dev", sandbox.FAllowTTY, // go test output is not a tty
new(sandbox.Ops). new(sandbox.Ops).
@ -132,14 +132,14 @@ func TestContainer(t *testing.T) {
container.Stdin = want container.Stdin = want
if err := container.Start(); err != nil { if err := container.Start(); err != nil {
fmsg.PrintBaseError(err, "start:") hlog.PrintBaseError(err, "start:")
t.Fatalf("cannot start container: %v", err) t.Fatalf("cannot start container: %v", err)
} else if err = container.Serve(); err != nil { } else if err = container.Serve(); err != nil {
fmsg.PrintBaseError(err, "serve:") hlog.PrintBaseError(err, "serve:")
t.Errorf("cannot serve setup params: %v", err) t.Errorf("cannot serve setup params: %v", err)
} }
if err := container.Wait(); err != nil { if err := container.Wait(); err != nil {
fmsg.PrintBaseError(err, "wait:") hlog.PrintBaseError(err, "wait:")
t.Fatalf("wait: %v", err) t.Fatalf("wait: %v", err)
} }
}) })
@ -175,8 +175,8 @@ func TestHelperInit(t *testing.T) {
if len(os.Args) != 5 || os.Args[4] != "init" { if len(os.Args) != 5 || os.Args[4] != "init" {
return return
} }
sandbox.SetOutput(fmsg.Output{}) sandbox.SetOutput(hlog.Output{})
sandbox.Init(fmsg.Prepare, internal.InstallFmsg) sandbox.Init(hlog.Prepare, internal.InstallFmsg)
} }
func TestHelperCheckContainer(t *testing.T) { func TestHelperCheckContainer(t *testing.T) {

View File

@ -4,7 +4,7 @@ import (
"os" "os"
"testing" "testing"
"git.gensokyo.uk/security/fortify/sandbox" "git.gensokyo.uk/security/hakurei/sandbox"
) )
func TestExecutable(t *testing.T) { func TestExecutable(t *testing.T) {

View File

@ -13,7 +13,7 @@ import (
"syscall" "syscall"
"time" "time"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
) )
const ( const (
@ -24,7 +24,7 @@ const (
basePath = "/tmp" basePath = "/tmp"
// setup params file descriptor // setup params file descriptor
setupEnv = "FORTIFY_SETUP" setupEnv = "HAKUREI_SETUP"
) )
type initParams struct { type initParams struct {
@ -56,7 +56,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
log.Fatal("invalid setup descriptor") log.Fatal("invalid setup descriptor")
} }
if errors.Is(err, ErrNotSet) { if errors.Is(err, ErrNotSet) {
log.Fatal("FORTIFY_SETUP not set") log.Fatal("HAKUREI_SETUP not set")
} }
log.Fatalf("cannot decode init setup payload: %v", err) log.Fatalf("cannot decode init setup payload: %v", err)

View File

@ -7,7 +7,7 @@ import (
"path/filepath" "path/filepath"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/sandbox/vfs" "git.gensokyo.uk/security/hakurei/sandbox/vfs"
) )
func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) error { func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) error {

View File

@ -10,7 +10,7 @@ import (
"strings" "strings"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/sandbox/vfs" "git.gensokyo.uk/security/hakurei/sandbox/vfs"
) )
const ( const (

View File

@ -5,7 +5,7 @@ import (
"errors" "errors"
"syscall" "syscall"
"git.gensokyo.uk/security/fortify/helper/proc" "git.gensokyo.uk/security/hakurei/helper/proc"
) )
const ( const (

View File

@ -8,7 +8,7 @@ import (
"syscall" "syscall"
"testing" "testing"
"git.gensokyo.uk/security/fortify/sandbox/seccomp" "git.gensokyo.uk/security/hakurei/sandbox/seccomp"
) )
func TestExport(t *testing.T) { func TestExport(t *testing.T) {
@ -72,7 +72,7 @@ func TestExport(t *testing.T) {
0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd, 0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd,
0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa, 0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa,
}, false}, }, false},
{"fortify default", seccomp.FilterExt | seccomp.FilterDenyDevel, []byte{ {"hakurei default", seccomp.FilterExt | seccomp.FilterDenyDevel, []byte{
0xc6, 0x98, 0xb0, 0x81, 0xff, 0x95, 0x7a, 0xfe, 0xc6, 0x98, 0xb0, 0x81, 0xff, 0x95, 0x7a, 0xfe,
0x17, 0xa6, 0xd9, 0x43, 0x74, 0x53, 0x7d, 0x37, 0x17, 0xa6, 0xd9, 0x43, 0x74, 0x53, 0x7d, 0x37,
0xf2, 0xa6, 0x3f, 0x6f, 0x9d, 0xd7, 0x5d, 0xa7, 0xf2, 0xa6, 0x3f, 0x6f, 0x9d, 0xd7, 0x5d, 0xa7,

Some files were not shown because too many files have changed in this diff Show More