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
with:
files: |-
result/fortify-**
result/hakurei-**
api_key: '${{secrets.RELEASE_TOKEN}}'

View File

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

4
.gitignore vendored
View File

@ -5,7 +5,7 @@
*.so
*.dylib
*.pkg
/fortify
/hakurei
# Test binary, built with `go test -c`
*.test
@ -29,4 +29,4 @@ go.work.sum
security-context-v1-protocol.*
# 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 Report Card](https://goreportcard.com/badge/git.gensokyo.uk/security/fortify)](https://goreportcard.com/report/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/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
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:
```shell
nix run git+https://git.gensokyo.uk/security/fortify -- help
nix run git+https://git.gensokyo.uk/security/hakurei -- help
```
## Module usage
@ -34,35 +34,35 @@ To use the module, import it into your configuration with
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
fortify = {
url = "git+https://git.gensokyo.uk/security/fortify";
hakurei = {
url = "git+https://git.gensokyo.uk/security/hakurei";
# Optional but recommended to limit the size of your system closure.
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";
modules = [
fortify.nixosModules.fortify
hakurei.nixosModules.hakurei
];
};
};
}
```
This adds the `environment.fortify` option:
This adds the `environment.hakurei` option:
```nix
{ pkgs, ... }:
{
environment.fortify = {
environment.hakurei = {
enable = true;
stateDir = "/var/lib/fortify";
stateDir = "/var/lib/hakurei";
users = {
alice = 0;
nixos = 10;

View File

@ -4,7 +4,7 @@
#include <stdlib.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) {
int ret = -1;
bool v;

View File

@ -1,4 +1,4 @@
#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);

View File

@ -23,7 +23,7 @@ func Update(name string, uid int, perms ...Perm) error {
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.uid_t(uid),
(*C.acl_perm_t)(p),

View File

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

View File

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

View File

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

View File

@ -10,13 +10,13 @@ import (
"path"
"syscall"
"git.gensokyo.uk/security/fortify/command"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/app/instance"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/sys"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/hakurei/command"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/hakurei/internal/app/instance"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/hakurei/sandbox"
)
const shellPath = "/run/current-system/sw/bin/bash"
@ -28,7 +28,7 @@ var (
)
func init() {
fmsg.Prepare("fpkg")
hlog.Prepare("fpkg")
if err := os.Setenv("SHELL", shellPath); err != nil {
log.Fatalf("cannot set $SHELL: %v", err)
}
@ -36,7 +36,7 @@ func init() {
func main() {
// 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 {
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
@ -60,7 +60,7 @@ func main() {
return nil
}).
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 })
@ -166,10 +166,10 @@ func main() {
}
// 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)
} else {
fmsg.Verbosef("application %q clean installation", bundle.ID)
hlog.Verbosef("application %q clean installation", bundle.ID)
// sec: should install credentials
}
@ -179,7 +179,7 @@ func main() {
withCacheDir(ctx, "install", []string{
// export inner bundle path in the environment
"export BUNDLE=" + fst.Tmp + "/bundle",
"export BUNDLE=" + hst.Tmp + "/bundle",
// replace inner /etc
"mkdir -p etc",
"chmod -R +w etc",
@ -218,7 +218,7 @@ func main() {
"rm -rf .local/state/{nix,home-manager}",
// run activation script
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)
/*
@ -291,8 +291,8 @@ func main() {
"--out-link /nix/.nixGL/auto/vulkan " +
"--override-input nixpkgs path:/etc/nixpkgs " +
"path:" + a.NixGL + "#nixVulkanNvidia",
}, true, func(config *fst.Config) *fst.Config {
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{
}, true, func(config *hst.Config) *hst.Config {
config.Container.Filesystem = append(config.Container.Filesystem, []*hst.FilesystemConfig{
{Src: "/etc/resolv.conf"},
{Src: "/sys/block"},
{Src: "/sys/bus"},
@ -325,7 +325,7 @@ func main() {
if a.GPU {
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)
}
@ -341,9 +341,9 @@ func main() {
}
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) {
fmsg.BeforeExit()
hlog.BeforeExit()
os.Exit(0)
}
})

View File

@ -8,8 +8,8 @@ import (
"strconv"
"sync/atomic"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/hlog"
)
var (
@ -18,10 +18,10 @@ var (
func init() {
// dataHome
if p, ok := os.LookupEnv("FORTIFY_DATA_HOME"); ok {
if p, ok := os.LookupEnv("HAKUREI_DATA_HOME"); ok {
dataHome = p
} 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()])
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.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
if err := cmd.Run(); err != nil {
@ -71,8 +71,8 @@ func pathSetByApp(id string) *appPathSet {
return pathSet
}
func appendGPUFilesystem(config *fst.Config) {
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{
func appendGPUFilesystem(config *hst.Config) {
config.Container.Filesystem = append(config.Container.Filesystem, []*hst.FilesystemConfig{
// flatpak commit 763a686d874dd668f0236f911de00b80766ffe79
{Src: "/dev/dri", Device: true},
// mali

View File

@ -4,19 +4,19 @@ import (
"context"
"os"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/instance"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/app/instance"
"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)
a := instance.MustNew(instance.ISetuid, ctx, std)
var code int
if sa, err := a.Seal(config); err != nil {
fmsg.PrintBaseError(err, "cannot seal app:")
hlog.PrintBaseError(err, "cannot seal app:")
code = 1
} else {
code = instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs))

View File

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

View File

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

View File

@ -47,22 +47,22 @@ def wait_for_window(pattern):
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", "")
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.screenshot(name)
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:
raise Exception(f"unexpected state length {len(instances)}")
instance = next(iter(instances.values()))
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']}")
if config['enablements'] != enablements:
@ -72,15 +72,15 @@ def check_state(name, enablements):
start_all()
machine.wait_for_unit("multi-user.target")
# To check fortify's version:
print(machine.succeed("sudo -u alice -i fortify version"))
# To check hakurei's version:
print(machine.succeed("sudo -u alice -i hakurei version"))
# Wait for Sway to complete startup:
machine.wait_for_file("/run/user/1000/wayland-1")
machine.wait_for_file("/tmp/sway-ipc.sock")
# 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:
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:
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.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")
check_state("foot", 13)
# 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)
machine.wait_for_file("/tmp/sway-exit-ok")
# Print fortify runDir contents:
print(machine.succeed("find /run/user/1000/fortify"))
# Print hakurei runDir contents:
print(machine.succeed("find /run/user/1000/hakurei"))

View File

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

View File

@ -13,17 +13,17 @@ import (
)
const (
fsuConfFile = "/etc/fsurc"
envShim = "FORTIFY_SHIM"
envAID = "FORTIFY_APP_ID"
envGroups = "FORTIFY_GROUPS"
hsuConfFile = "/etc/hsurc"
envShim = "HAKUREI_SHIM"
envAID = "HAKUREI_APP_ID"
envGroups = "HAKUREI_GROUPS"
PR_SET_NO_NEW_PRIVS = 0x26
)
func main() {
log.SetFlags(0)
log.SetPrefix("fsu: ")
log.SetPrefix("hsu: ")
log.SetOutput(os.Stderr)
if os.Geteuid() != 0 {
@ -40,9 +40,9 @@ func main() {
if p, err := os.Readlink(pexe); err != nil {
log.Fatalf("cannot read parent executable path: %v", err)
} else if strings.HasSuffix(p, " (deleted)") {
log.Fatal("fortify executable has been deleted")
} else if p != mustCheckPath(fmain) && p != mustCheckPath(fpkg) {
log.Fatal("this program must be started by fortify")
log.Fatal("hakurei executable has been deleted")
} else if p != mustCheckPath(hmain) && p != mustCheckPath(fpkg) {
log.Fatal("this program must be started by hakurei")
} else {
toolPath = p
}
@ -52,27 +52,27 @@ func main() {
// aid
uid := 1000000
// refuse to run if fsurc is not protected correctly
if s, err := os.Stat(fsuConfFile); err != nil {
// refuse to run if hsurc is not protected correctly
if s, err := os.Stat(hsuConfFile); err != nil {
log.Fatal(err)
} 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 {
log.Fatal("fsurc must be owned by uid 0")
log.Fatal("hsurc must be owned by uid 0")
}
// authenticate before accepting user input
if f, err := os.Open(fsuConfFile); err != nil {
if f, err := os.Open(hsuConfFile); err != nil {
log.Fatal(err)
} 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 {
uid += fid * 10000
}
// allowed aid range 0 to 9999
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 {
log.Fatal("invalid aid")
} else {
@ -82,12 +82,12 @@ func main() {
// pass through setup fd to shim
var shimSetupFd string
if s, ok := os.LookupEnv(envShim); !ok {
// fortify requests target uid
// hakurei requests target uid
// print resolved uid and exit
fmt.Print(uid)
os.Exit(0)
} 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 {
shimSetupFd = s
}
@ -124,7 +124,7 @@ func main() {
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 {
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 {
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)
}

View File

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

View File

@ -65,7 +65,7 @@ func Test_parseConfig(t *testing.T) {
{"empty", 0, -1, "", ``},
{"invalid field", 0, -1, "invalid entry on line 1", `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`},
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,11 @@
#compdef fortify
#compdef hakurei
_fortify_app() {
__fortify_files
_hakurei_app() {
__hakurei_files
return $?
}
_fortify_run() {
_hakurei_run() {
_arguments \
'--id[Reverse-DNS style Application identifier, leave empty to inherit instance identifier]:id' \
'-a[Application identity]: :_numbers' \
@ -22,26 +22,26 @@ _fortify_run() {
'--dbus-log[Force buffered logging in the D-Bus proxy]'
}
_fortify_ps() {
_hakurei_ps() {
_arguments \
'--short[List instances only]'
}
_fortify_show() {
_hakurei_show() {
_alternative \
'instances:domains:__fortify_instances' \
'files:files:__fortify_files'
'instances:domains:__hakurei_instances' \
'files:files:__hakurei_files'
}
__fortify_files() {
_files -g "*.(json|ftfy)"
__hakurei_files() {
_files -g "*.(json|hakurei)"
return $?
}
__fortify_instances() {
__hakurei_instances() {
local -a out
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
_message "No active instances"
else
@ -50,26 +50,26 @@ __fortify_instances() {
return $?
}
(( $+functions[_fortify_commands] )) || _fortify_commands()
(( $+functions[_hakurei_commands] )) || _hakurei_commands()
{
local -a _fortify_cmds
_fortify_cmds=(
"app:Launch app defined by the specified config file"
local -a _hakurei_cmds
_hakurei_cmds=(
"app:Load app from configuration file"
"run:Configure and start a permissive default sandbox"
"show:Show the contents of an app configuration"
"ps:List active apps and their state"
"version:Show fortify version"
"show:Show live or local app configuration"
"ps:List active instances"
"version:Display version information"
"license:Show full license text"
"template:Produce a config template"
"help:Show help message"
)
if (( CURRENT == 1 )); then
_describe -t commands 'action' _fortify_cmds || compadd "$@"
_describe -t commands 'action' _hakurei_cmds || compadd "$@"
else
local curcontext="$curcontext"
cmd="${${_fortify_cmds[(r)$words[1]:*]%%:*}}"
if (( $+functions[_fortify_$cmd] )); then
_fortify_$cmd
cmd="${${_hakurei_cmds[(r)$words[1]:*]%%:*}}"
if (( $+functions[_hakurei_$cmd] )); then
_hakurei_$cmd
else
_message "no more options"
fi
@ -77,6 +77,6 @@ __fortify_instances() {
}
_arguments -C \
'-v[Verbose output]' \
'-v[Increase log verbosity]' \
'--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
cd "$(dirname -- "$0")" || exit 1
install -vDm0755 "bin/fortify" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fortify"
install -vDm0755 "bin/fpkg" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fpkg"
install -vDm0755 "bin/hakurei" "${HAKUREI_INSTALL_PREFIX}/usr/bin/hakurei"
install -vDm0755 "bin/fpkg" "${HAKUREI_INSTALL_PREFIX}/usr/bin/fpkg"
install -vDm6511 "bin/fsu" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fsu"
if [ ! -f "${FORTIFY_INSTALL_PREFIX}/etc/fsurc" ]; then
install -vDm0400 "fsurc.default" "${FORTIFY_INSTALL_PREFIX}/etc/fsurc"
install -vDm6511 "bin/hsu" "${HAKUREI_INSTALL_PREFIX}/usr/bin/hsu"
if [ ! -f "${HAKUREI_INSTALL_PREFIX}/etc/hsurc" ]; then
install -vDm0400 "hsurc.default" "${HAKUREI_INSTALL_PREFIX}/etc/hsurc"
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
cd "$(dirname -- "$0")/.."
VERSION="${FORTIFY_VERSION:-untagged}"
pname="fortify-${VERSION}"
VERSION="${HAKUREI_VERSION:-untagged}"
pname="hakurei-${VERSION}"
out="dist/${pname}"
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}"
go generate ./...
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/fortify/internal.fsu=/usr/bin/fsu
-X main.fmain=/usr/bin/fortify
-X git.gensokyo.uk/security/hakurei/internal.version=${VERSION}
-X git.gensokyo.uk/security/hakurei/internal.hsu=/usr/bin/hsu
-X main.hmain=/usr/bin/hakurei
-X main.fpkg=/usr/bin/fpkg" ./...
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 = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
@ -27,7 +27,7 @@
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
in
{
nixosModules.fortify = import ./nixos.nix self.packages;
nixosModules.hakurei = import ./nixos.nix self.packages;
buildPackage = forAllSystems (
system:
@ -57,7 +57,7 @@
;
in
{
fortify = callPackage ./test { inherit system self; };
hakurei = callPackage ./test { inherit system self; };
race = callPackage ./test {
inherit system self;
withRace = true;
@ -105,12 +105,12 @@
packages = forAllSystems (
system:
let
inherit (self.packages.${system}) fortify fsu;
inherit (self.packages.${system}) hakurei hsu;
pkgs = nixpkgsFor.${system};
in
{
default = fortify;
fortify = pkgs.pkgsStatic.callPackage ./package.nix {
default = hakurei;
hakurei = pkgs.pkgsStatic.callPackage ./package.nix {
inherit (pkgs)
# passthru.buildInputs
go
@ -131,20 +131,20 @@
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
export XDG_CACHE_HOME="$(mktemp -d)"
# get a different workdir as go does not like /build
cd $(mktemp -d) \
&& cp -r ${fortify.src}/. . \
&& chmod +w cmd && cp -r ${fsu.src}/. cmd/fsu/ \
&& cp -r ${hakurei.src}/. . \
&& chmod +w cmd && cp -r ${hsu.src}/. cmd/hsu/ \
&& chmod -R +w .
export FORTIFY_VERSION="v${fortify.version}"
./dist/release.sh && mkdir $out && cp -v "dist/fortify-$FORTIFY_VERSION.tar.gz"* $out
export HAKUREI_VERSION="v${hakurei.version}"
./dist/release.sh && mkdir $out && cp -v "dist/hakurei-$HAKUREI_VERSION.tar.gz"* $out
'';
}
);
@ -152,12 +152,12 @@
devShells = forAllSystems (
system:
let
inherit (self.packages.${system}) fortify;
inherit (self.packages.${system}) hakurei;
pkgs = nixpkgsFor.${system};
in
{
default = pkgs.mkShell { buildInputs = fortify.targetPkgs; };
withPackage = pkgs.mkShell { buildInputs = [ fortify ] ++ fortify.targetPkgs; };
default = pkgs.mkShell { buildInputs = hakurei.targetPkgs; };
withPackage = pkgs.mkShell { buildInputs = [ hakurei ] ++ hakurei.targetPkgs; };
generateDoc =
let
@ -174,7 +174,7 @@
cleanEval = lib.filterAttrsRecursive (n: _: n != "_module") eval;
in
pkgs.nixosOptionsDoc { inherit (cleanEval) options; };
docText = pkgs.runCommand "fortify-module-docs.md" { } ''
docText = pkgs.runCommand "hakurei-module-docs.md" { } ''
cat ${doc.optionsCommonMark} > $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"
"testing"
"git.gensokyo.uk/security/fortify/helper"
"git.gensokyo.uk/security/hakurei/helper"
)
func TestArgsString(t *testing.T) {

View File

@ -10,7 +10,7 @@ import (
"sync"
"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.
@ -67,17 +67,17 @@ func (h *helperCmd) Start() error {
h.Env = slices.Grow(h.Env, 2)
if h.useArgsFd {
h.Env = append(h.Env, FortifyHelper+"=1")
h.Env = append(h.Env, HakureiHelper+"=1")
} else {
h.Env = append(h.Env, FortifyHelper+"=0")
h.Env = append(h.Env, HakureiHelper+"=0")
}
if h.useStatFd {
h.Env = append(h.Env, FortifyStatus+"=1")
h.Env = append(h.Env, HakureiStatus+"=1")
// stat is populated on fulfill
h.Cancel = func() error { return h.stat.Close() }
} 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)

View File

@ -8,7 +8,7 @@ import (
"os/exec"
"testing"
"git.gensokyo.uk/security/fortify/helper"
"git.gensokyo.uk/security/hakurei/helper"
)
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) {
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",
argsWt, "fortify")
argsWt, "hakurei")
return
}
})

View File

@ -9,8 +9,8 @@ import (
"slices"
"sync"
"git.gensokyo.uk/security/fortify/helper/proc"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/hakurei/helper/proc"
"git.gensokyo.uk/security/hakurei/sandbox"
)
// 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)
if h.useArgsFd {
h.Env = append(h.Env, FortifyHelper+"=1")
h.Env = append(h.Env, HakureiHelper+"=1")
} else {
h.Env = append(h.Env, FortifyHelper+"=0")
h.Env = append(h.Env, HakureiHelper+"=0")
}
if h.useStatFd {
h.Env = append(h.Env, FortifyStatus+"=1")
h.Env = append(h.Env, HakureiStatus+"=1")
// stat is populated on fulfill
h.Cancel = func(*exec.Cmd) error { return h.stat.Close() }
} 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 {

View File

@ -7,10 +7,10 @@ import (
"os/exec"
"testing"
"git.gensokyo.uk/security/fortify/helper"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/hakurei/helper"
"git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/sandbox"
)
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) {
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",
argsWt, "fortify")
argsWt, "hakurei")
return
}
})
@ -52,6 +52,6 @@ func TestHelperInit(t *testing.T) {
if len(os.Args) != 5 || os.Args[4] != "init" {
return
}
sandbox.SetOutput(fmsg.Output{})
sandbox.Init(fmsg.Prepare, func(bool) { internal.InstallFmsg(false) })
sandbox.SetOutput(hlog.Output{})
sandbox.Init(hlog.Prepare, func(bool) { internal.InstallFmsg(false) })
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
package fst
package hst
import (
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
"git.gensokyo.uk/security/hakurei/system"
)
// Template returns a fully populated instance of Config.
@ -46,11 +46,11 @@ func Template() *Config {
Username: "chronos",
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",
ExtraPerms: []*ExtraPermConfig{
{Path: "/var/lib/fortify/u0", Ensure: true, Execute: true},
{Path: "/var/lib/fortify/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
{Path: "/var/lib/hakurei/u0", Ensure: true, Execute: true},
{Path: "/var/lib/hakurei/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
},
Identity: 9,
@ -78,7 +78,7 @@ func Template() *Config {
{Src: "/run/current-system"},
{Src: "/run/opengl-driver"},
{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},
{Src: "/dev/dri", Device: true},
},

View File

@ -1,10 +1,10 @@
package fst_test
package hst_test
import (
"encoding/json"
"testing"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/hakurei/hst"
)
func TestTemplate(t *testing.T) {
@ -57,16 +57,16 @@ func TestTemplate(t *testing.T) {
},
"username": "chronos",
"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",
"extra_perms": [
{
"ensure": true,
"path": "/var/lib/fortify/u0",
"path": "/var/lib/hakurei/u0",
"x": true
},
{
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true,
"w": true,
"x": true
@ -108,7 +108,7 @@ func TestTemplate(t *testing.T) {
},
{
"dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": 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)
} else if s := string(p); s != want {
t.Fatalf("Template:\n%s\nwant:\n%s",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

59
main.go
View File

@ -15,17 +15,17 @@ import (
"syscall"
"time"
"git.gensokyo.uk/security/fortify/command"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/app/instance"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/fortify/internal/sys"
"git.gensokyo.uk/security/fortify/sandbox"
"git.gensokyo.uk/security/fortify/system"
"git.gensokyo.uk/security/hakurei/command"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/app/instance"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/internal/state"
"git.gensokyo.uk/security/hakurei/internal/sys"
"git.gensokyo.uk/security/hakurei/sandbox"
"git.gensokyo.uk/security/hakurei/system"
)
var (
@ -35,13 +35,13 @@ var (
license string
)
func init() { fmsg.Prepare("fortify") }
func init() { hlog.Prepare("hakurei") }
var std sys.State = new(sys.Std)
func main() {
// 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 {
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) {
fmsg.Verbosef("command returned %v", err)
hlog.Verbosef("command returned %v", err)
if errors.Is(err, errSuccess) {
fmsg.BeforeExit()
hlog.BeforeExit()
os.Exit(0)
}
})
@ -67,16 +67,13 @@ func buildCommand(out io.Writer) command.Command {
flagVerbose bool
flagJSON bool
)
c := command.New(out, log.Printf, "fortify", func([]string) error {
internal.InstallFmsg(flagVerbose)
return nil
}).
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
c := command.New(out, log.Printf, "hakurei", func([]string) error { internal.InstallFmsg(flagVerbose); return nil }).
Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
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("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 {
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 {
// initialise config from flags
config := &fst.Config{
config := &hst.Config{
ID: fid,
Args: args,
}
@ -123,19 +120,19 @@ func buildCommand(out io.Writer) command.Command {
passwdFunc = func() {
var us string
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)
} else {
us = strconv.Itoa(uid)
}
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{
Uid: us,
Gid: us,
Username: "chronos",
Name: "Fortify",
Name: "Hakurei Permissive Default",
HomeDir: "/var/empty",
}
} else {
@ -233,7 +230,7 @@ func buildCommand(out io.Writer) command.Command {
}
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) {
case 0: // system
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")
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)
return errSuccess
}).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())
return errSuccess
})
@ -269,7 +266,7 @@ func buildCommand(out io.Writer) command.Command {
})
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
})
@ -281,7 +278,7 @@ func buildCommand(out io.Writer) command.Command {
return c
}
func runApp(config *fst.Config) {
func runApp(config *hst.Config) {
ctx, stop := signal.NotifyContext(context.Background(),
syscall.SIGINT, syscall.SIGTERM)
defer stop() // unreachable
@ -289,7 +286,7 @@ func runApp(config *fst.Config) {
rs := new(app.RunState)
if sa, err := a.Seal(config); err != nil {
fmsg.PrintBaseError(err, "cannot seal app:")
hlog.PrintBaseError(err, "cannot seal app:")
internal.Exit(1)
} else {
internal.Exit(instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs)))

View File

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

View File

@ -18,7 +18,7 @@ let
optionals
;
cfg = config.environment.fortify;
cfg = config.environment.hakurei;
getsubuid = fid: aid: 1000000 + fid * 10000 + aid;
getsubname = fid: aid: "u${toString fid}_a${toString aid}";
@ -45,20 +45,21 @@ in
in
{
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 = {
source = "${cfg.fsuPackage}/bin/fsu";
security.wrappers.hsu = {
source = "${cfg.hsuPackage}/bin/hsu";
setuid = true;
owner = "root";
setgid = true;
group = "root";
};
environment.etc.fsurc = {
environment.etc.hsurc = {
mode = "0400";
text = foldlAttrs (
acc: username: fid:
@ -200,7 +201,7 @@ in
};
in
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: {
isSystemUser = 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;
home = getsubhome 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:*
` <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:*
` <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 = {
environment.fortify = {
enable = mkEnableOption "fortify";
environment.hakurei = {
enable = mkEnableOption "hakurei";
package = mkOption {
type = types.package;
default = packages.${pkgs.system}.fortify;
description = "The fortify package to use.";
default = packages.${pkgs.system}.hakurei;
description = "The hakurei package to use.";
};
fsuPackage = mkOption {
hsuPackage = mkOption {
type = types.package;
default = packages.${pkgs.system}.fsu;
description = "The fsu package to use.";
default = packages.${pkgs.system}.hsu;
description = "The hsu package to use.";
};
users = mkOption {
@ -61,7 +61,7 @@ in
in
attrsOf (ints.between 0 99);
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 = { };
description = ''
Declaratively configured fortify apps.
Declaratively configured hakurei apps.
'';
};

View File

@ -30,13 +30,13 @@
}:
buildGoModule rec {
pname = "fortify";
pname = "hakurei";
version = "0.4.1";
srcFiltered = builtins.path {
name = "${pname}-src";
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;
@ -65,7 +65,7 @@ buildGoModule rec {
lib.attrsets.foldlAttrs
(
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" ]
@ -76,7 +76,7 @@ buildGoModule rec {
)
{
version = "v${version}";
fsu = "/run/wrappers/bin/fsu";
hsu = "/run/wrappers/bin/hsu";
};
# nix build environment does not allow acls
@ -113,7 +113,7 @@ buildGoModule rec {
mkdir "$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}
makeBinaryWrapper "$out/libexec/fpkg" "$out/bin/fpkg" \

View File

@ -10,19 +10,19 @@ import (
"strings"
"syscall"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"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
config = new(fst.Config)
config = new(hst.Config)
if name != "-" {
r = tryFd(name)
if r == nil {
fmsg.Verbose("load configuration from file")
hlog.Verbose("load configuration from file")
if f, err := os.Open(name); err != nil {
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 {
if v, err := strconv.Atoi(name); err != nil {
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
} else {
fmsg.Verbosef("trying config stream from %d", v)
hlog.Verbosef("trying config stream from %d", v)
fd := uintptr(v)
if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_GETFD, 0); errno != 0 {
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
if len(name) <= 32 {
likePrefix = true
@ -85,7 +85,7 @@ func tryShort(name string) (config *fst.Config, entry *state.State) {
// try to match from state store
if likePrefix && len(name) >= 8 {
fmsg.Verbose("argument looks like prefix")
hlog.Verbose("argument looks like prefix")
s := state.NewMulti(std.Paths().RunDirPath)
if entries, err := state.Join(s); err != nil {
@ -101,7 +101,7 @@ func tryShort(name string) (config *fst.Config, entry *state.State) {
break
}
fmsg.Verbosef("instance %s skipped", v)
hlog.Verbosef("instance %s skipped", v)
}
}
}

View File

@ -12,21 +12,21 @@ import (
"text/tabwriter"
"time"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/fmsg"
"git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/hlog"
"git.gensokyo.uk/security/hakurei/internal/state"
)
func printShowSystem(output io.Writer, short, flagJSON bool) {
t := newPrinter(output)
defer t.MustFlush()
info := new(fst.Info)
info := new(hst.Info)
// get fid by querying uid of aid 0
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)
} else {
info.User = (uid / 10000) - 100
@ -42,7 +42,7 @@ func printShowSystem(output io.Writer, short, flagJSON bool) {
func printShowInstance(
output io.Writer, now time.Time,
instance *state.State, config *fst.Config,
instance *state.State, config *hst.Config,
short, flagJSON bool) {
if flagJSON {
if instance != nil {
@ -69,9 +69,9 @@ func printShowInstance(
t.Printf("App\n")
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 {
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())
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)
id := e.Config.ID
if id == "" {
id = "uk.gensokyo.fortify." + e.s[:8]
id = "uk.gensokyo.hakurei." + e.s[:8]
}
as += " (" + id + ")"
}

View File

@ -5,10 +5,10 @@ import (
"testing"
"time"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/app"
"git.gensokyo.uk/security/fortify/internal/state"
"git.gensokyo.uk/security/hakurei/dbus"
"git.gensokyo.uk/security/hakurei/hst"
"git.gensokyo.uk/security/hakurei/internal/app"
"git.gensokyo.uk/security/hakurei/internal/state"
)
var (
@ -21,7 +21,7 @@ var (
testState = &state.State{
ID: testID,
PID: 0xDEADBEEF,
Config: fst.Template(),
Config: hst.Template(),
Time: testAppTime,
}
testTime = time.Unix(3752, 1).UTC()
@ -32,15 +32,15 @@ func Test_printShowInstance(t *testing.T) {
testCases := []struct {
name string
instance *state.State
config *fst.Config
config *hst.Config
short, json bool
want string
}{
{"config", nil, fst.Template(), false, false, `App
ID: 9 (org.chromium.Chromium)
{"config", nil, hst.Template(), false, false, `App
Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pulseaudio
Groups: video, dialout, plugdev
Data: /var/lib/fortify/u0/org.chromium.Chromium
Data: /var/lib/hakurei/u0/org.chromium.Chromium
Hostname: localhost
Flags: userns devel net device tty mapuid autoetc
Etc: /etc
@ -53,12 +53,12 @@ Filesystem
+/run/current-system
+/run/opengl-driver
+/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
Extra ACL
--x+:/var/lib/fortify/u0
rwx:/var/lib/fortify/u0/org.chromium.Chromium
--x+:/var/lib/hakurei/u0
rwx:/var/lib/hakurei/u0/org.chromium.Chromium
Session bus
Filter: true
@ -72,23 +72,23 @@ System bus
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
ID: 0
Identity: 0
Enablements: (no enablements)
`},
{"config flag none", nil, &fst.Config{Container: new(fst.ContainerConfig)}, false, false, `App
ID: 0
{"config flag none", nil, &hst.Config{Container: new(hst.ContainerConfig)}, false, false, `App
Identity: 0
Enablements: (no enablements)
Flags: none
Etc: /etc
Path:
`},
{"config nil entries", nil, &fst.Config{Container: &fst.ContainerConfig{Filesystem: make([]*fst.FilesystemConfig, 1)}, ExtraPerms: make([]*fst.ExtraPermConfig, 1)}, false, false, `App
ID: 0
{"config nil entries", nil, &hst.Config{Container: &hst.ContainerConfig{Filesystem: make([]*hst.FilesystemConfig, 1)}, ExtraPerms: make([]*hst.ExtraPermConfig, 1)}, false, false, `App
Identity: 0
Enablements: (no enablements)
Flags: none
Etc: /etc
@ -99,10 +99,10 @@ Filesystem
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
ID: 0
Identity: 0
Enablements: (no enablements)
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)
Uptime: 1h2m32s
App
ID: 9 (org.chromium.Chromium)
Identity: 9 (org.chromium.Chromium)
Enablements: wayland, dbus, pulseaudio
Groups: video, dialout, plugdev
Data: /var/lib/fortify/u0/org.chromium.Chromium
Data: /var/lib/hakurei/u0/org.chromium.Chromium
Hostname: localhost
Flags: userns devel net device tty mapuid autoetc
Etc: /etc
@ -132,12 +132,12 @@ Filesystem
+/run/current-system
+/run/opengl-driver
+/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
Extra ACL
--x+:/var/lib/fortify/u0
rwx:/var/lib/fortify/u0/org.chromium.Chromium
--x+:/var/lib/hakurei/u0
rwx:/var/lib/hakurei/u0/org.chromium.Chromium
Session bus
Filter: true
@ -151,14 +151,14 @@ System bus
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
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
Uptime: 1h2m32s
App
ID: 0
Identity: 0
Enablements: (no enablements)
`},
@ -234,16 +234,16 @@ App
},
"username": "chronos",
"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",
"extra_perms": [
{
"ensure": true,
"path": "/var/lib/fortify/u0",
"path": "/var/lib/hakurei/u0",
"x": true
},
{
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true,
"w": true,
"x": true
@ -285,7 +285,7 @@ App
},
{
"dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": true,
"require": true
},
@ -310,7 +310,7 @@ App
"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",
"path": "/run/current-system/sw/bin/chromium",
"args": [
@ -359,16 +359,16 @@ App
},
"username": "chronos",
"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",
"extra_perms": [
{
"ensure": true,
"path": "/var/lib/fortify/u0",
"path": "/var/lib/hakurei/u0",
"x": true
},
{
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true,
"w": true,
"x": true
@ -410,7 +410,7 @@ App
},
{
"dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": 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"},
{"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
8e2c76b0 256 0 (uk.gensokyo.fortify.8e2c76b0) 1h2m32s
{"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.hakurei.8e2c76b0) 1h2m32s
`},
{"valid", state.Entries{testID: testState}, false, false, ` Instance PID Application Uptime
@ -538,16 +538,16 @@ func Test_printPs(t *testing.T) {
},
"username": "chronos",
"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",
"extra_perms": [
{
"ensure": true,
"path": "/var/lib/fortify/u0",
"path": "/var/lib/hakurei/u0",
"x": true
},
{
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
"r": true,
"w": true,
"x": true
@ -589,7 +589,7 @@ func Test_printPs(t *testing.T) {
},
{
"dst": "/data/data/org.chromium.Chromium",
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
"write": true,
"require": true
},

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@ import (
"syscall"
"time"
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
)
const (
@ -24,7 +24,7 @@ const (
basePath = "/tmp"
// setup params file descriptor
setupEnv = "FORTIFY_SETUP"
setupEnv = "HAKUREI_SETUP"
)
type initParams struct {
@ -56,7 +56,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
log.Fatal("invalid setup descriptor")
}
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)

View File

@ -7,7 +7,7 @@ import (
"path/filepath"
"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 {

View File

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

View File

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

View File

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

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