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
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:
parent
3992073212
commit
87e008d56d
@ -20,5 +20,5 @@ jobs:
|
|||||||
uses: https://gitea.com/actions/release-action@main
|
uses: https://gitea.com/actions/release-action@main
|
||||||
with:
|
with:
|
||||||
files: |-
|
files: |-
|
||||||
result/fortify-**
|
result/hakurei-**
|
||||||
api_key: '${{secrets.RELEASE_TOKEN}}'
|
api_key: '${{secrets.RELEASE_TOKEN}}'
|
||||||
|
@ -5,25 +5,25 @@ on:
|
|||||||
- pull_request
|
- pull_request
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
fortify:
|
hakurei:
|
||||||
name: Fortify
|
name: Hakurei
|
||||||
runs-on: nix
|
runs-on: nix
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Run NixOS test
|
- name: Run NixOS test
|
||||||
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.fortify
|
run: nix build --out-link "result" --print-out-paths --print-build-logs .#checks.x86_64-linux.hakurei
|
||||||
|
|
||||||
- name: Upload test output
|
- name: Upload test output
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "fortify-vm-output"
|
name: "hakurei-vm-output"
|
||||||
path: result/*
|
path: result/*
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
race:
|
race:
|
||||||
name: Fortify (race detector)
|
name: Hakurei (race detector)
|
||||||
runs-on: nix
|
runs-on: nix
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@ -35,7 +35,7 @@ jobs:
|
|||||||
- name: Upload test output
|
- name: Upload test output
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "fortify-race-vm-output"
|
name: "hakurei-race-vm-output"
|
||||||
path: result/*
|
path: result/*
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ jobs:
|
|||||||
check:
|
check:
|
||||||
name: Flake checks
|
name: Flake checks
|
||||||
needs:
|
needs:
|
||||||
- fortify
|
- hakurei
|
||||||
- race
|
- race
|
||||||
- sandbox
|
- sandbox
|
||||||
- sandbox-race
|
- sandbox-race
|
||||||
@ -116,15 +116,15 @@ jobs:
|
|||||||
- name: Build for test
|
- name: Build for test
|
||||||
id: build-test
|
id: build-test
|
||||||
run: >-
|
run: >-
|
||||||
export FORTIFY_REV="$(git rev-parse --short HEAD)" &&
|
export HAKUREI_REV="$(git rev-parse --short HEAD)" &&
|
||||||
sed -i.old 's/version = /version = "0.0.0-'$FORTIFY_REV'"; # version = /' package.nix &&
|
sed -i.old 's/version = /version = "0.0.0-'$HAKUREI_REV'"; # version = /' package.nix &&
|
||||||
nix build --print-out-paths --print-build-logs .#dist &&
|
nix build --print-out-paths --print-build-logs .#dist &&
|
||||||
mv package.nix.old package.nix &&
|
mv package.nix.old package.nix &&
|
||||||
echo "rev=$FORTIFY_REV" >> $GITHUB_OUTPUT
|
echo "rev=$HAKUREI_REV" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Upload test build
|
- name: Upload test build
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: "fortify-${{ steps.build-test.outputs.rev }}"
|
name: "hakurei-${{ steps.build-test.outputs.rev }}"
|
||||||
path: result/*
|
path: result/*
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -5,7 +5,7 @@
|
|||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
*.pkg
|
*.pkg
|
||||||
/fortify
|
/hakurei
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# Test binary, built with `go test -c`
|
||||||
*.test
|
*.test
|
||||||
@ -29,4 +29,4 @@ go.work.sum
|
|||||||
security-context-v1-protocol.*
|
security-context-v1-protocol.*
|
||||||
|
|
||||||
# release
|
# release
|
||||||
/dist/fortify-*
|
/dist/hakurei-*
|
24
README.md
24
README.md
@ -1,8 +1,8 @@
|
|||||||
Fortify
|
Hakurei
|
||||||
=======
|
=======
|
||||||
|
|
||||||
[](https://pkg.go.dev/git.gensokyo.uk/security/fortify)
|
[](https://pkg.go.dev/git.gensokyo.uk/security/hakurei)
|
||||||
[](https://goreportcard.com/report/git.gensokyo.uk/security/fortify)
|
[](https://goreportcard.com/report/git.gensokyo.uk/security/hakurei)
|
||||||
|
|
||||||
Lets you run graphical applications as another user in a confined environment with a nice NixOS
|
Lets you run graphical applications as another user in a confined environment with a nice NixOS
|
||||||
module to configure target users and provide launchers and desktop files for your privileged user.
|
module to configure target users and provide launchers and desktop files for your privileged user.
|
||||||
@ -18,7 +18,7 @@ Why would you want this?
|
|||||||
If you have a flakes-enabled nix environment, you can try out the tool by running:
|
If you have a flakes-enabled nix environment, you can try out the tool by running:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
nix run git+https://git.gensokyo.uk/security/fortify -- help
|
nix run git+https://git.gensokyo.uk/security/hakurei -- help
|
||||||
```
|
```
|
||||||
|
|
||||||
## Module usage
|
## Module usage
|
||||||
@ -34,35 +34,35 @@ To use the module, import it into your configuration with
|
|||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||||
|
|
||||||
fortify = {
|
hakurei = {
|
||||||
url = "git+https://git.gensokyo.uk/security/fortify";
|
url = "git+https://git.gensokyo.uk/security/hakurei";
|
||||||
|
|
||||||
# Optional but recommended to limit the size of your system closure.
|
# Optional but recommended to limit the size of your system closure.
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, fortify, ... }:
|
outputs = { self, nixpkgs, hakurei, ... }:
|
||||||
{
|
{
|
||||||
nixosConfigurations.fortify = nixpkgs.lib.nixosSystem {
|
nixosConfigurations.hakurei = nixpkgs.lib.nixosSystem {
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
modules = [
|
modules = [
|
||||||
fortify.nixosModules.fortify
|
hakurei.nixosModules.hakurei
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
This adds the `environment.fortify` option:
|
This adds the `environment.hakurei` option:
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
environment.fortify = {
|
environment.hakurei = {
|
||||||
enable = true;
|
enable = true;
|
||||||
stateDir = "/var/lib/fortify";
|
stateDir = "/var/lib/hakurei";
|
||||||
users = {
|
users = {
|
||||||
alice = 0;
|
alice = 0;
|
||||||
nixos = 10;
|
nixos = 10;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/acl.h>
|
#include <sys/acl.h>
|
||||||
|
|
||||||
int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
|
int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
|
||||||
size_t plen) {
|
size_t plen) {
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
bool v;
|
bool v;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include <sys/acl.h>
|
#include <sys/acl.h>
|
||||||
|
|
||||||
int f_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
|
int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, acl_perm_t *perms,
|
||||||
size_t plen);
|
size_t plen);
|
||||||
|
@ -23,7 +23,7 @@ func Update(name string, uid int, perms ...Perm) error {
|
|||||||
p = &perms[0]
|
p = &perms[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
r, err := C.f_acl_update_file_by_uid(
|
r, err := C.hakurei_acl_update_file_by_uid(
|
||||||
C.CString(name),
|
C.CString(name),
|
||||||
C.uid_t(uid),
|
C.uid_t(uid),
|
||||||
(*C.acl_perm_t)(p),
|
(*C.acl_perm_t)(p),
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/acl"
|
"git.gensokyo.uk/security/hakurei/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
const testFileName = "acl.test"
|
const testFileName = "acl.test"
|
||||||
|
@ -6,46 +6,46 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
type appInfo struct {
|
type appInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
|
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Identity int `json:"identity"`
|
Identity int `json:"identity"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Groups []string `json:"groups,omitempty"`
|
Groups []string `json:"groups,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Devel bool `json:"devel,omitempty"`
|
Devel bool `json:"devel,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Userns bool `json:"userns,omitempty"`
|
Userns bool `json:"userns,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Net bool `json:"net,omitempty"`
|
Net bool `json:"net,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Device bool `json:"dev,omitempty"`
|
Device bool `json:"dev,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Tty bool `json:"tty,omitempty"`
|
Tty bool `json:"tty,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
MapRealUID bool `json:"map_real_uid,omitempty"`
|
MapRealUID bool `json:"map_real_uid,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
DirectWayland bool `json:"direct_wayland,omitempty"`
|
DirectWayland bool `json:"direct_wayland,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
SystemBus *dbus.Config `json:"system_bus,omitempty"`
|
SystemBus *dbus.Config `json:"system_bus,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
SessionBus *dbus.Config `json:"session_bus,omitempty"`
|
SessionBus *dbus.Config `json:"session_bus,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Enablements system.Enablement `json:"enablements"`
|
Enablements system.Enablement `json:"enablements"`
|
||||||
|
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Multiarch bool `json:"multiarch,omitempty"`
|
Multiarch bool `json:"multiarch,omitempty"`
|
||||||
// passed through to [fst.Config]
|
// passed through to [hst.Config]
|
||||||
Bluetooth bool `json:"bluetooth,omitempty"`
|
Bluetooth bool `json:"bluetooth,omitempty"`
|
||||||
|
|
||||||
// allow gpu access within sandbox
|
// allow gpu access within sandbox
|
||||||
@ -62,8 +62,8 @@ type appInfo struct {
|
|||||||
ActivationPackage string `json:"activation_package"`
|
ActivationPackage string `json:"activation_package"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool) *fst.Config {
|
func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool) *hst.Config {
|
||||||
config := &fst.Config{
|
config := &hst.Config{
|
||||||
ID: app.ID,
|
ID: app.ID,
|
||||||
|
|
||||||
Path: argv[0],
|
Path: argv[0],
|
||||||
@ -75,7 +75,7 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
|
|||||||
SessionBus: app.SessionBus,
|
SessionBus: app.SessionBus,
|
||||||
DirectWayland: app.DirectWayland,
|
DirectWayland: app.DirectWayland,
|
||||||
|
|
||||||
Username: "fortify",
|
Username: "hakurei",
|
||||||
Shell: shellPath,
|
Shell: shellPath,
|
||||||
Data: pathSet.homeDir,
|
Data: pathSet.homeDir,
|
||||||
Dir: path.Join("/data/data", app.ID),
|
Dir: path.Join("/data/data", app.ID),
|
||||||
@ -83,7 +83,7 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
|
|||||||
Identity: app.Identity,
|
Identity: app.Identity,
|
||||||
Groups: app.Groups,
|
Groups: app.Groups,
|
||||||
|
|
||||||
Container: &fst.ContainerConfig{
|
Container: &hst.ContainerConfig{
|
||||||
Hostname: formatHostname(app.Name),
|
Hostname: formatHostname(app.Name),
|
||||||
Devel: app.Devel,
|
Devel: app.Devel,
|
||||||
Userns: app.Userns,
|
Userns: app.Userns,
|
||||||
@ -91,9 +91,9 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
|
|||||||
Device: app.Device,
|
Device: app.Device,
|
||||||
Tty: app.Tty || flagDropShell,
|
Tty: app.Tty || flagDropShell,
|
||||||
MapRealUID: app.MapRealUID,
|
MapRealUID: app.MapRealUID,
|
||||||
Filesystem: []*fst.FilesystemConfig{
|
Filesystem: []*hst.FilesystemConfig{
|
||||||
{Src: path.Join(pathSet.nixPath, "store"), Dst: "/nix/store", Must: true},
|
{Src: path.Join(pathSet.nixPath, "store"), Dst: "/nix/store", Must: true},
|
||||||
{Src: pathSet.metaPath, Dst: path.Join(fst.Tmp, "app"), Must: true},
|
{Src: pathSet.metaPath, Dst: path.Join(hst.Tmp, "app"), Must: true},
|
||||||
{Src: "/etc/resolv.conf"},
|
{Src: "/etc/resolv.conf"},
|
||||||
{Src: "/sys/block"},
|
{Src: "/sys/block"},
|
||||||
{Src: "/sys/bus"},
|
{Src: "/sys/bus"},
|
||||||
@ -109,7 +109,7 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
|
|||||||
Etc: path.Join(pathSet.cacheDir, "etc"),
|
Etc: path.Join(pathSet.cacheDir, "etc"),
|
||||||
AutoEtc: true,
|
AutoEtc: true,
|
||||||
},
|
},
|
||||||
ExtraPerms: []*fst.ExtraPermConfig{
|
ExtraPerms: []*hst.ExtraPermConfig{
|
||||||
{Path: dataHome, Execute: true},
|
{Path: dataHome, Execute: true},
|
||||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||||
},
|
},
|
||||||
@ -147,7 +147,7 @@ func loadAppInfo(name string, beforeFail func()) *appInfo {
|
|||||||
func formatHostname(name string) string {
|
func formatHostname(name string) string {
|
||||||
if h, err := os.Hostname(); err != nil {
|
if h, err := os.Hostname(); err != nil {
|
||||||
log.Printf("cannot get hostname: %v", err)
|
log.Printf("cannot get hostname: %v", err)
|
||||||
return "fortify-" + name
|
return "hakurei-" + name
|
||||||
} else {
|
} else {
|
||||||
return h + "-" + name
|
return h + "-" + name
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ let
|
|||||||
modules = modules ++ [
|
modules = modules ++ [
|
||||||
{
|
{
|
||||||
home = {
|
home = {
|
||||||
username = "fortify";
|
username = "hakurei";
|
||||||
homeDirectory = "/data/data/${id}";
|
homeDirectory = "/data/data/${id}";
|
||||||
stateVersion = "22.11";
|
stateVersion = "22.11";
|
||||||
};
|
};
|
||||||
@ -65,7 +65,7 @@ let
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
launcher = writeScript "fortify-${pname}" ''
|
launcher = writeScript "hakurei-${pname}" ''
|
||||||
#!${runtimeShell} -el
|
#!${runtimeShell} -el
|
||||||
${script}
|
${script}
|
||||||
'';
|
'';
|
||||||
|
@ -10,13 +10,13 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/command"
|
"git.gensokyo.uk/security/hakurei/command"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app/instance"
|
"git.gensokyo.uk/security/hakurei/internal/app/instance"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
const shellPath = "/run/current-system/sw/bin/bash"
|
const shellPath = "/run/current-system/sw/bin/bash"
|
||||||
@ -28,7 +28,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
fmsg.Prepare("fpkg")
|
hlog.Prepare("fpkg")
|
||||||
if err := os.Setenv("SHELL", shellPath); err != nil {
|
if err := os.Setenv("SHELL", shellPath); err != nil {
|
||||||
log.Fatalf("cannot set $SHELL: %v", err)
|
log.Fatalf("cannot set $SHELL: %v", err)
|
||||||
}
|
}
|
||||||
@ -36,7 +36,7 @@ func init() {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// early init path, skips root check and duplicate PR_SET_DUMPABLE
|
// early init path, skips root check and duplicate PR_SET_DUMPABLE
|
||||||
sandbox.TryArgv0(fmsg.Output{}, fmsg.Prepare, internal.InstallFmsg)
|
sandbox.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallFmsg)
|
||||||
|
|
||||||
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
|
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
|
||||||
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
|
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||||
@ -60,7 +60,7 @@ func main() {
|
|||||||
return nil
|
return nil
|
||||||
}).
|
}).
|
||||||
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
|
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
|
||||||
Flag(&flagDropShell, "s", command.BoolFlag(false), "Drop to a shell in place of next fortify action")
|
Flag(&flagDropShell, "s", command.BoolFlag(false), "Drop to a shell in place of next hakurei action")
|
||||||
|
|
||||||
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
|
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
|
||||||
|
|
||||||
@ -166,10 +166,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sec: should compare version string
|
// sec: should compare version string
|
||||||
fmsg.Verbosef("installing application %q version %q over local %q",
|
hlog.Verbosef("installing application %q version %q over local %q",
|
||||||
bundle.ID, bundle.Version, a.Version)
|
bundle.ID, bundle.Version, a.Version)
|
||||||
} else {
|
} else {
|
||||||
fmsg.Verbosef("application %q clean installation", bundle.ID)
|
hlog.Verbosef("application %q clean installation", bundle.ID)
|
||||||
// sec: should install credentials
|
// sec: should install credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ func main() {
|
|||||||
|
|
||||||
withCacheDir(ctx, "install", []string{
|
withCacheDir(ctx, "install", []string{
|
||||||
// export inner bundle path in the environment
|
// export inner bundle path in the environment
|
||||||
"export BUNDLE=" + fst.Tmp + "/bundle",
|
"export BUNDLE=" + hst.Tmp + "/bundle",
|
||||||
// replace inner /etc
|
// replace inner /etc
|
||||||
"mkdir -p etc",
|
"mkdir -p etc",
|
||||||
"chmod -R +w etc",
|
"chmod -R +w etc",
|
||||||
@ -218,7 +218,7 @@ func main() {
|
|||||||
"rm -rf .local/state/{nix,home-manager}",
|
"rm -rf .local/state/{nix,home-manager}",
|
||||||
// run activation script
|
// run activation script
|
||||||
bundle.ActivationPackage + "/activate",
|
bundle.ActivationPackage + "/activate",
|
||||||
}, false, func(config *fst.Config) *fst.Config { return config },
|
}, false, func(config *hst.Config) *hst.Config { return config },
|
||||||
bundle, pathSet, flagDropShellActivate, cleanup)
|
bundle, pathSet, flagDropShellActivate, cleanup)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -291,8 +291,8 @@ func main() {
|
|||||||
"--out-link /nix/.nixGL/auto/vulkan " +
|
"--out-link /nix/.nixGL/auto/vulkan " +
|
||||||
"--override-input nixpkgs path:/etc/nixpkgs " +
|
"--override-input nixpkgs path:/etc/nixpkgs " +
|
||||||
"path:" + a.NixGL + "#nixVulkanNvidia",
|
"path:" + a.NixGL + "#nixVulkanNvidia",
|
||||||
}, true, func(config *fst.Config) *fst.Config {
|
}, true, func(config *hst.Config) *hst.Config {
|
||||||
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{
|
config.Container.Filesystem = append(config.Container.Filesystem, []*hst.FilesystemConfig{
|
||||||
{Src: "/etc/resolv.conf"},
|
{Src: "/etc/resolv.conf"},
|
||||||
{Src: "/sys/block"},
|
{Src: "/sys/block"},
|
||||||
{Src: "/sys/bus"},
|
{Src: "/sys/bus"},
|
||||||
@ -325,7 +325,7 @@ func main() {
|
|||||||
|
|
||||||
if a.GPU {
|
if a.GPU {
|
||||||
config.Container.Filesystem = append(config.Container.Filesystem,
|
config.Container.Filesystem = append(config.Container.Filesystem,
|
||||||
&fst.FilesystemConfig{Src: path.Join(pathSet.nixPath, ".nixGL"), Dst: path.Join(fst.Tmp, "nixGL")})
|
&hst.FilesystemConfig{Src: path.Join(pathSet.nixPath, ".nixGL"), Dst: path.Join(hst.Tmp, "nixGL")})
|
||||||
appendGPUFilesystem(config)
|
appendGPUFilesystem(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,9 +341,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.MustParse(os.Args[1:], func(err error) {
|
c.MustParse(os.Args[1:], func(err error) {
|
||||||
fmsg.Verbosef("command returned %v", err)
|
hlog.Verbosef("command returned %v", err)
|
||||||
if errors.Is(err, errSuccess) {
|
if errors.Is(err, errSuccess) {
|
||||||
fmsg.BeforeExit()
|
hlog.BeforeExit()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -18,10 +18,10 @@ var (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// dataHome
|
// dataHome
|
||||||
if p, ok := os.LookupEnv("FORTIFY_DATA_HOME"); ok {
|
if p, ok := os.LookupEnv("HAKUREI_DATA_HOME"); ok {
|
||||||
dataHome = p
|
dataHome = p
|
||||||
} else {
|
} else {
|
||||||
dataHome = "/var/lib/fortify/" + strconv.Itoa(os.Getuid())
|
dataHome = "/var/lib/hakurei/" + strconv.Itoa(os.Getuid())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ func lookPath(file string) string {
|
|||||||
var beforeRunFail = new(atomic.Pointer[func()])
|
var beforeRunFail = new(atomic.Pointer[func()])
|
||||||
|
|
||||||
func mustRun(name string, arg ...string) {
|
func mustRun(name string, arg ...string) {
|
||||||
fmsg.Verbosef("spawning process: %q %q", name, arg)
|
hlog.Verbosef("spawning process: %q %q", name, arg)
|
||||||
cmd := exec.Command(name, arg...)
|
cmd := exec.Command(name, arg...)
|
||||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||||
if err := cmd.Run(); err != nil {
|
if err := cmd.Run(); err != nil {
|
||||||
@ -71,8 +71,8 @@ func pathSetByApp(id string) *appPathSet {
|
|||||||
return pathSet
|
return pathSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendGPUFilesystem(config *fst.Config) {
|
func appendGPUFilesystem(config *hst.Config) {
|
||||||
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{
|
config.Container.Filesystem = append(config.Container.Filesystem, []*hst.FilesystemConfig{
|
||||||
// flatpak commit 763a686d874dd668f0236f911de00b80766ffe79
|
// flatpak commit 763a686d874dd668f0236f911de00b80766ffe79
|
||||||
{Src: "/dev/dri", Device: true},
|
{Src: "/dev/dri", Device: true},
|
||||||
// mali
|
// mali
|
||||||
|
@ -4,19 +4,19 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app/instance"
|
"git.gensokyo.uk/security/hakurei/internal/app/instance"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustRunApp(ctx context.Context, config *fst.Config, beforeFail func()) {
|
func mustRunApp(ctx context.Context, config *hst.Config, beforeFail func()) {
|
||||||
rs := new(app.RunState)
|
rs := new(app.RunState)
|
||||||
a := instance.MustNew(instance.ISetuid, ctx, std)
|
a := instance.MustNew(instance.ISetuid, ctx, std)
|
||||||
|
|
||||||
var code int
|
var code int
|
||||||
if sa, err := a.Seal(config); err != nil {
|
if sa, err := a.Seal(config); err != nil {
|
||||||
fmsg.PrintBaseError(err, "cannot seal app:")
|
hlog.PrintBaseError(err, "cannot seal app:")
|
||||||
code = 1
|
code = 1
|
||||||
} else {
|
} else {
|
||||||
code = instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs))
|
code = instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs))
|
||||||
|
@ -50,9 +50,9 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.fortify = {
|
environment.hakurei = {
|
||||||
enable = true;
|
enable = true;
|
||||||
stateDir = "/var/lib/fortify";
|
stateDir = "/var/lib/hakurei";
|
||||||
users.alice = 0;
|
users.alice = 0;
|
||||||
|
|
||||||
extraHomeConfig = {
|
extraHomeConfig = {
|
||||||
|
@ -18,7 +18,7 @@ nixosTest {
|
|||||||
imports = [
|
imports = [
|
||||||
./configuration.nix
|
./configuration.nix
|
||||||
|
|
||||||
self.nixosModules.fortify
|
self.nixosModules.hakurei
|
||||||
self.inputs.home-manager.nixosModules.home-manager
|
self.inputs.home-manager.nixosModules.home-manager
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@ -47,22 +47,22 @@ def wait_for_window(pattern):
|
|||||||
|
|
||||||
|
|
||||||
def collect_state_ui(name):
|
def collect_state_ui(name):
|
||||||
swaymsg(f"exec fortify ps > '/tmp/{name}.ps'")
|
swaymsg(f"exec hakurei ps > '/tmp/{name}.ps'")
|
||||||
machine.copy_from_vm(f"/tmp/{name}.ps", "")
|
machine.copy_from_vm(f"/tmp/{name}.ps", "")
|
||||||
swaymsg(f"exec fortify --json ps > '/tmp/{name}.json'")
|
swaymsg(f"exec hakurei --json ps > '/tmp/{name}.json'")
|
||||||
machine.copy_from_vm(f"/tmp/{name}.json", "")
|
machine.copy_from_vm(f"/tmp/{name}.json", "")
|
||||||
machine.screenshot(name)
|
machine.screenshot(name)
|
||||||
|
|
||||||
|
|
||||||
def check_state(name, enablements):
|
def check_state(name, enablements):
|
||||||
instances = json.loads(machine.succeed("sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 fortify --json ps"))
|
instances = json.loads(machine.succeed("sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 hakurei --json ps"))
|
||||||
if len(instances) != 1:
|
if len(instances) != 1:
|
||||||
raise Exception(f"unexpected state length {len(instances)}")
|
raise Exception(f"unexpected state length {len(instances)}")
|
||||||
instance = next(iter(instances.values()))
|
instance = next(iter(instances.values()))
|
||||||
|
|
||||||
config = instance['config']
|
config = instance['config']
|
||||||
|
|
||||||
if len(config['args']) != 1 or not (config['args'][0].startswith("/nix/store/")) or f"fortify-{name}-" not in (config['args'][0]):
|
if len(config['args']) != 1 or not (config['args'][0].startswith("/nix/store/")) or f"hakurei-{name}-" not in (config['args'][0]):
|
||||||
raise Exception(f"unexpected args {instance['config']['args']}")
|
raise Exception(f"unexpected args {instance['config']['args']}")
|
||||||
|
|
||||||
if config['enablements'] != enablements:
|
if config['enablements'] != enablements:
|
||||||
@ -72,15 +72,15 @@ def check_state(name, enablements):
|
|||||||
start_all()
|
start_all()
|
||||||
machine.wait_for_unit("multi-user.target")
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
# To check fortify's version:
|
# To check hakurei's version:
|
||||||
print(machine.succeed("sudo -u alice -i fortify version"))
|
print(machine.succeed("sudo -u alice -i hakurei version"))
|
||||||
|
|
||||||
# Wait for Sway to complete startup:
|
# Wait for Sway to complete startup:
|
||||||
machine.wait_for_file("/run/user/1000/wayland-1")
|
machine.wait_for_file("/run/user/1000/wayland-1")
|
||||||
machine.wait_for_file("/tmp/sway-ipc.sock")
|
machine.wait_for_file("/tmp/sway-ipc.sock")
|
||||||
|
|
||||||
# Prepare fpkg directory:
|
# Prepare fpkg directory:
|
||||||
machine.succeed("install -dm 0700 -o alice -g users /var/lib/fortify/1000")
|
machine.succeed("install -dm 0700 -o alice -g users /var/lib/hakurei/1000")
|
||||||
|
|
||||||
# Install fpkg app:
|
# Install fpkg app:
|
||||||
swaymsg("exec fpkg -v install /etc/foot.pkg && touch /tmp/fpkg-install-done")
|
swaymsg("exec fpkg -v install /etc/foot.pkg && touch /tmp/fpkg-install-done")
|
||||||
@ -88,9 +88,9 @@ machine.wait_for_file("/tmp/fpkg-install-done")
|
|||||||
|
|
||||||
# Start app (foot) with Wayland enablement:
|
# Start app (foot) with Wayland enablement:
|
||||||
swaymsg("exec fpkg -v start org.codeberg.dnkl.foot")
|
swaymsg("exec fpkg -v start org.codeberg.dnkl.foot")
|
||||||
wait_for_window("fortify@machine-foot")
|
wait_for_window("hakurei@machine-foot")
|
||||||
machine.send_chars("clear; wayland-info && touch /tmp/success-client\n")
|
machine.send_chars("clear; wayland-info && touch /tmp/success-client\n")
|
||||||
machine.wait_for_file("/tmp/fortify.1000/tmpdir/2/success-client")
|
machine.wait_for_file("/tmp/hakurei.1000/tmpdir/2/success-client")
|
||||||
collect_state_ui("app_wayland")
|
collect_state_ui("app_wayland")
|
||||||
check_state("foot", 13)
|
check_state("foot", 13)
|
||||||
# Verify acl on XDG_RUNTIME_DIR:
|
# Verify acl on XDG_RUNTIME_DIR:
|
||||||
@ -104,5 +104,5 @@ machine.wait_until_fails("getfacl --absolute-names --omit-header --numeric /run/
|
|||||||
swaymsg("exit", succeed=False)
|
swaymsg("exit", succeed=False)
|
||||||
machine.wait_for_file("/tmp/sway-exit-ok")
|
machine.wait_for_file("/tmp/sway-exit-ok")
|
||||||
|
|
||||||
# Print fortify runDir contents:
|
# Print hakurei runDir contents:
|
||||||
print(machine.succeed("find /run/user/1000/fortify"))
|
print(machine.succeed("find /run/user/1000/hakurei"))
|
@ -5,17 +5,17 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func withNixDaemon(
|
func withNixDaemon(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
action string, command []string, net bool, updateConfig func(config *fst.Config) *fst.Config,
|
action string, command []string, net bool, updateConfig func(config *hst.Config) *hst.Config,
|
||||||
app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func(),
|
app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func(),
|
||||||
) {
|
) {
|
||||||
mustRunAppDropShell(ctx, updateConfig(&fst.Config{
|
mustRunAppDropShell(ctx, updateConfig(&hst.Config{
|
||||||
ID: app.ID,
|
ID: app.ID,
|
||||||
|
|
||||||
Path: shellPath,
|
Path: shellPath,
|
||||||
@ -31,24 +31,24 @@ func withNixDaemon(
|
|||||||
" && pkill nix-daemon",
|
" && pkill nix-daemon",
|
||||||
},
|
},
|
||||||
|
|
||||||
Username: "fortify",
|
Username: "hakurei",
|
||||||
Shell: shellPath,
|
Shell: shellPath,
|
||||||
Data: pathSet.homeDir,
|
Data: pathSet.homeDir,
|
||||||
Dir: path.Join("/data/data", app.ID),
|
Dir: path.Join("/data/data", app.ID),
|
||||||
ExtraPerms: []*fst.ExtraPermConfig{
|
ExtraPerms: []*hst.ExtraPermConfig{
|
||||||
{Path: dataHome, Execute: true},
|
{Path: dataHome, Execute: true},
|
||||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||||
},
|
},
|
||||||
|
|
||||||
Identity: app.Identity,
|
Identity: app.Identity,
|
||||||
|
|
||||||
Container: &fst.ContainerConfig{
|
Container: &hst.ContainerConfig{
|
||||||
Hostname: formatHostname(app.Name) + "-" + action,
|
Hostname: formatHostname(app.Name) + "-" + action,
|
||||||
Userns: true, // nix sandbox requires userns
|
Userns: true, // nix sandbox requires userns
|
||||||
Net: net,
|
Net: net,
|
||||||
Seccomp: seccomp.FilterMultiarch,
|
Seccomp: seccomp.FilterMultiarch,
|
||||||
Tty: dropShell,
|
Tty: dropShell,
|
||||||
Filesystem: []*fst.FilesystemConfig{
|
Filesystem: []*hst.FilesystemConfig{
|
||||||
{Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true},
|
{Src: pathSet.nixPath, Dst: "/nix", Write: true, Must: true},
|
||||||
},
|
},
|
||||||
Link: [][2]string{
|
Link: [][2]string{
|
||||||
@ -66,7 +66,7 @@ func withCacheDir(
|
|||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
action string, command []string, workDir string,
|
action string, command []string, workDir string,
|
||||||
app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) {
|
app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) {
|
||||||
mustRunAppDropShell(ctx, &fst.Config{
|
mustRunAppDropShell(ctx, &hst.Config{
|
||||||
ID: app.ID,
|
ID: app.ID,
|
||||||
|
|
||||||
Path: shellPath,
|
Path: shellPath,
|
||||||
@ -76,7 +76,7 @@ func withCacheDir(
|
|||||||
Shell: shellPath,
|
Shell: shellPath,
|
||||||
Data: pathSet.cacheDir, // this also ensures cacheDir via shim
|
Data: pathSet.cacheDir, // this also ensures cacheDir via shim
|
||||||
Dir: path.Join("/data/data", app.ID, "cache"),
|
Dir: path.Join("/data/data", app.ID, "cache"),
|
||||||
ExtraPerms: []*fst.ExtraPermConfig{
|
ExtraPerms: []*hst.ExtraPermConfig{
|
||||||
{Path: dataHome, Execute: true},
|
{Path: dataHome, Execute: true},
|
||||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||||
{Path: workDir, Execute: true},
|
{Path: workDir, Execute: true},
|
||||||
@ -84,13 +84,13 @@ func withCacheDir(
|
|||||||
|
|
||||||
Identity: app.Identity,
|
Identity: app.Identity,
|
||||||
|
|
||||||
Container: &fst.ContainerConfig{
|
Container: &hst.ContainerConfig{
|
||||||
Hostname: formatHostname(app.Name) + "-" + action,
|
Hostname: formatHostname(app.Name) + "-" + action,
|
||||||
Seccomp: seccomp.FilterMultiarch,
|
Seccomp: seccomp.FilterMultiarch,
|
||||||
Tty: dropShell,
|
Tty: dropShell,
|
||||||
Filesystem: []*fst.FilesystemConfig{
|
Filesystem: []*hst.FilesystemConfig{
|
||||||
{Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true},
|
{Src: path.Join(workDir, "nix"), Dst: "/nix", Must: true},
|
||||||
{Src: workDir, Dst: path.Join(fst.Tmp, "bundle"), Must: true},
|
{Src: workDir, Dst: path.Join(hst.Tmp, "bundle"), Must: true},
|
||||||
},
|
},
|
||||||
Link: [][2]string{
|
Link: [][2]string{
|
||||||
{app.CurrentSystem, "/run/current-system"},
|
{app.CurrentSystem, "/run/current-system"},
|
||||||
@ -103,7 +103,7 @@ func withCacheDir(
|
|||||||
}, dropShell, beforeFail)
|
}, dropShell, beforeFail)
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustRunAppDropShell(ctx context.Context, config *fst.Config, dropShell bool, beforeFail func()) {
|
func mustRunAppDropShell(ctx context.Context, config *hst.Config, dropShell bool, beforeFail func()) {
|
||||||
if dropShell {
|
if dropShell {
|
||||||
config.Args = []string{shellPath, "-l"}
|
config.Args = []string{shellPath, "-l"}
|
||||||
mustRunApp(ctx, config, beforeFail)
|
mustRunApp(ctx, config, beforeFail)
|
||||||
|
@ -13,17 +13,17 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
fsuConfFile = "/etc/fsurc"
|
hsuConfFile = "/etc/hsurc"
|
||||||
envShim = "FORTIFY_SHIM"
|
envShim = "HAKUREI_SHIM"
|
||||||
envAID = "FORTIFY_APP_ID"
|
envAID = "HAKUREI_APP_ID"
|
||||||
envGroups = "FORTIFY_GROUPS"
|
envGroups = "HAKUREI_GROUPS"
|
||||||
|
|
||||||
PR_SET_NO_NEW_PRIVS = 0x26
|
PR_SET_NO_NEW_PRIVS = 0x26
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
log.SetPrefix("fsu: ")
|
log.SetPrefix("hsu: ")
|
||||||
log.SetOutput(os.Stderr)
|
log.SetOutput(os.Stderr)
|
||||||
|
|
||||||
if os.Geteuid() != 0 {
|
if os.Geteuid() != 0 {
|
||||||
@ -40,9 +40,9 @@ func main() {
|
|||||||
if p, err := os.Readlink(pexe); err != nil {
|
if p, err := os.Readlink(pexe); err != nil {
|
||||||
log.Fatalf("cannot read parent executable path: %v", err)
|
log.Fatalf("cannot read parent executable path: %v", err)
|
||||||
} else if strings.HasSuffix(p, " (deleted)") {
|
} else if strings.HasSuffix(p, " (deleted)") {
|
||||||
log.Fatal("fortify executable has been deleted")
|
log.Fatal("hakurei executable has been deleted")
|
||||||
} else if p != mustCheckPath(fmain) && p != mustCheckPath(fpkg) {
|
} else if p != mustCheckPath(hmain) && p != mustCheckPath(fpkg) {
|
||||||
log.Fatal("this program must be started by fortify")
|
log.Fatal("this program must be started by hakurei")
|
||||||
} else {
|
} else {
|
||||||
toolPath = p
|
toolPath = p
|
||||||
}
|
}
|
||||||
@ -52,27 +52,27 @@ func main() {
|
|||||||
// aid
|
// aid
|
||||||
uid := 1000000
|
uid := 1000000
|
||||||
|
|
||||||
// refuse to run if fsurc is not protected correctly
|
// refuse to run if hsurc is not protected correctly
|
||||||
if s, err := os.Stat(fsuConfFile); err != nil {
|
if s, err := os.Stat(hsuConfFile); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
} else if s.Mode().Perm() != 0400 {
|
} else if s.Mode().Perm() != 0400 {
|
||||||
log.Fatal("bad fsurc perm")
|
log.Fatal("bad hsurc perm")
|
||||||
} else if st := s.Sys().(*syscall.Stat_t); st.Uid != 0 || st.Gid != 0 {
|
} else if st := s.Sys().(*syscall.Stat_t); st.Uid != 0 || st.Gid != 0 {
|
||||||
log.Fatal("fsurc must be owned by uid 0")
|
log.Fatal("hsurc must be owned by uid 0")
|
||||||
}
|
}
|
||||||
|
|
||||||
// authenticate before accepting user input
|
// authenticate before accepting user input
|
||||||
if f, err := os.Open(fsuConfFile); err != nil {
|
if f, err := os.Open(hsuConfFile); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
} else if fid, ok := mustParseConfig(f, puid); !ok {
|
} else if fid, ok := mustParseConfig(f, puid); !ok {
|
||||||
log.Fatalf("uid %d is not in the fsurc file", puid)
|
log.Fatalf("uid %d is not in the hsurc file", puid)
|
||||||
} else {
|
} else {
|
||||||
uid += fid * 10000
|
uid += fid * 10000
|
||||||
}
|
}
|
||||||
|
|
||||||
// allowed aid range 0 to 9999
|
// allowed aid range 0 to 9999
|
||||||
if as, ok := os.LookupEnv(envAID); !ok {
|
if as, ok := os.LookupEnv(envAID); !ok {
|
||||||
log.Fatal("FORTIFY_APP_ID not set")
|
log.Fatal("HAKUREI_APP_ID not set")
|
||||||
} else if aid, err := parseUint32Fast(as); err != nil || aid < 0 || aid > 9999 {
|
} else if aid, err := parseUint32Fast(as); err != nil || aid < 0 || aid > 9999 {
|
||||||
log.Fatal("invalid aid")
|
log.Fatal("invalid aid")
|
||||||
} else {
|
} else {
|
||||||
@ -82,12 +82,12 @@ func main() {
|
|||||||
// pass through setup fd to shim
|
// pass through setup fd to shim
|
||||||
var shimSetupFd string
|
var shimSetupFd string
|
||||||
if s, ok := os.LookupEnv(envShim); !ok {
|
if s, ok := os.LookupEnv(envShim); !ok {
|
||||||
// fortify requests target uid
|
// hakurei requests target uid
|
||||||
// print resolved uid and exit
|
// print resolved uid and exit
|
||||||
fmt.Print(uid)
|
fmt.Print(uid)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
|
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
|
||||||
log.Fatal("FORTIFY_SHIM holds an invalid value")
|
log.Fatal("HAKUREI_SHIM holds an invalid value")
|
||||||
} else {
|
} else {
|
||||||
shimSetupFd = s
|
shimSetupFd = s
|
||||||
}
|
}
|
||||||
@ -124,7 +124,7 @@ func main() {
|
|||||||
panic("uid out of bounds")
|
panic("uid out of bounds")
|
||||||
}
|
}
|
||||||
|
|
||||||
// careful! users in the allowlist is effectively allowed to drop groups via fsu
|
// careful! users in the allowlist is effectively allowed to drop groups via hsu
|
||||||
|
|
||||||
if err := syscall.Setresgid(uid, uid, uid); err != nil {
|
if err := syscall.Setresgid(uid, uid, uid); err != nil {
|
||||||
log.Fatalf("cannot set gid: %v", err)
|
log.Fatalf("cannot set gid: %v", err)
|
||||||
@ -138,7 +138,7 @@ func main() {
|
|||||||
if _, _, errno := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_NO_NEW_PRIVS, 1, 0); errno != 0 {
|
if _, _, errno := syscall.AllThreadsSyscall(syscall.SYS_PRCTL, PR_SET_NO_NEW_PRIVS, 1, 0); errno != 0 {
|
||||||
log.Fatalf("cannot set no_new_privs flag: %s", errno.Error())
|
log.Fatalf("cannot set no_new_privs flag: %s", errno.Error())
|
||||||
}
|
}
|
||||||
if err := syscall.Exec(toolPath, []string{"fortify", "shim"}, []string{envShim + "=" + shimSetupFd}); err != nil {
|
if err := syscall.Exec(toolPath, []string{"hakurei", "shim"}, []string{envShim + "=" + shimSetupFd}); err != nil {
|
||||||
log.Fatalf("cannot start shim: %v", err)
|
log.Fatalf("cannot start shim: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
lib,
|
lib,
|
||||||
buildGoModule,
|
buildGoModule,
|
||||||
fortify ? abort "fortify package required",
|
hakurei ? abort "hakurei package required",
|
||||||
}:
|
}:
|
||||||
|
|
||||||
buildGoModule {
|
buildGoModule {
|
||||||
pname = "${fortify.pname}-fsu";
|
pname = "${hakurei.pname}-hsu";
|
||||||
inherit (fortify) version;
|
inherit (hakurei) version;
|
||||||
|
|
||||||
src = ./.;
|
src = ./.;
|
||||||
inherit (fortify) vendorHash;
|
inherit (hakurei) vendorHash;
|
||||||
env.CGO_ENABLED = 0;
|
env.CGO_ENABLED = 0;
|
||||||
|
|
||||||
preBuild = ''
|
preBuild = ''
|
||||||
go mod init fsu >& /dev/null
|
go mod init hsu >& /dev/null
|
||||||
'';
|
'';
|
||||||
|
|
||||||
ldflags =
|
ldflags =
|
||||||
@ -24,7 +24,7 @@ buildGoModule {
|
|||||||
)
|
)
|
||||||
[ "-s -w" ]
|
[ "-s -w" ]
|
||||||
{
|
{
|
||||||
fmain = "${fortify}/libexec/fortify";
|
hmain = "${hakurei}/libexec/hakurei";
|
||||||
fpkg = "${fortify}/libexec/fpkg";
|
fpkg = "${hakurei}/libexec/fpkg";
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -50,7 +50,7 @@ func parseConfig(r io.Reader, puid int) (fid int, ok bool, err error) {
|
|||||||
if ok {
|
if ok {
|
||||||
// allowed fid range 0 to 99
|
// allowed fid range 0 to 99
|
||||||
if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 {
|
if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 {
|
||||||
return -1, false, fmt.Errorf("invalid fortify uid on line %d", line)
|
return -1, false, fmt.Errorf("invalid identity on line %d", line)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
@ -65,7 +65,7 @@ func Test_parseConfig(t *testing.T) {
|
|||||||
{"empty", 0, -1, "", ``},
|
{"empty", 0, -1, "", ``},
|
||||||
{"invalid field", 0, -1, "invalid entry on line 1", `9`},
|
{"invalid field", 0, -1, "invalid entry on line 1", `9`},
|
||||||
{"invalid puid", 0, -1, "invalid parent uid on line 1", `f 9`},
|
{"invalid puid", 0, -1, "invalid parent uid on line 1", `f 9`},
|
||||||
{"invalid fid", 1000, -1, "invalid fortify uid on line 1", `1000 f`},
|
{"invalid fid", 1000, -1, "invalid identity on line 1", `1000 f`},
|
||||||
{"match", 1000, 0, "", `1000 0`},
|
{"match", 1000, 0, "", `1000 0`},
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
|||||||
const compPoison = "INVALIDINVALIDINVALIDINVALIDINVALID"
|
const compPoison = "INVALIDINVALIDINVALIDINVALIDINVALID"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fmain = compPoison
|
hmain = compPoison
|
||||||
fpkg = compPoison
|
fpkg = compPoison
|
||||||
)
|
)
|
||||||
|
|
@ -3,7 +3,7 @@ package command_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/command"
|
"git.gensokyo.uk/security/hakurei/command"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBuild(t *testing.T) {
|
func TestBuild(t *testing.T) {
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/command"
|
"git.gensokyo.uk/security/hakurei/command"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig_Args(t *testing.T) {
|
func TestConfig_Args(t *testing.T) {
|
||||||
|
@ -13,11 +13,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFinalise(t *testing.T) {
|
func TestFinalise(t *testing.T) {
|
||||||
@ -208,6 +208,6 @@ func TestHelperInit(t *testing.T) {
|
|||||||
if len(os.Args) != 5 || os.Args[4] != "init" {
|
if len(os.Args) != 5 || os.Args[4] != "init" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sandbox.SetOutput(fmsg.Output{})
|
sandbox.SetOutput(hlog.Output{})
|
||||||
sandbox.Init(fmsg.Prepare, internal.InstallFmsg)
|
sandbox.Init(hlog.Prepare, internal.InstallFmsg)
|
||||||
}
|
}
|
||||||
|
10
dbus/proc.go
10
dbus/proc.go
@ -11,10 +11,10 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
"git.gensokyo.uk/security/fortify/ldd"
|
"git.gensokyo.uk/security/hakurei/ldd"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start starts and configures a D-Bus proxy process.
|
// Start starts and configures a D-Bus proxy process.
|
||||||
@ -67,7 +67,7 @@ func (p *Proxy) Start() error {
|
|||||||
p.final, true,
|
p.final, true,
|
||||||
argF, func(container *sandbox.Container) {
|
argF, func(container *sandbox.Container) {
|
||||||
container.Seccomp |= seccomp.FilterMultiarch
|
container.Seccomp |= seccomp.FilterMultiarch
|
||||||
container.Hostname = "fortify-dbus"
|
container.Hostname = "hakurei-dbus"
|
||||||
container.CommandContext = p.CommandContext
|
container.CommandContext = p.CommandContext
|
||||||
if p.output != nil {
|
if p.output != nil {
|
||||||
container.Stdout, container.Stderr = p.output, p.output
|
container.Stdout, container.Stderr = p.output, p.output
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProxyName is the file name or path to the proxy program.
|
// ProxyName is the file name or path to the proxy program.
|
||||||
|
@ -3,7 +3,7 @@ package dbus_test
|
|||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -3,7 +3,7 @@ package dbus_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }
|
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }
|
||||||
|
50
dist/comp/_fortify → dist/comp/_hakurei
vendored
50
dist/comp/_fortify → dist/comp/_hakurei
vendored
@ -1,11 +1,11 @@
|
|||||||
#compdef fortify
|
#compdef hakurei
|
||||||
|
|
||||||
_fortify_app() {
|
_hakurei_app() {
|
||||||
__fortify_files
|
__hakurei_files
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
_fortify_run() {
|
_hakurei_run() {
|
||||||
_arguments \
|
_arguments \
|
||||||
'--id[Reverse-DNS style Application identifier, leave empty to inherit instance identifier]:id' \
|
'--id[Reverse-DNS style Application identifier, leave empty to inherit instance identifier]:id' \
|
||||||
'-a[Application identity]: :_numbers' \
|
'-a[Application identity]: :_numbers' \
|
||||||
@ -22,26 +22,26 @@ _fortify_run() {
|
|||||||
'--dbus-log[Force buffered logging in the D-Bus proxy]'
|
'--dbus-log[Force buffered logging in the D-Bus proxy]'
|
||||||
}
|
}
|
||||||
|
|
||||||
_fortify_ps() {
|
_hakurei_ps() {
|
||||||
_arguments \
|
_arguments \
|
||||||
'--short[List instances only]'
|
'--short[List instances only]'
|
||||||
}
|
}
|
||||||
|
|
||||||
_fortify_show() {
|
_hakurei_show() {
|
||||||
_alternative \
|
_alternative \
|
||||||
'instances:domains:__fortify_instances' \
|
'instances:domains:__hakurei_instances' \
|
||||||
'files:files:__fortify_files'
|
'files:files:__hakurei_files'
|
||||||
}
|
}
|
||||||
|
|
||||||
__fortify_files() {
|
__hakurei_files() {
|
||||||
_files -g "*.(json|ftfy)"
|
_files -g "*.(json|hakurei)"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
__fortify_instances() {
|
__hakurei_instances() {
|
||||||
local -a out
|
local -a out
|
||||||
shift -p
|
shift -p
|
||||||
out=( ${(f)"$(_call_program commands fortify ps --short 2>&1)"} )
|
out=( ${(f)"$(_call_program commands hakurei ps --short 2>&1)"} )
|
||||||
if (( $#out == 0 )); then
|
if (( $#out == 0 )); then
|
||||||
_message "No active instances"
|
_message "No active instances"
|
||||||
else
|
else
|
||||||
@ -50,26 +50,26 @@ __fortify_instances() {
|
|||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
(( $+functions[_fortify_commands] )) || _fortify_commands()
|
(( $+functions[_hakurei_commands] )) || _hakurei_commands()
|
||||||
{
|
{
|
||||||
local -a _fortify_cmds
|
local -a _hakurei_cmds
|
||||||
_fortify_cmds=(
|
_hakurei_cmds=(
|
||||||
"app:Launch app defined by the specified config file"
|
"app:Load app from configuration file"
|
||||||
"run:Configure and start a permissive default sandbox"
|
"run:Configure and start a permissive default sandbox"
|
||||||
"show:Show the contents of an app configuration"
|
"show:Show live or local app configuration"
|
||||||
"ps:List active apps and their state"
|
"ps:List active instances"
|
||||||
"version:Show fortify version"
|
"version:Display version information"
|
||||||
"license:Show full license text"
|
"license:Show full license text"
|
||||||
"template:Produce a config template"
|
"template:Produce a config template"
|
||||||
"help:Show help message"
|
"help:Show help message"
|
||||||
)
|
)
|
||||||
if (( CURRENT == 1 )); then
|
if (( CURRENT == 1 )); then
|
||||||
_describe -t commands 'action' _fortify_cmds || compadd "$@"
|
_describe -t commands 'action' _hakurei_cmds || compadd "$@"
|
||||||
else
|
else
|
||||||
local curcontext="$curcontext"
|
local curcontext="$curcontext"
|
||||||
cmd="${${_fortify_cmds[(r)$words[1]:*]%%:*}}"
|
cmd="${${_hakurei_cmds[(r)$words[1]:*]%%:*}}"
|
||||||
if (( $+functions[_fortify_$cmd] )); then
|
if (( $+functions[_hakurei_$cmd] )); then
|
||||||
_fortify_$cmd
|
_hakurei_$cmd
|
||||||
else
|
else
|
||||||
_message "no more options"
|
_message "no more options"
|
||||||
fi
|
fi
|
||||||
@ -77,6 +77,6 @@ __fortify_instances() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_arguments -C \
|
_arguments -C \
|
||||||
'-v[Verbose output]' \
|
'-v[Increase log verbosity]' \
|
||||||
'--json[Serialise output in JSON when applicable]' \
|
'--json[Serialise output in JSON when applicable]' \
|
||||||
'*::fortify command:_fortify_commands'
|
'*::hakurei command:_hakurei_commands'
|
0
dist/fsurc.default → dist/hsurc.default
vendored
0
dist/fsurc.default → dist/hsurc.default
vendored
12
dist/install.sh
vendored
12
dist/install.sh
vendored
@ -1,12 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
cd "$(dirname -- "$0")" || exit 1
|
cd "$(dirname -- "$0")" || exit 1
|
||||||
|
|
||||||
install -vDm0755 "bin/fortify" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fortify"
|
install -vDm0755 "bin/hakurei" "${HAKUREI_INSTALL_PREFIX}/usr/bin/hakurei"
|
||||||
install -vDm0755 "bin/fpkg" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fpkg"
|
install -vDm0755 "bin/fpkg" "${HAKUREI_INSTALL_PREFIX}/usr/bin/fpkg"
|
||||||
|
|
||||||
install -vDm6511 "bin/fsu" "${FORTIFY_INSTALL_PREFIX}/usr/bin/fsu"
|
install -vDm6511 "bin/hsu" "${HAKUREI_INSTALL_PREFIX}/usr/bin/hsu"
|
||||||
if [ ! -f "${FORTIFY_INSTALL_PREFIX}/etc/fsurc" ]; then
|
if [ ! -f "${HAKUREI_INSTALL_PREFIX}/etc/hsurc" ]; then
|
||||||
install -vDm0400 "fsurc.default" "${FORTIFY_INSTALL_PREFIX}/etc/fsurc"
|
install -vDm0400 "hsurc.default" "${HAKUREI_INSTALL_PREFIX}/etc/hsurc"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
install -vDm0644 "comp/_fortify" "${FORTIFY_INSTALL_PREFIX}/usr/share/zsh/site-functions/_fortify"
|
install -vDm0644 "comp/_hakurei" "${HAKUREI_INSTALL_PREFIX}/usr/share/zsh/site-functions/_hakurei"
|
12
dist/release.sh
vendored
12
dist/release.sh
vendored
@ -1,18 +1,18 @@
|
|||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
cd "$(dirname -- "$0")/.."
|
cd "$(dirname -- "$0")/.."
|
||||||
VERSION="${FORTIFY_VERSION:-untagged}"
|
VERSION="${HAKUREI_VERSION:-untagged}"
|
||||||
pname="fortify-${VERSION}"
|
pname="hakurei-${VERSION}"
|
||||||
out="dist/${pname}"
|
out="dist/${pname}"
|
||||||
|
|
||||||
mkdir -p "${out}"
|
mkdir -p "${out}"
|
||||||
cp -v "README.md" "dist/fsurc.default" "dist/install.sh" "${out}"
|
cp -v "README.md" "dist/hsurc.default" "dist/install.sh" "${out}"
|
||||||
cp -rv "dist/comp" "${out}"
|
cp -rv "dist/comp" "${out}"
|
||||||
|
|
||||||
go generate ./...
|
go generate ./...
|
||||||
go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w -buildid= -extldflags '-static'
|
go build -trimpath -v -o "${out}/bin/" -ldflags "-s -w -buildid= -extldflags '-static'
|
||||||
-X git.gensokyo.uk/security/fortify/internal.version=${VERSION}
|
-X git.gensokyo.uk/security/hakurei/internal.version=${VERSION}
|
||||||
-X git.gensokyo.uk/security/fortify/internal.fsu=/usr/bin/fsu
|
-X git.gensokyo.uk/security/hakurei/internal.hsu=/usr/bin/hsu
|
||||||
-X main.fmain=/usr/bin/fortify
|
-X main.hmain=/usr/bin/hakurei
|
||||||
-X main.fpkg=/usr/bin/fpkg" ./...
|
-X main.fpkg=/usr/bin/fpkg" ./...
|
||||||
|
|
||||||
rm -f "./${out}.tar.gz" && tar -C dist -czf "${out}.tar.gz" "${pname}"
|
rm -f "./${out}.tar.gz" && tar -C dist -czf "${out}.tar.gz" "${pname}"
|
||||||
|
32
flake.nix
32
flake.nix
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
description = "fortify sandbox tool and nixos module";
|
description = "hakurei container tool and nixos module";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
|
||||||
@ -27,7 +27,7 @@
|
|||||||
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
|
nixpkgsFor = forAllSystems (system: import nixpkgs { inherit system; });
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
nixosModules.fortify = import ./nixos.nix self.packages;
|
nixosModules.hakurei = import ./nixos.nix self.packages;
|
||||||
|
|
||||||
buildPackage = forAllSystems (
|
buildPackage = forAllSystems (
|
||||||
system:
|
system:
|
||||||
@ -57,7 +57,7 @@
|
|||||||
;
|
;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
fortify = callPackage ./test { inherit system self; };
|
hakurei = callPackage ./test { inherit system self; };
|
||||||
race = callPackage ./test {
|
race = callPackage ./test {
|
||||||
inherit system self;
|
inherit system self;
|
||||||
withRace = true;
|
withRace = true;
|
||||||
@ -105,12 +105,12 @@
|
|||||||
packages = forAllSystems (
|
packages = forAllSystems (
|
||||||
system:
|
system:
|
||||||
let
|
let
|
||||||
inherit (self.packages.${system}) fortify fsu;
|
inherit (self.packages.${system}) hakurei hsu;
|
||||||
pkgs = nixpkgsFor.${system};
|
pkgs = nixpkgsFor.${system};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
default = fortify;
|
default = hakurei;
|
||||||
fortify = pkgs.pkgsStatic.callPackage ./package.nix {
|
hakurei = pkgs.pkgsStatic.callPackage ./package.nix {
|
||||||
inherit (pkgs)
|
inherit (pkgs)
|
||||||
# passthru.buildInputs
|
# passthru.buildInputs
|
||||||
go
|
go
|
||||||
@ -131,20 +131,20 @@
|
|||||||
coreutils
|
coreutils
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
fsu = pkgs.callPackage ./cmd/fsu/package.nix { inherit (self.packages.${system}) fortify; };
|
hsu = pkgs.callPackage ./cmd/hsu/package.nix { inherit (self.packages.${system}) hakurei; };
|
||||||
|
|
||||||
dist = pkgs.runCommand "${fortify.name}-dist" { buildInputs = fortify.targetPkgs ++ [ pkgs.pkgsStatic.musl ]; } ''
|
dist = pkgs.runCommand "${hakurei.name}-dist" { buildInputs = hakurei.targetPkgs ++ [ pkgs.pkgsStatic.musl ]; } ''
|
||||||
# go requires XDG_CACHE_HOME for the build cache
|
# go requires XDG_CACHE_HOME for the build cache
|
||||||
export XDG_CACHE_HOME="$(mktemp -d)"
|
export XDG_CACHE_HOME="$(mktemp -d)"
|
||||||
|
|
||||||
# get a different workdir as go does not like /build
|
# get a different workdir as go does not like /build
|
||||||
cd $(mktemp -d) \
|
cd $(mktemp -d) \
|
||||||
&& cp -r ${fortify.src}/. . \
|
&& cp -r ${hakurei.src}/. . \
|
||||||
&& chmod +w cmd && cp -r ${fsu.src}/. cmd/fsu/ \
|
&& chmod +w cmd && cp -r ${hsu.src}/. cmd/hsu/ \
|
||||||
&& chmod -R +w .
|
&& chmod -R +w .
|
||||||
|
|
||||||
export FORTIFY_VERSION="v${fortify.version}"
|
export HAKUREI_VERSION="v${hakurei.version}"
|
||||||
./dist/release.sh && mkdir $out && cp -v "dist/fortify-$FORTIFY_VERSION.tar.gz"* $out
|
./dist/release.sh && mkdir $out && cp -v "dist/hakurei-$HAKUREI_VERSION.tar.gz"* $out
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -152,12 +152,12 @@
|
|||||||
devShells = forAllSystems (
|
devShells = forAllSystems (
|
||||||
system:
|
system:
|
||||||
let
|
let
|
||||||
inherit (self.packages.${system}) fortify;
|
inherit (self.packages.${system}) hakurei;
|
||||||
pkgs = nixpkgsFor.${system};
|
pkgs = nixpkgsFor.${system};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
default = pkgs.mkShell { buildInputs = fortify.targetPkgs; };
|
default = pkgs.mkShell { buildInputs = hakurei.targetPkgs; };
|
||||||
withPackage = pkgs.mkShell { buildInputs = [ fortify ] ++ fortify.targetPkgs; };
|
withPackage = pkgs.mkShell { buildInputs = [ hakurei ] ++ hakurei.targetPkgs; };
|
||||||
|
|
||||||
generateDoc =
|
generateDoc =
|
||||||
let
|
let
|
||||||
@ -174,7 +174,7 @@
|
|||||||
cleanEval = lib.filterAttrsRecursive (n: _: n != "_module") eval;
|
cleanEval = lib.filterAttrsRecursive (n: _: n != "_module") eval;
|
||||||
in
|
in
|
||||||
pkgs.nixosOptionsDoc { inherit (cleanEval) options; };
|
pkgs.nixosOptionsDoc { inherit (cleanEval) options; };
|
||||||
docText = pkgs.runCommand "fortify-module-docs.md" { } ''
|
docText = pkgs.runCommand "hakurei-module-docs.md" { } ''
|
||||||
cat ${doc.optionsCommonMark} > $out
|
cat ${doc.optionsCommonMark} > $out
|
||||||
sed -i '/*Declared by:*/,+1 d' $out
|
sed -i '/*Declared by:*/,+1 d' $out
|
||||||
'';
|
'';
|
||||||
|
4
go.mod
4
go.mod
@ -1,3 +1,3 @@
|
|||||||
module git.gensokyo.uk/security/fortify
|
module git.gensokyo.uk/security/hakurei
|
||||||
|
|
||||||
go 1.23
|
go 1.24
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestArgsString(t *testing.T) {
|
func TestArgsString(t *testing.T) {
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper/proc"
|
"git.gensokyo.uk/security/hakurei/helper/proc"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDirect initialises a new direct Helper instance with wt as the null-terminated argument writer.
|
// NewDirect initialises a new direct Helper instance with wt as the null-terminated argument writer.
|
||||||
@ -67,17 +67,17 @@ func (h *helperCmd) Start() error {
|
|||||||
|
|
||||||
h.Env = slices.Grow(h.Env, 2)
|
h.Env = slices.Grow(h.Env, 2)
|
||||||
if h.useArgsFd {
|
if h.useArgsFd {
|
||||||
h.Env = append(h.Env, FortifyHelper+"=1")
|
h.Env = append(h.Env, HakureiHelper+"=1")
|
||||||
} else {
|
} else {
|
||||||
h.Env = append(h.Env, FortifyHelper+"=0")
|
h.Env = append(h.Env, HakureiHelper+"=0")
|
||||||
}
|
}
|
||||||
if h.useStatFd {
|
if h.useStatFd {
|
||||||
h.Env = append(h.Env, FortifyStatus+"=1")
|
h.Env = append(h.Env, HakureiStatus+"=1")
|
||||||
|
|
||||||
// stat is populated on fulfill
|
// stat is populated on fulfill
|
||||||
h.Cancel = func() error { return h.stat.Close() }
|
h.Cancel = func() error { return h.stat.Close() }
|
||||||
} else {
|
} else {
|
||||||
h.Env = append(h.Env, FortifyStatus+"=0")
|
h.Env = append(h.Env, HakureiStatus+"=0")
|
||||||
}
|
}
|
||||||
|
|
||||||
return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, h.Cmd.Start, h.files, h.extraFiles)
|
return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, h.Cmd.Start, h.files, h.extraFiles)
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCmd(t *testing.T) {
|
func TestCmd(t *testing.T) {
|
||||||
@ -22,9 +22,9 @@ func TestCmd(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("valid new helper nil check", func(t *testing.T) {
|
t.Run("valid new helper nil check", func(t *testing.T) {
|
||||||
if got := helper.NewDirect(t.Context(), "fortify", argsWt, false, argF, nil, nil); got == nil {
|
if got := helper.NewDirect(t.Context(), "hakurei", argsWt, false, argF, nil, nil); got == nil {
|
||||||
t.Errorf("NewDirect(%q, %q) got nil",
|
t.Errorf("NewDirect(%q, %q) got nil",
|
||||||
argsWt, "fortify")
|
argsWt, "hakurei")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -9,8 +9,8 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper/proc"
|
"git.gensokyo.uk/security/hakurei/helper/proc"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// New initialises a Helper instance with wt as the null-terminated argument writer.
|
// New initialises a Helper instance with wt as the null-terminated argument writer.
|
||||||
@ -54,17 +54,17 @@ func (h *helperContainer) Start() error {
|
|||||||
|
|
||||||
h.Env = slices.Grow(h.Env, 2)
|
h.Env = slices.Grow(h.Env, 2)
|
||||||
if h.useArgsFd {
|
if h.useArgsFd {
|
||||||
h.Env = append(h.Env, FortifyHelper+"=1")
|
h.Env = append(h.Env, HakureiHelper+"=1")
|
||||||
} else {
|
} else {
|
||||||
h.Env = append(h.Env, FortifyHelper+"=0")
|
h.Env = append(h.Env, HakureiHelper+"=0")
|
||||||
}
|
}
|
||||||
if h.useStatFd {
|
if h.useStatFd {
|
||||||
h.Env = append(h.Env, FortifyStatus+"=1")
|
h.Env = append(h.Env, HakureiStatus+"=1")
|
||||||
|
|
||||||
// stat is populated on fulfill
|
// stat is populated on fulfill
|
||||||
h.Cancel = func(*exec.Cmd) error { return h.stat.Close() }
|
h.Cancel = func(*exec.Cmd) error { return h.stat.Close() }
|
||||||
} else {
|
} else {
|
||||||
h.Env = append(h.Env, FortifyStatus+"=0")
|
h.Env = append(h.Env, HakureiStatus+"=0")
|
||||||
}
|
}
|
||||||
|
|
||||||
return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, func() error {
|
return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, func() error {
|
||||||
|
@ -7,10 +7,10 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestContainer(t *testing.T) {
|
func TestContainer(t *testing.T) {
|
||||||
@ -25,9 +25,9 @@ func TestContainer(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("valid new helper nil check", func(t *testing.T) {
|
t.Run("valid new helper nil check", func(t *testing.T) {
|
||||||
if got := helper.New(t.Context(), "fortify", argsWt, false, argF, nil, nil); got == nil {
|
if got := helper.New(t.Context(), "hakurei", argsWt, false, argF, nil, nil); got == nil {
|
||||||
t.Errorf("New(%q, %q) got nil",
|
t.Errorf("New(%q, %q) got nil",
|
||||||
argsWt, "fortify")
|
argsWt, "hakurei")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -52,6 +52,6 @@ func TestHelperInit(t *testing.T) {
|
|||||||
if len(os.Args) != 5 || os.Args[4] != "init" {
|
if len(os.Args) != 5 || os.Args[4] != "init" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sandbox.SetOutput(fmsg.Output{})
|
sandbox.SetOutput(hlog.Output{})
|
||||||
sandbox.Init(fmsg.Prepare, func(bool) { internal.InstallFmsg(false) })
|
sandbox.Init(hlog.Prepare, func(bool) { internal.InstallFmsg(false) })
|
||||||
}
|
}
|
||||||
|
@ -8,16 +8,16 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper/proc"
|
"git.gensokyo.uk/security/hakurei/helper/proc"
|
||||||
)
|
)
|
||||||
|
|
||||||
var WaitDelay = 2 * time.Second
|
var WaitDelay = 2 * time.Second
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// FortifyHelper is set to 1 when args fd is enabled and 0 otherwise.
|
// HakureiHelper is set to 1 when args fd is enabled and 0 otherwise.
|
||||||
FortifyHelper = "FORTIFY_HELPER"
|
HakureiHelper = "HAKUREI_HELPER"
|
||||||
// FortifyStatus is set to 1 when stat fd is enabled and 0 otherwise.
|
// HakureiStatus is set to 1 when stat fd is enabled and 0 otherwise.
|
||||||
FortifyStatus = "FORTIFY_STATUS"
|
HakureiStatus = "HAKUREI_STATUS"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Helper interface {
|
type Helper interface {
|
||||||
|
@ -11,13 +11,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
wantArgs = []string{
|
wantArgs = []string{
|
||||||
"unix:path=/run/dbus/system_bus_socket",
|
"unix:path=/run/dbus/system_bus_socket",
|
||||||
"/tmp/fortify.1971/12622d846cc3fe7b4c10359d01f0eb47/system_bus_socket",
|
"/tmp/hakurei.1971/12622d846cc3fe7b4c10359d01f0eb47/system_bus_socket",
|
||||||
"--filter",
|
"--filter",
|
||||||
"--talk=org.bluez",
|
"--talk=org.bluez",
|
||||||
"--talk=org.freedesktop.Avahi",
|
"--talk=org.freedesktop.Avahi",
|
||||||
|
@ -14,13 +14,13 @@ import (
|
|||||||
func InternalHelperStub() {
|
func InternalHelperStub() {
|
||||||
// this test mocks the helper process
|
// this test mocks the helper process
|
||||||
var ap, sp string
|
var ap, sp string
|
||||||
if v, ok := os.LookupEnv(FortifyHelper); !ok {
|
if v, ok := os.LookupEnv(HakureiHelper); !ok {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
ap = v
|
ap = v
|
||||||
}
|
}
|
||||||
if v, ok := os.LookupEnv(FortifyStatus); !ok {
|
if v, ok := os.LookupEnv(HakureiStatus); !ok {
|
||||||
panic(FortifyStatus)
|
panic(HakureiStatus)
|
||||||
} else {
|
} else {
|
||||||
sp = v
|
sp = v
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package helper_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/hakurei/helper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }
|
func TestHelperStub(t *testing.T) { helper.InternalHelperStub() }
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
// Package fst exports shared fortify types.
|
// Package hst exports shared types for invoking hakurei.
|
||||||
package fst
|
package hst
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Tmp = "/.fortify"
|
const Tmp = "/.hakurei"
|
||||||
|
|
||||||
// Config is used to seal an app implementation.
|
// Config is used to seal an app implementation.
|
||||||
type Config struct {
|
type Config struct {
|
@ -1,7 +1,7 @@
|
|||||||
package fst
|
package hst
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
@ -1,4 +1,4 @@
|
|||||||
package fst
|
package hst
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
User int `json:"user"`
|
User int `json:"user"`
|
@ -1,9 +1,9 @@
|
|||||||
package fst
|
package hst
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Template returns a fully populated instance of Config.
|
// Template returns a fully populated instance of Config.
|
||||||
@ -46,11 +46,11 @@ func Template() *Config {
|
|||||||
|
|
||||||
Username: "chronos",
|
Username: "chronos",
|
||||||
Shell: "/run/current-system/sw/bin/zsh",
|
Shell: "/run/current-system/sw/bin/zsh",
|
||||||
Data: "/var/lib/fortify/u0/org.chromium.Chromium",
|
Data: "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
Dir: "/data/data/org.chromium.Chromium",
|
Dir: "/data/data/org.chromium.Chromium",
|
||||||
ExtraPerms: []*ExtraPermConfig{
|
ExtraPerms: []*ExtraPermConfig{
|
||||||
{Path: "/var/lib/fortify/u0", Ensure: true, Execute: true},
|
{Path: "/var/lib/hakurei/u0", Ensure: true, Execute: true},
|
||||||
{Path: "/var/lib/fortify/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
|
{Path: "/var/lib/hakurei/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
|
||||||
},
|
},
|
||||||
|
|
||||||
Identity: 9,
|
Identity: 9,
|
||||||
@ -78,7 +78,7 @@ func Template() *Config {
|
|||||||
{Src: "/run/current-system"},
|
{Src: "/run/current-system"},
|
||||||
{Src: "/run/opengl-driver"},
|
{Src: "/run/opengl-driver"},
|
||||||
{Src: "/var/db/nix-channels"},
|
{Src: "/var/db/nix-channels"},
|
||||||
{Src: "/var/lib/fortify/u0/org.chromium.Chromium",
|
{Src: "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
Dst: "/data/data/org.chromium.Chromium", Write: true, Must: true},
|
Dst: "/data/data/org.chromium.Chromium", Write: true, Must: true},
|
||||||
{Src: "/dev/dri", Device: true},
|
{Src: "/dev/dri", Device: true},
|
||||||
},
|
},
|
@ -1,10 +1,10 @@
|
|||||||
package fst_test
|
package hst_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTemplate(t *testing.T) {
|
func TestTemplate(t *testing.T) {
|
||||||
@ -57,16 +57,16 @@ func TestTemplate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"username": "chronos",
|
"username": "chronos",
|
||||||
"shell": "/run/current-system/sw/bin/zsh",
|
"shell": "/run/current-system/sw/bin/zsh",
|
||||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"data": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"dir": "/data/data/org.chromium.Chromium",
|
"dir": "/data/data/org.chromium.Chromium",
|
||||||
"extra_perms": [
|
"extra_perms": [
|
||||||
{
|
{
|
||||||
"ensure": true,
|
"ensure": true,
|
||||||
"path": "/var/lib/fortify/u0",
|
"path": "/var/lib/hakurei/u0",
|
||||||
"x": true
|
"x": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"r": true,
|
"r": true,
|
||||||
"w": true,
|
"w": true,
|
||||||
"x": true
|
"x": true
|
||||||
@ -108,7 +108,7 @@ func TestTemplate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"dst": "/data/data/org.chromium.Chromium",
|
"dst": "/data/data/org.chromium.Chromium",
|
||||||
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"write": true,
|
"write": true,
|
||||||
"require": true
|
"require": true
|
||||||
},
|
},
|
||||||
@ -131,7 +131,7 @@ func TestTemplate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
if p, err := json.MarshalIndent(fst.Template(), "", "\t"); err != nil {
|
if p, err := json.MarshalIndent(hst.Template(), "", "\t"); err != nil {
|
||||||
t.Fatalf("cannot marshal: %v", err)
|
t.Fatalf("cannot marshal: %v", err)
|
||||||
} else if s := string(p); s != want {
|
} else if s := string(p); s != want {
|
||||||
t.Fatalf("Template:\n%s\nwant:\n%s",
|
t.Fatalf("Template:\n%s\nwant:\n%s",
|
@ -5,7 +5,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
type App interface {
|
type App interface {
|
||||||
@ -14,7 +14,7 @@ type App interface {
|
|||||||
|
|
||||||
// Seal determines the outcome of config as a [SealedApp].
|
// Seal determines the outcome of config as a [SealedApp].
|
||||||
// The value of config might be overwritten and must not be used again.
|
// The value of config might be overwritten and must not be used again.
|
||||||
Seal(config *fst.Config) (SealedApp, error)
|
Seal(config *hst.Config) (SealedApp, error)
|
||||||
|
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
@ -48,12 +48,12 @@ func (rs *RunState) SetStart() {
|
|||||||
rs.Time = &now
|
rs.Time = &now
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paths contains environment-dependent paths used by fortify.
|
// Paths contains environment-dependent paths used by hakurei.
|
||||||
type Paths struct {
|
type Paths struct {
|
||||||
// path to shared directory (usually `/tmp/fortify.%d`)
|
// path to shared directory (usually `/tmp/hakurei.%d`)
|
||||||
SharePath string `json:"share_path"`
|
SharePath string `json:"share_path"`
|
||||||
// XDG_RUNTIME_DIR value (usually `/run/user/%d`)
|
// XDG_RUNTIME_DIR value (usually `/run/user/%d`)
|
||||||
RuntimePath string `json:"runtime_path"`
|
RuntimePath string `json:"runtime_path"`
|
||||||
// application runtime directory (usually `/run/user/%d/fortify`)
|
// application runtime directory (usually `/run/user/%d/hakurei`)
|
||||||
RunDirPath string `json:"run_dir_path"`
|
RunDirPath string `json:"run_dir_path"`
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "git.gensokyo.uk/security/fortify/internal/app"
|
. "git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseAppID(t *testing.T) {
|
func TestParseAppID(t *testing.T) {
|
||||||
|
@ -8,20 +8,20 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// in practice there should be less than 30 entries added by the runtime;
|
// in practice there should be less than 30 entries added by the runtime;
|
||||||
// allocating slightly more as a margin for future expansion
|
// allocating slightly more as a margin for future expansion
|
||||||
const preallocateOpsCount = 1 << 5
|
const preallocateOpsCount = 1 << 5
|
||||||
|
|
||||||
// NewContainer initialises [sandbox.Params] via [fst.ContainerConfig].
|
// NewContainer initialises [sandbox.Params] via [hst.ContainerConfig].
|
||||||
// Note that remaining container setup must be queued by the caller.
|
// Note that remaining container setup must be queued by the caller.
|
||||||
func NewContainer(s *fst.ContainerConfig, os sys.State, uid, gid *int) (*sandbox.Params, map[string]string, error) {
|
func NewContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*sandbox.Params, map[string]string, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil, nil, syscall.EBADE
|
return nil, nil, syscall.EBADE
|
||||||
}
|
}
|
||||||
@ -67,7 +67,7 @@ func NewContainer(s *fst.ContainerConfig, os sys.State, uid, gid *int) (*sandbox
|
|||||||
|
|
||||||
container.
|
container.
|
||||||
Proc("/proc").
|
Proc("/proc").
|
||||||
Tmpfs(fst.Tmp, 1<<12, 0755)
|
Tmpfs(hst.Tmp, 1<<12, 0755)
|
||||||
|
|
||||||
if !s.Device {
|
if !s.Device {
|
||||||
container.Dev("/dev").Mqueue("/dev/mqueue")
|
container.Dev("/dev").Mqueue("/dev/mqueue")
|
||||||
|
@ -3,8 +3,8 @@ package instance
|
|||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
|
"git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PrintRunStateErr(whence int, rs *app.RunState, runErr error) (code int) {
|
func PrintRunStateErr(whence int, rs *app.RunState, runErr error) (code int) {
|
||||||
|
@ -6,9 +6,9 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
|
"git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package instance
|
package instance
|
||||||
|
|
||||||
import "git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
|
import "git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
|
||||||
|
|
||||||
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
|
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
|
||||||
func ShimMain() { setuid.ShimMain() }
|
func ShimMain() { setuid.ShimMain() }
|
||||||
|
@ -5,10 +5,10 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
. "git.gensokyo.uk/security/fortify/internal/app"
|
. "git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(ctx context.Context, os sys.State) (App, error) {
|
func New(ctx context.Context, os sys.State) (App, error) {
|
||||||
@ -52,7 +52,7 @@ func (a *app) String() string {
|
|||||||
return fmt.Sprintf("(unsealed app %s)", a.id)
|
return fmt.Sprintf("(unsealed app %s)", a.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) Seal(config *fst.Config) (SealedApp, error) {
|
func (a *app) Seal(config *hst.Config) (SealedApp, error) {
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
defer a.mu.Unlock()
|
defer a.mu.Unlock()
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ func (a *app) Seal(config *fst.Config) (SealedApp, error) {
|
|||||||
panic("app sealed twice")
|
panic("app sealed twice")
|
||||||
}
|
}
|
||||||
if config == nil {
|
if config == nil {
|
||||||
return nil, fmsg.WrapError(ErrConfig,
|
return nil, hlog.WrapErr(ErrConfig,
|
||||||
"attempted to seal app with nil config")
|
"attempted to seal app with nil config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,25 +1,25 @@
|
|||||||
package setuid_test
|
package setuid_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.gensokyo.uk/security/fortify/acl"
|
"git.gensokyo.uk/security/hakurei/acl"
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testCasesNixos = []sealTestCase{
|
var testCasesNixos = []sealTestCase{
|
||||||
{
|
{
|
||||||
"nixos chromium direct wayland", new(stubNixOS),
|
"nixos chromium direct wayland", new(stubNixOS),
|
||||||
&fst.Config{
|
&hst.Config{
|
||||||
ID: "org.chromium.Chromium",
|
ID: "org.chromium.Chromium",
|
||||||
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
|
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
|
||||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||||
|
|
||||||
Container: &fst.ContainerConfig{
|
Container: &hst.ContainerConfig{
|
||||||
Userns: true, Net: true, MapRealUID: true, Env: nil, AutoEtc: true,
|
Userns: true, Net: true, MapRealUID: true, Env: nil, AutoEtc: true,
|
||||||
Filesystem: []*fst.FilesystemConfig{
|
Filesystem: []*hst.FilesystemConfig{
|
||||||
{Src: "/bin", Must: true}, {Src: "/usr/bin", Must: true},
|
{Src: "/bin", Must: true}, {Src: "/usr/bin", Must: true},
|
||||||
{Src: "/nix/store", Must: true}, {Src: "/run/current-system", Must: true},
|
{Src: "/nix/store", Must: true}, {Src: "/run/current-system", Must: true},
|
||||||
{Src: "/sys/block"}, {Src: "/sys/bus"}, {Src: "/sys/class"}, {Src: "/sys/dev"}, {Src: "/sys/devices"},
|
{Src: "/sys/block"}, {Src: "/sys/bus"}, {Src: "/sys/class"}, {Src: "/sys/dev"}, {Src: "/sys/devices"},
|
||||||
@ -48,7 +48,7 @@ var testCasesNixos = []sealTestCase{
|
|||||||
DirectWayland: true,
|
DirectWayland: true,
|
||||||
|
|
||||||
Username: "u0_a1",
|
Username: "u0_a1",
|
||||||
Data: "/var/lib/persist/module/fortify/0/1",
|
Data: "/var/lib/persist/module/hakurei/0/1",
|
||||||
Identity: 1, Groups: []string{},
|
Identity: 1, Groups: []string{},
|
||||||
},
|
},
|
||||||
app.ID{
|
app.ID{
|
||||||
@ -58,19 +58,19 @@ var testCasesNixos = []sealTestCase{
|
|||||||
0xb4, 0x6e, 0xb5, 0xc1,
|
0xb4, 0x6e, 0xb5, 0xc1,
|
||||||
},
|
},
|
||||||
system.New(1000001).
|
system.New(1000001).
|
||||||
Ensure("/tmp/fortify.1971", 0711).
|
Ensure("/tmp/hakurei.1971", 0711).
|
||||||
Ensure("/tmp/fortify.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime", acl.Execute).
|
Ensure("/tmp/hakurei.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime", acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/runtime/1", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime/1", acl.Read, acl.Write, acl.Execute).
|
Ensure("/tmp/hakurei.1971/runtime/1", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime/1", acl.Read, acl.Write, acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir", acl.Execute).
|
Ensure("/tmp/hakurei.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir", acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/tmpdir/1", 01700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir/1", acl.Read, acl.Write, acl.Execute).
|
Ensure("/tmp/hakurei.1971/tmpdir/1", 01700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir/1", acl.Read, acl.Write, acl.Execute).
|
||||||
Ensure("/run/user/1971/fortify", 0700).UpdatePermType(system.User, "/run/user/1971/fortify", acl.Execute).
|
Ensure("/run/user/1971/hakurei", 0700).UpdatePermType(system.User, "/run/user/1971/hakurei", acl.Execute).
|
||||||
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
|
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
|
||||||
UpdatePermType(system.EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute).
|
UpdatePermType(system.EWayland, "/run/user/1971/wayland-0", acl.Read, acl.Write, acl.Execute).
|
||||||
Ephemeral(system.Process, "/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1", 0700).UpdatePermType(system.Process, "/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1", acl.Execute).
|
Ephemeral(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", 0700).UpdatePermType(system.Process, "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1", acl.Execute).
|
||||||
Link("/run/user/1971/pulse/native", "/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1/pulse").
|
Link("/run/user/1971/pulse/native", "/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse").
|
||||||
CopyFile(nil, "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
|
CopyFile(nil, "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
|
||||||
Ephemeral(system.Process, "/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1", 0711).
|
Ephemeral(system.Process, "/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1", 0711).
|
||||||
MustProxyDBus("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", &dbus.Config{
|
MustProxyDBus("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", &dbus.Config{
|
||||||
Talk: []string{
|
Talk: []string{
|
||||||
"org.freedesktop.FileManager1", "org.freedesktop.Notifications",
|
"org.freedesktop.FileManager1", "org.freedesktop.Notifications",
|
||||||
"org.freedesktop.ScreenSaver", "org.freedesktop.secrets",
|
"org.freedesktop.ScreenSaver", "org.freedesktop.secrets",
|
||||||
@ -83,7 +83,7 @@ var testCasesNixos = []sealTestCase{
|
|||||||
},
|
},
|
||||||
Call: map[string]string{}, Broadcast: map[string]string{},
|
Call: map[string]string{}, Broadcast: map[string]string{},
|
||||||
Filter: true,
|
Filter: true,
|
||||||
}, "/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", &dbus.Config{
|
}, "/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", &dbus.Config{
|
||||||
Talk: []string{
|
Talk: []string{
|
||||||
"org.bluez",
|
"org.bluez",
|
||||||
"org.freedesktop.Avahi",
|
"org.freedesktop.Avahi",
|
||||||
@ -91,20 +91,20 @@ var testCasesNixos = []sealTestCase{
|
|||||||
},
|
},
|
||||||
Filter: true,
|
Filter: true,
|
||||||
}).
|
}).
|
||||||
UpdatePerm("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", acl.Read, acl.Write).
|
UpdatePerm("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", acl.Read, acl.Write).
|
||||||
UpdatePerm("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", acl.Read, acl.Write),
|
UpdatePerm("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", acl.Read, acl.Write),
|
||||||
&sandbox.Params{
|
&sandbox.Params{
|
||||||
Uid: 1971,
|
Uid: 1971,
|
||||||
Gid: 100,
|
Gid: 100,
|
||||||
Flags: sandbox.FAllowNet | sandbox.FAllowUserns,
|
Flags: sandbox.FAllowNet | sandbox.FAllowUserns,
|
||||||
Dir: "/var/lib/persist/module/fortify/0/1",
|
Dir: "/var/lib/persist/module/hakurei/0/1",
|
||||||
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
|
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
|
||||||
Args: []string{"/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"},
|
Args: []string{"/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start"},
|
||||||
Env: []string{
|
Env: []string{
|
||||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1971/bus",
|
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1971/bus",
|
||||||
"DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
|
"DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
|
||||||
"HOME=/var/lib/persist/module/fortify/0/1",
|
"HOME=/var/lib/persist/module/hakurei/0/1",
|
||||||
"PULSE_COOKIE=" + fst.Tmp + "/pulse-cookie",
|
"PULSE_COOKIE=" + hst.Tmp + "/pulse-cookie",
|
||||||
"PULSE_SERVER=unix:/run/user/1971/pulse/native",
|
"PULSE_SERVER=unix:/run/user/1971/pulse/native",
|
||||||
"SHELL=/run/current-system/sw/bin/zsh",
|
"SHELL=/run/current-system/sw/bin/zsh",
|
||||||
"TERM=xterm-256color",
|
"TERM=xterm-256color",
|
||||||
@ -116,7 +116,7 @@ var testCasesNixos = []sealTestCase{
|
|||||||
},
|
},
|
||||||
Ops: new(sandbox.Ops).
|
Ops: new(sandbox.Ops).
|
||||||
Proc("/proc").
|
Proc("/proc").
|
||||||
Tmpfs(fst.Tmp, 4096, 0755).
|
Tmpfs(hst.Tmp, 4096, 0755).
|
||||||
Dev("/dev").Mqueue("/dev/mqueue").
|
Dev("/dev").Mqueue("/dev/mqueue").
|
||||||
Bind("/bin", "/bin", 0).
|
Bind("/bin", "/bin", 0).
|
||||||
Bind("/usr/bin", "/usr/bin", 0).
|
Bind("/usr/bin", "/usr/bin", 0).
|
||||||
@ -131,16 +131,16 @@ var testCasesNixos = []sealTestCase{
|
|||||||
Bind("/dev/dri", "/dev/dri", sandbox.BindDevice|sandbox.BindWritable|sandbox.BindOptional).
|
Bind("/dev/dri", "/dev/dri", sandbox.BindDevice|sandbox.BindWritable|sandbox.BindOptional).
|
||||||
Etc("/etc", "8e2c76b066dabe574cf073bdb46eb5c1").
|
Etc("/etc", "8e2c76b066dabe574cf073bdb46eb5c1").
|
||||||
Tmpfs("/run/user", 4096, 0755).
|
Tmpfs("/run/user", 4096, 0755).
|
||||||
Bind("/tmp/fortify.1971/runtime/1", "/run/user/1971", sandbox.BindWritable).
|
Bind("/tmp/hakurei.1971/runtime/1", "/run/user/1971", sandbox.BindWritable).
|
||||||
Bind("/tmp/fortify.1971/tmpdir/1", "/tmp", sandbox.BindWritable).
|
Bind("/tmp/hakurei.1971/tmpdir/1", "/tmp", sandbox.BindWritable).
|
||||||
Bind("/var/lib/persist/module/fortify/0/1", "/var/lib/persist/module/fortify/0/1", sandbox.BindWritable).
|
Bind("/var/lib/persist/module/hakurei/0/1", "/var/lib/persist/module/hakurei/0/1", sandbox.BindWritable).
|
||||||
Place("/etc/passwd", []byte("u0_a1:x:1971:100:Fortify:/var/lib/persist/module/fortify/0/1:/run/current-system/sw/bin/zsh\n")).
|
Place("/etc/passwd", []byte("u0_a1:x:1971:100:Hakurei:/var/lib/persist/module/hakurei/0/1:/run/current-system/sw/bin/zsh\n")).
|
||||||
Place("/etc/group", []byte("fortify:x:100:\n")).
|
Place("/etc/group", []byte("hakurei:x:100:\n")).
|
||||||
Bind("/run/user/1971/wayland-0", "/run/user/1971/wayland-0", 0).
|
Bind("/run/user/1971/wayland-0", "/run/user/1971/wayland-0", 0).
|
||||||
Bind("/run/user/1971/fortify/8e2c76b066dabe574cf073bdb46eb5c1/pulse", "/run/user/1971/pulse/native", 0).
|
Bind("/run/user/1971/hakurei/8e2c76b066dabe574cf073bdb46eb5c1/pulse", "/run/user/1971/pulse/native", 0).
|
||||||
Place(fst.Tmp+"/pulse-cookie", nil).
|
Place(hst.Tmp+"/pulse-cookie", nil).
|
||||||
Bind("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", "/run/user/1971/bus", 0).
|
Bind("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/bus", "/run/user/1971/bus", 0).
|
||||||
Bind("/tmp/fortify.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", "/run/dbus/system_bus_socket", 0).
|
Bind("/tmp/hakurei.1971/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", "/run/dbus/system_bus_socket", 0).
|
||||||
Tmpfs("/var/run/nscd", 8192, 0755),
|
Tmpfs("/var/run/nscd", 8192, 0755),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3,18 +3,18 @@ package setuid_test
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/acl"
|
"git.gensokyo.uk/security/hakurei/acl"
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
var testCasesPd = []sealTestCase{
|
var testCasesPd = []sealTestCase{
|
||||||
{
|
{
|
||||||
"nixos permissive defaults no enablements", new(stubNixOS),
|
"nixos permissive defaults no enablements", new(stubNixOS),
|
||||||
&fst.Config{Username: "chronos", Data: "/home/chronos"},
|
&hst.Config{Username: "chronos", Data: "/home/chronos"},
|
||||||
app.ID{
|
app.ID{
|
||||||
0x4a, 0x45, 0x0b, 0x65,
|
0x4a, 0x45, 0x0b, 0x65,
|
||||||
0x96, 0xd7, 0xbc, 0x15,
|
0x96, 0xd7, 0xbc, 0x15,
|
||||||
@ -22,11 +22,11 @@ var testCasesPd = []sealTestCase{
|
|||||||
0xb9, 0xa6, 0x07, 0xac,
|
0xb9, 0xa6, 0x07, 0xac,
|
||||||
},
|
},
|
||||||
system.New(1000000).
|
system.New(1000000).
|
||||||
Ensure("/tmp/fortify.1971", 0711).
|
Ensure("/tmp/hakurei.1971", 0711).
|
||||||
Ensure("/tmp/fortify.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime", acl.Execute).
|
Ensure("/tmp/hakurei.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime", acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/runtime/0", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime/0", acl.Read, acl.Write, acl.Execute).
|
Ensure("/tmp/hakurei.1971/runtime/0", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime/0", acl.Read, acl.Write, acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir", acl.Execute).
|
Ensure("/tmp/hakurei.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir", acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/tmpdir/0", 01700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir/0", acl.Read, acl.Write, acl.Execute),
|
Ensure("/tmp/hakurei.1971/tmpdir/0", 01700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir/0", acl.Read, acl.Write, acl.Execute),
|
||||||
&sandbox.Params{
|
&sandbox.Params{
|
||||||
Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
|
Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
|
||||||
Dir: "/home/chronos",
|
Dir: "/home/chronos",
|
||||||
@ -43,7 +43,7 @@ var testCasesPd = []sealTestCase{
|
|||||||
},
|
},
|
||||||
Ops: new(sandbox.Ops).
|
Ops: new(sandbox.Ops).
|
||||||
Proc("/proc").
|
Proc("/proc").
|
||||||
Tmpfs(fst.Tmp, 4096, 0755).
|
Tmpfs(hst.Tmp, 4096, 0755).
|
||||||
Dev("/dev").Mqueue("/dev/mqueue").
|
Dev("/dev").Mqueue("/dev/mqueue").
|
||||||
Bind("/bin", "/bin", sandbox.BindWritable).
|
Bind("/bin", "/bin", sandbox.BindWritable).
|
||||||
Bind("/boot", "/boot", sandbox.BindWritable).
|
Bind("/boot", "/boot", sandbox.BindWritable).
|
||||||
@ -62,17 +62,17 @@ var testCasesPd = []sealTestCase{
|
|||||||
Tmpfs("/run/dbus", 8192, 0755).
|
Tmpfs("/run/dbus", 8192, 0755).
|
||||||
Etc("/etc", "4a450b6596d7bc15bd01780eb9a607ac").
|
Etc("/etc", "4a450b6596d7bc15bd01780eb9a607ac").
|
||||||
Tmpfs("/run/user", 4096, 0755).
|
Tmpfs("/run/user", 4096, 0755).
|
||||||
Bind("/tmp/fortify.1971/runtime/0", "/run/user/65534", sandbox.BindWritable).
|
Bind("/tmp/hakurei.1971/runtime/0", "/run/user/65534", sandbox.BindWritable).
|
||||||
Bind("/tmp/fortify.1971/tmpdir/0", "/tmp", sandbox.BindWritable).
|
Bind("/tmp/hakurei.1971/tmpdir/0", "/tmp", sandbox.BindWritable).
|
||||||
Bind("/home/chronos", "/home/chronos", sandbox.BindWritable).
|
Bind("/home/chronos", "/home/chronos", sandbox.BindWritable).
|
||||||
Place("/etc/passwd", []byte("chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
Place("/etc/passwd", []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||||
Place("/etc/group", []byte("fortify:x:65534:\n")).
|
Place("/etc/group", []byte("hakurei:x:65534:\n")).
|
||||||
Tmpfs("/var/run/nscd", 8192, 0755),
|
Tmpfs("/var/run/nscd", 8192, 0755),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"nixos permissive defaults chromium", new(stubNixOS),
|
"nixos permissive defaults chromium", new(stubNixOS),
|
||||||
&fst.Config{
|
&hst.Config{
|
||||||
ID: "org.chromium.Chromium",
|
ID: "org.chromium.Chromium",
|
||||||
Args: []string{"zsh", "-c", "exec chromium "},
|
Args: []string{"zsh", "-c", "exec chromium "},
|
||||||
Identity: 9,
|
Identity: 9,
|
||||||
@ -119,19 +119,19 @@ var testCasesPd = []sealTestCase{
|
|||||||
0x9b, 0x64, 0xce, 0x7c,
|
0x9b, 0x64, 0xce, 0x7c,
|
||||||
},
|
},
|
||||||
system.New(1000009).
|
system.New(1000009).
|
||||||
Ensure("/tmp/fortify.1971", 0711).
|
Ensure("/tmp/hakurei.1971", 0711).
|
||||||
Ensure("/tmp/fortify.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime", acl.Execute).
|
Ensure("/tmp/hakurei.1971/runtime", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime", acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/runtime/9", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/runtime/9", acl.Read, acl.Write, acl.Execute).
|
Ensure("/tmp/hakurei.1971/runtime/9", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/runtime/9", acl.Read, acl.Write, acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir", acl.Execute).
|
Ensure("/tmp/hakurei.1971/tmpdir", 0700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir", acl.Execute).
|
||||||
Ensure("/tmp/fortify.1971/tmpdir/9", 01700).UpdatePermType(system.User, "/tmp/fortify.1971/tmpdir/9", acl.Read, acl.Write, acl.Execute).
|
Ensure("/tmp/hakurei.1971/tmpdir/9", 01700).UpdatePermType(system.User, "/tmp/hakurei.1971/tmpdir/9", acl.Read, acl.Write, acl.Execute).
|
||||||
Ephemeral(system.Process, "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c", 0711).
|
Ephemeral(system.Process, "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c", 0711).
|
||||||
Wayland(new(*os.File), "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/1971/wayland-0", "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
|
Wayland(new(*os.File), "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/1971/wayland-0", "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c").
|
||||||
Ensure("/run/user/1971/fortify", 0700).UpdatePermType(system.User, "/run/user/1971/fortify", acl.Execute).
|
Ensure("/run/user/1971/hakurei", 0700).UpdatePermType(system.User, "/run/user/1971/hakurei", acl.Execute).
|
||||||
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
|
Ensure("/run/user/1971", 0700).UpdatePermType(system.User, "/run/user/1971", acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset
|
||||||
Ephemeral(system.Process, "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c", 0700).UpdatePermType(system.Process, "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c", acl.Execute).
|
Ephemeral(system.Process, "/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c", 0700).UpdatePermType(system.Process, "/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c", acl.Execute).
|
||||||
Link("/run/user/1971/pulse/native", "/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/pulse").
|
Link("/run/user/1971/pulse/native", "/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c/pulse").
|
||||||
CopyFile(new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
|
CopyFile(new([]byte), "/home/ophestra/xdg/config/pulse/cookie", 256, 256).
|
||||||
MustProxyDBus("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", &dbus.Config{
|
MustProxyDBus("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", &dbus.Config{
|
||||||
Talk: []string{
|
Talk: []string{
|
||||||
"org.freedesktop.Notifications",
|
"org.freedesktop.Notifications",
|
||||||
"org.freedesktop.FileManager1",
|
"org.freedesktop.FileManager1",
|
||||||
@ -153,7 +153,7 @@ var testCasesPd = []sealTestCase{
|
|||||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*",
|
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*",
|
||||||
},
|
},
|
||||||
Filter: true,
|
Filter: true,
|
||||||
}, "/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", &dbus.Config{
|
}, "/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", &dbus.Config{
|
||||||
Talk: []string{
|
Talk: []string{
|
||||||
"org.bluez",
|
"org.bluez",
|
||||||
"org.freedesktop.Avahi",
|
"org.freedesktop.Avahi",
|
||||||
@ -161,8 +161,8 @@ var testCasesPd = []sealTestCase{
|
|||||||
},
|
},
|
||||||
Filter: true,
|
Filter: true,
|
||||||
}).
|
}).
|
||||||
UpdatePerm("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", acl.Read, acl.Write).
|
UpdatePerm("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", acl.Read, acl.Write).
|
||||||
UpdatePerm("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", acl.Read, acl.Write),
|
UpdatePerm("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", acl.Read, acl.Write),
|
||||||
&sandbox.Params{
|
&sandbox.Params{
|
||||||
Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
|
Flags: sandbox.FAllowNet | sandbox.FAllowUserns | sandbox.FAllowTTY,
|
||||||
Dir: "/home/chronos",
|
Dir: "/home/chronos",
|
||||||
@ -172,7 +172,7 @@ var testCasesPd = []sealTestCase{
|
|||||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
|
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus",
|
||||||
"DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
|
"DBUS_SYSTEM_BUS_ADDRESS=unix:path=/run/dbus/system_bus_socket",
|
||||||
"HOME=/home/chronos",
|
"HOME=/home/chronos",
|
||||||
"PULSE_COOKIE=" + fst.Tmp + "/pulse-cookie",
|
"PULSE_COOKIE=" + hst.Tmp + "/pulse-cookie",
|
||||||
"PULSE_SERVER=unix:/run/user/65534/pulse/native",
|
"PULSE_SERVER=unix:/run/user/65534/pulse/native",
|
||||||
"SHELL=/run/current-system/sw/bin/zsh",
|
"SHELL=/run/current-system/sw/bin/zsh",
|
||||||
"TERM=xterm-256color",
|
"TERM=xterm-256color",
|
||||||
@ -184,7 +184,7 @@ var testCasesPd = []sealTestCase{
|
|||||||
},
|
},
|
||||||
Ops: new(sandbox.Ops).
|
Ops: new(sandbox.Ops).
|
||||||
Proc("/proc").
|
Proc("/proc").
|
||||||
Tmpfs(fst.Tmp, 4096, 0755).
|
Tmpfs(hst.Tmp, 4096, 0755).
|
||||||
Dev("/dev").Mqueue("/dev/mqueue").
|
Dev("/dev").Mqueue("/dev/mqueue").
|
||||||
Bind("/bin", "/bin", sandbox.BindWritable).
|
Bind("/bin", "/bin", sandbox.BindWritable).
|
||||||
Bind("/boot", "/boot", sandbox.BindWritable).
|
Bind("/boot", "/boot", sandbox.BindWritable).
|
||||||
@ -204,16 +204,16 @@ var testCasesPd = []sealTestCase{
|
|||||||
Tmpfs("/run/dbus", 8192, 0755).
|
Tmpfs("/run/dbus", 8192, 0755).
|
||||||
Etc("/etc", "ebf083d1b175911782d413369b64ce7c").
|
Etc("/etc", "ebf083d1b175911782d413369b64ce7c").
|
||||||
Tmpfs("/run/user", 4096, 0755).
|
Tmpfs("/run/user", 4096, 0755).
|
||||||
Bind("/tmp/fortify.1971/runtime/9", "/run/user/65534", sandbox.BindWritable).
|
Bind("/tmp/hakurei.1971/runtime/9", "/run/user/65534", sandbox.BindWritable).
|
||||||
Bind("/tmp/fortify.1971/tmpdir/9", "/tmp", sandbox.BindWritable).
|
Bind("/tmp/hakurei.1971/tmpdir/9", "/tmp", sandbox.BindWritable).
|
||||||
Bind("/home/chronos", "/home/chronos", sandbox.BindWritable).
|
Bind("/home/chronos", "/home/chronos", sandbox.BindWritable).
|
||||||
Place("/etc/passwd", []byte("chronos:x:65534:65534:Fortify:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
Place("/etc/passwd", []byte("chronos:x:65534:65534:Hakurei:/home/chronos:/run/current-system/sw/bin/zsh\n")).
|
||||||
Place("/etc/group", []byte("fortify:x:65534:\n")).
|
Place("/etc/group", []byte("hakurei:x:65534:\n")).
|
||||||
Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/65534/wayland-0", 0).
|
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", "/run/user/65534/wayland-0", 0).
|
||||||
Bind("/run/user/1971/fortify/ebf083d1b175911782d413369b64ce7c/pulse", "/run/user/65534/pulse/native", 0).
|
Bind("/run/user/1971/hakurei/ebf083d1b175911782d413369b64ce7c/pulse", "/run/user/65534/pulse/native", 0).
|
||||||
Place(fst.Tmp+"/pulse-cookie", nil).
|
Place(hst.Tmp+"/pulse-cookie", nil).
|
||||||
Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/bus", "/run/user/65534/bus", 0).
|
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/bus", "/run/user/65534/bus", 0).
|
||||||
Bind("/tmp/fortify.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", "/run/dbus/system_bus_socket", 0).
|
Bind("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/system_bus_socket", "/run/dbus/system_bus_socket", 0).
|
||||||
Tmpfs("/var/run/nscd", 8192, 0755),
|
Tmpfs("/var/run/nscd", 8192, 0755),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"os/user"
|
"os/user"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fs methods are not implemented using a real FS
|
// fs methods are not implemented using a real FS
|
||||||
@ -20,7 +20,7 @@ type stubNixOS struct {
|
|||||||
func (s *stubNixOS) Getuid() int { return 1971 }
|
func (s *stubNixOS) Getuid() int { return 1971 }
|
||||||
func (s *stubNixOS) Getgid() int { return 100 }
|
func (s *stubNixOS) Getgid() int { return 100 }
|
||||||
func (s *stubNixOS) TempDir() string { return "/tmp" }
|
func (s *stubNixOS) TempDir() string { return "/tmp" }
|
||||||
func (s *stubNixOS) MustExecutable() string { return "/run/wrappers/bin/fortify" }
|
func (s *stubNixOS) MustExecutable() string { return "/run/wrappers/bin/hakurei" }
|
||||||
func (s *stubNixOS) Exit(code int) { panic("called exit on stub with code " + strconv.Itoa(code)) }
|
func (s *stubNixOS) Exit(code int) { panic("called exit on stub with code " + strconv.Itoa(code)) }
|
||||||
func (s *stubNixOS) EvalSymlinks(path string) (string, error) { return path, nil }
|
func (s *stubNixOS) EvalSymlinks(path string) (string, error) { return path, nil }
|
||||||
func (s *stubNixOS) Uid(aid int) (int, error) { return 1000000 + 0*10000 + aid, nil }
|
func (s *stubNixOS) Uid(aid int) (int, error) { return 1000000 + 0*10000 + aid, nil }
|
||||||
@ -127,8 +127,8 @@ func (s *stubNixOS) Open(name string) (fs.File, error) {
|
|||||||
|
|
||||||
func (s *stubNixOS) Paths() app.Paths {
|
func (s *stubNixOS) Paths() app.Paths {
|
||||||
return app.Paths{
|
return app.Paths{
|
||||||
SharePath: "/tmp/fortify.1971",
|
SharePath: "/tmp/hakurei.1971",
|
||||||
RuntimePath: "/run/user/1971",
|
RuntimePath: "/run/user/1971",
|
||||||
RunDirPath: "/run/user/1971/fortify",
|
RunDirPath: "/run/user/1971/hakurei",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,18 +7,18 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app/internal/setuid"
|
"git.gensokyo.uk/security/hakurei/internal/app/internal/setuid"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sealTestCase struct {
|
type sealTestCase struct {
|
||||||
name string
|
name string
|
||||||
os sys.State
|
os sys.State
|
||||||
config *fst.Config
|
config *hst.Config
|
||||||
id app.ID
|
id app.ID
|
||||||
wantSys *system.I
|
wantSys *system.I
|
||||||
wantContainer *sandbox.Params
|
wantContainer *sandbox.Params
|
||||||
@ -80,70 +80,25 @@ func stubDirEntries(names ...string) (e []fs.DirEntry, err error) {
|
|||||||
|
|
||||||
type stubDirEntryPath string
|
type stubDirEntryPath string
|
||||||
|
|
||||||
func (p stubDirEntryPath) Name() string {
|
func (p stubDirEntryPath) Name() string { return string(p) }
|
||||||
return string(p)
|
func (p stubDirEntryPath) IsDir() bool { panic("attempted to call IsDir") }
|
||||||
}
|
func (p stubDirEntryPath) Type() fs.FileMode { panic("attempted to call Type") }
|
||||||
|
func (p stubDirEntryPath) Info() (fs.FileInfo, error) { panic("attempted to call Info") }
|
||||||
func (p stubDirEntryPath) IsDir() bool {
|
|
||||||
panic("attempted to call IsDir")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p stubDirEntryPath) Type() fs.FileMode {
|
|
||||||
panic("attempted to call Type")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p stubDirEntryPath) Info() (fs.FileInfo, error) {
|
|
||||||
panic("attempted to call Info")
|
|
||||||
}
|
|
||||||
|
|
||||||
type stubFileInfoMode fs.FileMode
|
type stubFileInfoMode fs.FileMode
|
||||||
|
|
||||||
func (s stubFileInfoMode) Name() string {
|
func (s stubFileInfoMode) Name() string { panic("attempted to call Name") }
|
||||||
panic("attempted to call Name")
|
func (s stubFileInfoMode) Size() int64 { panic("attempted to call Size") }
|
||||||
}
|
func (s stubFileInfoMode) Mode() fs.FileMode { return fs.FileMode(s) }
|
||||||
|
func (s stubFileInfoMode) ModTime() time.Time { panic("attempted to call ModTime") }
|
||||||
func (s stubFileInfoMode) Size() int64 {
|
func (s stubFileInfoMode) IsDir() bool { panic("attempted to call IsDir") }
|
||||||
panic("attempted to call Size")
|
func (s stubFileInfoMode) Sys() any { panic("attempted to call Sys") }
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoMode) Mode() fs.FileMode {
|
|
||||||
return fs.FileMode(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoMode) ModTime() time.Time {
|
|
||||||
panic("attempted to call ModTime")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoMode) IsDir() bool {
|
|
||||||
panic("attempted to call IsDir")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoMode) Sys() any {
|
|
||||||
panic("attempted to call Sys")
|
|
||||||
}
|
|
||||||
|
|
||||||
type stubFileInfoIsDir bool
|
type stubFileInfoIsDir bool
|
||||||
|
|
||||||
func (s stubFileInfoIsDir) Name() string {
|
func (s stubFileInfoIsDir) Name() string { panic("attempted to call Name") }
|
||||||
panic("attempted to call Name")
|
func (s stubFileInfoIsDir) Size() int64 { panic("attempted to call Size") }
|
||||||
}
|
func (s stubFileInfoIsDir) Mode() fs.FileMode { panic("attempted to call Mode") }
|
||||||
|
func (s stubFileInfoIsDir) ModTime() time.Time { panic("attempted to call ModTime") }
|
||||||
func (s stubFileInfoIsDir) Size() int64 {
|
func (s stubFileInfoIsDir) IsDir() bool { return bool(s) }
|
||||||
panic("attempted to call Size")
|
func (s stubFileInfoIsDir) Sys() any { panic("attempted to call Sys") }
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoIsDir) Mode() fs.FileMode {
|
|
||||||
panic("attempted to call Mode")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoIsDir) ModTime() time.Time {
|
|
||||||
panic("attempted to call ModTime")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoIsDir) IsDir() bool {
|
|
||||||
return bool(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s stubFileInfoIsDir) Sys() any {
|
|
||||||
panic("attempted to call Sys")
|
|
||||||
}
|
|
||||||
|
@ -4,8 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
. "git.gensokyo.uk/security/fortify/internal/app"
|
. "git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
||||||
@ -13,10 +13,10 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
|||||||
|
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
if rs.Time == nil {
|
if rs.Time == nil {
|
||||||
fmsg.PrintBaseError(runErr, "cannot start app:")
|
hlog.PrintBaseError(runErr, "cannot start app:")
|
||||||
} else {
|
} else {
|
||||||
var e *fmsg.BaseError
|
var e *hlog.BaseError
|
||||||
if !fmsg.AsBaseError(runErr, &e) {
|
if !hlog.AsBaseError(runErr, &e) {
|
||||||
log.Println("wait failed:", runErr)
|
log.Println("wait failed:", runErr)
|
||||||
} else {
|
} else {
|
||||||
// Wait only returns either *app.ProcessError or *app.StateStoreError wrapped in a *app.BaseError
|
// Wait only returns either *app.ProcessError or *app.StateStoreError wrapped in a *app.BaseError
|
||||||
@ -37,7 +37,7 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
|||||||
|
|
||||||
// every error here is wrapped in *app.BaseError
|
// every error here is wrapped in *app.BaseError
|
||||||
for _, ei := range errs {
|
for _, ei := range errs {
|
||||||
var eb *fmsg.BaseError
|
var eb *hlog.BaseError
|
||||||
if !errors.As(ei, &eb) {
|
if !errors.As(ei, &eb) {
|
||||||
// unreachable
|
// unreachable
|
||||||
log.Println("invalid error type returned by revert:", ei)
|
log.Println("invalid error type returned by revert:", ei)
|
||||||
@ -59,7 +59,7 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
|||||||
if rs.RevertErr != nil {
|
if rs.RevertErr != nil {
|
||||||
var stateStoreError *StateStoreError
|
var stateStoreError *StateStoreError
|
||||||
if !errors.As(rs.RevertErr, &stateStoreError) || stateStoreError == nil {
|
if !errors.As(rs.RevertErr, &stateStoreError) || stateStoreError == nil {
|
||||||
fmsg.PrintBaseError(rs.RevertErr, "generic fault during cleanup:")
|
hlog.PrintBaseError(rs.RevertErr, "generic fault during cleanup:")
|
||||||
goto out
|
goto out
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,11 +67,11 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
|||||||
if len(stateStoreError.Err) == 2 {
|
if len(stateStoreError.Err) == 2 {
|
||||||
if stateStoreError.Err[0] != nil {
|
if stateStoreError.Err[0] != nil {
|
||||||
if joinedErrs, ok := stateStoreError.Err[0].(interface{ Unwrap() []error }); !ok {
|
if joinedErrs, ok := stateStoreError.Err[0].(interface{ Unwrap() []error }); !ok {
|
||||||
fmsg.PrintBaseError(stateStoreError.Err[0], "generic fault during revert:")
|
hlog.PrintBaseError(stateStoreError.Err[0], "generic fault during revert:")
|
||||||
} else {
|
} else {
|
||||||
for _, err := range joinedErrs.Unwrap() {
|
for _, err := range joinedErrs.Unwrap() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmsg.PrintBaseError(err, "fault during revert:")
|
hlog.PrintBaseError(err, "fault during revert:")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,11 +91,11 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if stateStoreError.DoErr != nil {
|
if stateStoreError.DoErr != nil {
|
||||||
fmsg.PrintBaseError(stateStoreError.DoErr, "state store operation unsuccessful:")
|
hlog.PrintBaseError(stateStoreError.DoErr, "state store operation unsuccessful:")
|
||||||
}
|
}
|
||||||
|
|
||||||
if stateStoreError.Inner && stateStoreError.InnerErr != nil {
|
if stateStoreError.Inner && stateStoreError.InnerErr != nil {
|
||||||
fmsg.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:")
|
hlog.PrintBaseError(stateStoreError.InnerErr, "cannot destroy state entry:")
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -104,7 +104,7 @@ func PrintRunStateErr(rs *RunState, runErr error) (code int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rs.WaitErr != nil {
|
if rs.WaitErr != nil {
|
||||||
fmsg.Verbosef("wait: %v", rs.WaitErr)
|
hlog.Verbosef("wait: %v", rs.WaitErr)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ func (e *StateStoreError) equiv(a ...any) error {
|
|||||||
if e.Inner && e.InnerErr == nil && e.DoErr == nil && e.OpErr == nil && errors.Join(e.Err...) == nil {
|
if e.Inner && e.InnerErr == nil && e.DoErr == nil && e.OpErr == nil && errors.Join(e.Err...) == nil {
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return fmsg.WrapErrorSuffix(e, a...)
|
return hlog.WrapErrSuffix(e, a...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package setuid
|
package setuid
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "git.gensokyo.uk/security/fortify/internal/app"
|
. "git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewWithID(id ID, os sys.State) App {
|
func NewWithID(id ID, os sys.State) App {
|
||||||
|
@ -12,12 +12,12 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
. "git.gensokyo.uk/security/fortify/internal/app"
|
. "git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/internal/state"
|
"git.gensokyo.uk/security/hakurei/internal/state"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
const shimWaitTimeout = 5 * time.Second
|
const shimWaitTimeout = 5 * time.Second
|
||||||
@ -35,7 +35,7 @@ func (seal *outcome) Run(rs *RunState) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// read comp value early to allow for early failure
|
// read comp value early to allow for early failure
|
||||||
fsuPath := internal.MustFsuPath()
|
hsuPath := internal.MustHsuPath()
|
||||||
|
|
||||||
if err := seal.sys.Commit(seal.ctx); err != nil {
|
if err := seal.sys.Commit(seal.ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -59,7 +59,7 @@ func (seal *outcome) Run(rs *RunState) error {
|
|||||||
if l := len(states); l == 0 {
|
if l := len(states); l == 0 {
|
||||||
ec |= system.User
|
ec |= system.User
|
||||||
} else {
|
} else {
|
||||||
fmsg.Verbosef("found %d instances, cleaning up without user-scoped operations", l)
|
hlog.Verbosef("found %d instances, cleaning up without user-scoped operations", l)
|
||||||
}
|
}
|
||||||
|
|
||||||
// accumulate enablements of remaining launchers
|
// accumulate enablements of remaining launchers
|
||||||
@ -72,9 +72,9 @@ func (seal *outcome) Run(rs *RunState) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ec |= rt ^ (system.EWayland | system.EX11 | system.EDBus | system.EPulse)
|
ec |= rt ^ (system.EWayland | system.EX11 | system.EDBus | system.EPulse)
|
||||||
if fmsg.Load() {
|
if hlog.Load() {
|
||||||
if ec > 0 {
|
if ec > 0 {
|
||||||
fmsg.Verbose("reverting operations scope", system.TypeString(ec))
|
hlog.Verbose("reverting operations scope", system.TypeString(ec))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ func (seal *outcome) Run(rs *RunState) error {
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(seal.ctx)
|
ctx, cancel := context.WithCancel(seal.ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
cmd := exec.CommandContext(ctx, fsuPath)
|
cmd := exec.CommandContext(ctx, hsuPath)
|
||||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||||
cmd.Dir = "/" // container init enters final working directory
|
cmd.Dir = "/" // container init enters final working directory
|
||||||
// shim runs in the same session as monitor; see shim.go for behaviour
|
// shim runs in the same session as monitor; see shim.go for behaviour
|
||||||
@ -95,28 +95,28 @@ func (seal *outcome) Run(rs *RunState) error {
|
|||||||
|
|
||||||
var e *gob.Encoder
|
var e *gob.Encoder
|
||||||
if fd, encoder, err := sandbox.Setup(&cmd.ExtraFiles); err != nil {
|
if fd, encoder, err := sandbox.Setup(&cmd.ExtraFiles); err != nil {
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
"cannot create shim setup pipe:")
|
"cannot create shim setup pipe:")
|
||||||
} else {
|
} else {
|
||||||
e = encoder
|
e = encoder
|
||||||
cmd.Env = []string{
|
cmd.Env = []string{
|
||||||
// passed through to shim by fsu
|
// passed through to shim by hsu
|
||||||
shimEnv + "=" + strconv.Itoa(fd),
|
shimEnv + "=" + strconv.Itoa(fd),
|
||||||
// interpreted by fsu
|
// interpreted by hsu
|
||||||
"FORTIFY_APP_ID=" + seal.user.aid.String(),
|
"HAKUREI_APP_ID=" + seal.user.aid.String(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(seal.user.supp) > 0 {
|
if len(seal.user.supp) > 0 {
|
||||||
fmsg.Verbosef("attaching supplementary group ids %s", seal.user.supp)
|
hlog.Verbosef("attaching supplementary group ids %s", seal.user.supp)
|
||||||
// interpreted by fsu
|
// interpreted by hsu
|
||||||
cmd.Env = append(cmd.Env, "FORTIFY_GROUPS="+strings.Join(seal.user.supp, " "))
|
cmd.Env = append(cmd.Env, "HAKUREI_GROUPS="+strings.Join(seal.user.supp, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
fmsg.Verbosef("setuid helper at %s", fsuPath)
|
hlog.Verbosef("setuid helper at %s", hsuPath)
|
||||||
fmsg.Suspend()
|
hlog.Suspend()
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
"cannot start setuid wrapper:")
|
"cannot start setuid wrapper:")
|
||||||
}
|
}
|
||||||
rs.SetStart()
|
rs.SetStart()
|
||||||
@ -124,19 +124,19 @@ func (seal *outcome) Run(rs *RunState) error {
|
|||||||
// this prevents blocking forever on an early failure
|
// this prevents blocking forever on an early failure
|
||||||
waitErr, setupErr := make(chan error, 1), make(chan error, 1)
|
waitErr, setupErr := make(chan error, 1), make(chan error, 1)
|
||||||
go func() { waitErr <- cmd.Wait(); cancel() }()
|
go func() { waitErr <- cmd.Wait(); cancel() }()
|
||||||
go func() { setupErr <- e.Encode(&shimParams{os.Getpid(), seal.container, seal.user.data, fmsg.Load()}) }()
|
go func() { setupErr <- e.Encode(&shimParams{os.Getpid(), seal.container, seal.user.data, hlog.Load()}) }()
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case err := <-setupErr:
|
case err := <-setupErr:
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmsg.Resume()
|
hlog.Resume()
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
"cannot transmit shim config:")
|
"cannot transmit shim config:")
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
fmsg.Resume()
|
hlog.Resume()
|
||||||
return fmsg.WrapError(syscall.ECANCELED,
|
return hlog.WrapErr(syscall.ECANCELED,
|
||||||
"shim setup canceled")
|
"shim setup canceled")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,25 +163,25 @@ func (seal *outcome) Run(rs *RunState) error {
|
|||||||
select {
|
select {
|
||||||
case rs.WaitErr = <-waitErr:
|
case rs.WaitErr = <-waitErr:
|
||||||
rs.WaitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
|
rs.WaitStatus = cmd.ProcessState.Sys().(syscall.WaitStatus)
|
||||||
if fmsg.Load() {
|
if hlog.Load() {
|
||||||
switch {
|
switch {
|
||||||
case rs.Exited():
|
case rs.Exited():
|
||||||
fmsg.Verbosef("process %d exited with code %d", cmd.Process.Pid, rs.ExitStatus())
|
hlog.Verbosef("process %d exited with code %d", cmd.Process.Pid, rs.ExitStatus())
|
||||||
case rs.CoreDump():
|
case rs.CoreDump():
|
||||||
fmsg.Verbosef("process %d dumped core", cmd.Process.Pid)
|
hlog.Verbosef("process %d dumped core", cmd.Process.Pid)
|
||||||
case rs.Signaled():
|
case rs.Signaled():
|
||||||
fmsg.Verbosef("process %d got %s", cmd.Process.Pid, rs.Signal())
|
hlog.Verbosef("process %d got %s", cmd.Process.Pid, rs.Signal())
|
||||||
default:
|
default:
|
||||||
fmsg.Verbosef("process %d exited with status %#x", cmd.Process.Pid, rs.WaitStatus)
|
hlog.Verbosef("process %d exited with status %#x", cmd.Process.Pid, rs.WaitStatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-waitTimeout:
|
case <-waitTimeout:
|
||||||
rs.WaitErr = syscall.ETIMEDOUT
|
rs.WaitErr = syscall.ETIMEDOUT
|
||||||
fmsg.Resume()
|
hlog.Resume()
|
||||||
log.Printf("process %d did not terminate", cmd.Process.Pid)
|
log.Printf("process %d did not terminate", cmd.Process.Pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmsg.Resume()
|
hlog.Resume()
|
||||||
if seal.sync != nil {
|
if seal.sync != nil {
|
||||||
if err := seal.sync.Close(); err != nil {
|
if err := seal.sync.Close(); err != nil {
|
||||||
log.Printf("cannot close wayland security context: %v", err)
|
log.Printf("cannot close wayland security context: %v", err)
|
||||||
|
@ -16,17 +16,17 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/acl"
|
"git.gensokyo.uk/security/hakurei/acl"
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
. "git.gensokyo.uk/security/fortify/internal/app"
|
. "git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app/instance/common"
|
"git.gensokyo.uk/security/hakurei/internal/app/instance/common"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/wl"
|
"git.gensokyo.uk/security/hakurei/sandbox/wl"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -63,20 +63,20 @@ var (
|
|||||||
|
|
||||||
var posixUsername = regexp.MustCompilePOSIX("^[a-z_]([A-Za-z0-9_-]{0,31}|[A-Za-z0-9_-]{0,30}\\$)$")
|
var posixUsername = regexp.MustCompilePOSIX("^[a-z_]([A-Za-z0-9_-]{0,31}|[A-Za-z0-9_-]{0,30}\\$)$")
|
||||||
|
|
||||||
// outcome stores copies of various parts of [fst.Config]
|
// outcome stores copies of various parts of [hst.Config]
|
||||||
type outcome struct {
|
type outcome struct {
|
||||||
// copied from initialising [app]
|
// copied from initialising [app]
|
||||||
id *stringPair[ID]
|
id *stringPair[ID]
|
||||||
// copied from [sys.State] response
|
// copied from [sys.State] response
|
||||||
runDirPath string
|
runDirPath string
|
||||||
|
|
||||||
// initial [fst.Config] gob stream for state data;
|
// initial [hst.Config] gob stream for state data;
|
||||||
// this is prepared ahead of time as config is clobbered during seal creation
|
// this is prepared ahead of time as config is clobbered during seal creation
|
||||||
ct io.WriterTo
|
ct io.WriterTo
|
||||||
// dump dbus proxy message buffer
|
// dump dbus proxy message buffer
|
||||||
dbusMsg func()
|
dbusMsg func()
|
||||||
|
|
||||||
user fsuUser
|
user hsuUser
|
||||||
sys *system.I
|
sys *system.I
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ type outcome struct {
|
|||||||
|
|
||||||
// shareHost holds optional share directory state that must not be accessed directly
|
// shareHost holds optional share directory state that must not be accessed directly
|
||||||
type shareHost struct {
|
type shareHost struct {
|
||||||
// whether XDG_RUNTIME_DIR is used post fsu
|
// whether XDG_RUNTIME_DIR is used post hsu
|
||||||
useRuntimeDir bool
|
useRuntimeDir bool
|
||||||
// process-specific directory in tmpdir, empty if unused
|
// process-specific directory in tmpdir, empty if unused
|
||||||
sharePath string
|
sharePath string
|
||||||
@ -134,8 +134,8 @@ func (share *shareHost) runtime() string {
|
|||||||
return share.runtimeSharePath
|
return share.runtimeSharePath
|
||||||
}
|
}
|
||||||
|
|
||||||
// fsuUser stores post-fsu credentials and metadata
|
// hsuUser stores post-hsu credentials and metadata
|
||||||
type fsuUser struct {
|
type hsuUser struct {
|
||||||
// application id
|
// application id
|
||||||
aid *stringPair[int]
|
aid *stringPair[int]
|
||||||
// target uid resolved by fid:aid
|
// target uid resolved by fid:aid
|
||||||
@ -152,7 +152,7 @@ type fsuUser struct {
|
|||||||
username string
|
username string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Config) error {
|
func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Config) error {
|
||||||
if seal.ctx != nil {
|
if seal.ctx != nil {
|
||||||
panic("finalise called twice")
|
panic("finalise called twice")
|
||||||
}
|
}
|
||||||
@ -162,19 +162,19 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
// encode initial configuration for state tracking
|
// encode initial configuration for state tracking
|
||||||
ct := new(bytes.Buffer)
|
ct := new(bytes.Buffer)
|
||||||
if err := gob.NewEncoder(ct).Encode(config); err != nil {
|
if err := gob.NewEncoder(ct).Encode(config); err != nil {
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
"cannot encode initial config:")
|
"cannot encode initial config:")
|
||||||
}
|
}
|
||||||
seal.ct = ct
|
seal.ct = ct
|
||||||
}
|
}
|
||||||
|
|
||||||
// allowed aid range 0 to 9999, this is checked again in fsu
|
// allowed aid range 0 to 9999, this is checked again in hsu
|
||||||
if config.Identity < 0 || config.Identity > 9999 {
|
if config.Identity < 0 || config.Identity > 9999 {
|
||||||
return fmsg.WrapError(ErrUser,
|
return hlog.WrapErr(ErrUser,
|
||||||
fmt.Sprintf("identity %d out of range", config.Identity))
|
fmt.Sprintf("identity %d out of range", config.Identity))
|
||||||
}
|
}
|
||||||
|
|
||||||
seal.user = fsuUser{
|
seal.user = hsuUser{
|
||||||
aid: newInt(config.Identity),
|
aid: newInt(config.Identity),
|
||||||
data: config.Data,
|
data: config.Data,
|
||||||
home: config.Dir,
|
home: config.Dir,
|
||||||
@ -184,11 +184,11 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
seal.user.username = "chronos"
|
seal.user.username = "chronos"
|
||||||
} else if !posixUsername.MatchString(seal.user.username) ||
|
} else if !posixUsername.MatchString(seal.user.username) ||
|
||||||
len(seal.user.username) >= internal.Sysconf_SC_LOGIN_NAME_MAX() {
|
len(seal.user.username) >= internal.Sysconf_SC_LOGIN_NAME_MAX() {
|
||||||
return fmsg.WrapError(ErrName,
|
return hlog.WrapErr(ErrName,
|
||||||
fmt.Sprintf("invalid user name %q", seal.user.username))
|
fmt.Sprintf("invalid user name %q", seal.user.username))
|
||||||
}
|
}
|
||||||
if seal.user.data == "" || !path.IsAbs(seal.user.data) {
|
if seal.user.data == "" || !path.IsAbs(seal.user.data) {
|
||||||
return fmsg.WrapError(ErrHome,
|
return hlog.WrapErr(ErrHome,
|
||||||
fmt.Sprintf("invalid home directory %q", seal.user.data))
|
fmt.Sprintf("invalid home directory %q", seal.user.data))
|
||||||
}
|
}
|
||||||
if seal.user.home == "" {
|
if seal.user.home == "" {
|
||||||
@ -202,7 +202,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
seal.user.supp = make([]string, len(config.Groups))
|
seal.user.supp = make([]string, len(config.Groups))
|
||||||
for i, name := range config.Groups {
|
for i, name := range config.Groups {
|
||||||
if g, err := sys.LookupGroup(name); err != nil {
|
if g, err := sys.LookupGroup(name); err != nil {
|
||||||
return fmsg.WrapError(err,
|
return hlog.WrapErr(err,
|
||||||
fmt.Sprintf("unknown group %q", name))
|
fmt.Sprintf("unknown group %q", name))
|
||||||
} else {
|
} else {
|
||||||
seal.user.supp[i] = g.Gid
|
seal.user.supp[i] = g.Gid
|
||||||
@ -220,13 +220,13 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
|
|
||||||
// permissive defaults
|
// permissive defaults
|
||||||
if config.Container == nil {
|
if config.Container == nil {
|
||||||
fmsg.Verbose("container configuration not supplied, PROCEED WITH CAUTION")
|
hlog.Verbose("container configuration not supplied, PROCEED WITH CAUTION")
|
||||||
|
|
||||||
// fsu clears the environment so resolve paths early
|
// hsu clears the environment so resolve paths early
|
||||||
if !path.IsAbs(config.Path) {
|
if !path.IsAbs(config.Path) {
|
||||||
if len(config.Args) > 0 {
|
if len(config.Args) > 0 {
|
||||||
if p, err := sys.LookPath(config.Args[0]); err != nil {
|
if p, err := sys.LookPath(config.Args[0]); err != nil {
|
||||||
return fmsg.WrapError(err, err.Error())
|
return hlog.WrapErr(err, err.Error())
|
||||||
} else {
|
} else {
|
||||||
config.Path = p
|
config.Path = p
|
||||||
}
|
}
|
||||||
@ -235,7 +235,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conf := &fst.ContainerConfig{
|
conf := &hst.ContainerConfig{
|
||||||
Userns: true,
|
Userns: true,
|
||||||
Net: true,
|
Net: true,
|
||||||
Tty: true,
|
Tty: true,
|
||||||
@ -245,7 +245,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
if d, err := sys.ReadDir("/"); err != nil {
|
if d, err := sys.ReadDir("/"); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
b := make([]*fst.FilesystemConfig, 0, len(d))
|
b := make([]*hst.FilesystemConfig, 0, len(d))
|
||||||
for _, ent := range d {
|
for _, ent := range d {
|
||||||
p := "/" + ent.Name()
|
p := "/" + ent.Name()
|
||||||
switch p {
|
switch p {
|
||||||
@ -256,7 +256,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
case "/etc":
|
case "/etc":
|
||||||
|
|
||||||
default:
|
default:
|
||||||
b = append(b, &fst.FilesystemConfig{Src: p, Write: true, Must: true})
|
b = append(b, &hst.FilesystemConfig{Src: p, Write: true, Must: true})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
conf.Filesystem = append(conf.Filesystem, b...)
|
conf.Filesystem = append(conf.Filesystem, b...)
|
||||||
@ -269,10 +269,10 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
}
|
}
|
||||||
// bind GPU stuff
|
// bind GPU stuff
|
||||||
if config.Enablements&(system.EX11|system.EWayland) != 0 {
|
if config.Enablements&(system.EX11|system.EWayland) != 0 {
|
||||||
conf.Filesystem = append(conf.Filesystem, &fst.FilesystemConfig{Src: "/dev/dri", Device: true})
|
conf.Filesystem = append(conf.Filesystem, &hst.FilesystemConfig{Src: "/dev/dri", Device: true})
|
||||||
}
|
}
|
||||||
// opportunistically bind kvm
|
// opportunistically bind kvm
|
||||||
conf.Filesystem = append(conf.Filesystem, &fst.FilesystemConfig{Src: "/dev/kvm", Device: true})
|
conf.Filesystem = append(conf.Filesystem, &hst.FilesystemConfig{Src: "/dev/kvm", Device: true})
|
||||||
|
|
||||||
config.Container = conf
|
config.Container = conf
|
||||||
}
|
}
|
||||||
@ -283,11 +283,11 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
var err error
|
var err error
|
||||||
seal.container, seal.env, err = common.NewContainer(config.Container, sys, &uid, &gid)
|
seal.container, seal.env, err = common.NewContainer(config.Container, sys, &uid, &gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
"cannot initialise container configuration:")
|
"cannot initialise container configuration:")
|
||||||
}
|
}
|
||||||
if !path.IsAbs(config.Path) {
|
if !path.IsAbs(config.Path) {
|
||||||
return fmsg.WrapError(syscall.EINVAL,
|
return hlog.WrapErr(syscall.EINVAL,
|
||||||
"invalid program path")
|
"invalid program path")
|
||||||
}
|
}
|
||||||
if len(config.Args) == 0 {
|
if len(config.Args) == 0 {
|
||||||
@ -364,9 +364,9 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
seal.env[shell] = config.Shell
|
seal.env[shell] = config.Shell
|
||||||
|
|
||||||
seal.container.Place("/etc/passwd",
|
seal.container.Place("/etc/passwd",
|
||||||
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Fortify:"+homeDir+":"+config.Shell+"\n"))
|
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Hakurei:"+homeDir+":"+config.Shell+"\n"))
|
||||||
seal.container.Place("/etc/group",
|
seal.container.Place("/etc/group",
|
||||||
[]byte("fortify:x:"+mapgid.String()+":\n"))
|
[]byte("hakurei:x:"+mapgid.String()+":\n"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass TERM for proper terminal I/O in initial process
|
// pass TERM for proper terminal I/O in initial process
|
||||||
@ -378,7 +378,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
|
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
|
||||||
var socketPath string
|
var socketPath string
|
||||||
if name, ok := sys.LookupEnv(wl.WaylandDisplay); !ok {
|
if name, ok := sys.LookupEnv(wl.WaylandDisplay); !ok {
|
||||||
fmsg.Verbose(wl.WaylandDisplay + " is not set, assuming " + wl.FallbackName)
|
hlog.Verbose(wl.WaylandDisplay + " is not set, assuming " + wl.FallbackName)
|
||||||
socketPath = path.Join(share.sc.RuntimePath, wl.FallbackName)
|
socketPath = path.Join(share.sc.RuntimePath, wl.FallbackName)
|
||||||
} else if !path.IsAbs(name) {
|
} else if !path.IsAbs(name) {
|
||||||
socketPath = path.Join(share.sc.RuntimePath, name)
|
socketPath = path.Join(share.sc.RuntimePath, name)
|
||||||
@ -393,14 +393,14 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
appID := config.ID
|
appID := config.ID
|
||||||
if appID == "" {
|
if appID == "" {
|
||||||
// use instance ID in case app id is not set
|
// use instance ID in case app id is not set
|
||||||
appID = "uk.gensokyo.fortify." + seal.id.String()
|
appID = "uk.gensokyo.hakurei." + seal.id.String()
|
||||||
}
|
}
|
||||||
// downstream socket paths
|
// downstream socket paths
|
||||||
outerPath := path.Join(share.instance(), "wayland")
|
outerPath := path.Join(share.instance(), "wayland")
|
||||||
seal.sys.Wayland(&seal.sync, outerPath, socketPath, appID, seal.id.String())
|
seal.sys.Wayland(&seal.sync, outerPath, socketPath, appID, seal.id.String())
|
||||||
seal.container.Bind(outerPath, innerPath, 0)
|
seal.container.Bind(outerPath, innerPath, 0)
|
||||||
} else { // bind mount wayland socket (insecure)
|
} else { // bind mount wayland socket (insecure)
|
||||||
fmsg.Verbose("direct wayland access, PROCEED WITH CAUTION")
|
hlog.Verbose("direct wayland access, PROCEED WITH CAUTION")
|
||||||
share.ensureRuntimeDir()
|
share.ensureRuntimeDir()
|
||||||
seal.container.Bind(socketPath, innerPath, 0)
|
seal.container.Bind(socketPath, innerPath, 0)
|
||||||
seal.sys.UpdatePermType(system.EWayland, socketPath, acl.Read, acl.Write, acl.Execute)
|
seal.sys.UpdatePermType(system.EWayland, socketPath, acl.Read, acl.Write, acl.Execute)
|
||||||
@ -409,7 +409,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
|
|
||||||
if config.Enablements&system.EX11 != 0 {
|
if config.Enablements&system.EX11 != 0 {
|
||||||
if d, ok := sys.LookupEnv(display); !ok {
|
if d, ok := sys.LookupEnv(display); !ok {
|
||||||
return fmsg.WrapError(ErrXDisplay,
|
return hlog.WrapErr(ErrXDisplay,
|
||||||
"DISPLAY is not set")
|
"DISPLAY is not set")
|
||||||
} else {
|
} else {
|
||||||
seal.sys.ChangeHosts("#" + seal.user.uid.String())
|
seal.sys.ChangeHosts("#" + seal.user.uid.String())
|
||||||
@ -426,23 +426,23 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
|
|
||||||
if _, err := sys.Stat(pulseRuntimeDir); err != nil {
|
if _, err := sys.Stat(pulseRuntimeDir); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
fmt.Sprintf("cannot access PulseAudio directory %q:", pulseRuntimeDir))
|
fmt.Sprintf("cannot access PulseAudio directory %q:", pulseRuntimeDir))
|
||||||
}
|
}
|
||||||
return fmsg.WrapError(ErrPulseSocket,
|
return hlog.WrapErr(ErrPulseSocket,
|
||||||
fmt.Sprintf("PulseAudio directory %q not found", pulseRuntimeDir))
|
fmt.Sprintf("PulseAudio directory %q not found", pulseRuntimeDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
if s, err := sys.Stat(pulseSocket); err != nil {
|
if s, err := sys.Stat(pulseSocket); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return fmsg.WrapErrorSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
fmt.Sprintf("cannot access PulseAudio socket %q:", pulseSocket))
|
fmt.Sprintf("cannot access PulseAudio socket %q:", pulseSocket))
|
||||||
}
|
}
|
||||||
return fmsg.WrapError(ErrPulseSocket,
|
return hlog.WrapErr(ErrPulseSocket,
|
||||||
fmt.Sprintf("PulseAudio directory %q found but socket does not exist", pulseRuntimeDir))
|
fmt.Sprintf("PulseAudio directory %q found but socket does not exist", pulseRuntimeDir))
|
||||||
} else {
|
} else {
|
||||||
if m := s.Mode(); m&0o006 != 0o006 {
|
if m := s.Mode(); m&0o006 != 0o006 {
|
||||||
return fmsg.WrapError(ErrPulseMode,
|
return hlog.WrapErr(ErrPulseMode,
|
||||||
fmt.Sprintf("unexpected permissions on %q:", pulseSocket), m)
|
fmt.Sprintf("unexpected permissions on %q:", pulseSocket), m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,9 +457,9 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
// publish current user's pulse cookie for target user
|
// publish current user's pulse cookie for target user
|
||||||
if src, err := discoverPulseCookie(sys); err != nil {
|
if src, err := discoverPulseCookie(sys); err != nil {
|
||||||
// not fatal
|
// not fatal
|
||||||
fmsg.Verbose(strings.TrimSpace(err.(*fmsg.BaseError).Message()))
|
hlog.Verbose(strings.TrimSpace(err.(*hlog.BaseError).Message()))
|
||||||
} else {
|
} else {
|
||||||
innerDst := fst.Tmp + "/pulse-cookie"
|
innerDst := hst.Tmp + "/pulse-cookie"
|
||||||
seal.env[pulseCookie] = innerDst
|
seal.env[pulseCookie] = innerDst
|
||||||
var payload *[]byte
|
var payload *[]byte
|
||||||
seal.container.PlaceP(innerDst, &payload)
|
seal.container.PlaceP(innerDst, &payload)
|
||||||
@ -531,15 +531,15 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
|||||||
seal.container.Env = make([]string, 0, len(seal.env))
|
seal.container.Env = make([]string, 0, len(seal.env))
|
||||||
for k, v := range seal.env {
|
for k, v := range seal.env {
|
||||||
if strings.IndexByte(k, '=') != -1 {
|
if strings.IndexByte(k, '=') != -1 {
|
||||||
return fmsg.WrapError(syscall.EINVAL,
|
return hlog.WrapErr(syscall.EINVAL,
|
||||||
fmt.Sprintf("invalid environment variable %s", k))
|
fmt.Sprintf("invalid environment variable %s", k))
|
||||||
}
|
}
|
||||||
seal.container.Env = append(seal.container.Env, k+"="+v)
|
seal.container.Env = append(seal.container.Env, k+"="+v)
|
||||||
}
|
}
|
||||||
slices.Sort(seal.container.Env)
|
slices.Sort(seal.container.Env)
|
||||||
|
|
||||||
if fmsg.Load() {
|
if hlog.Load() {
|
||||||
fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, argv: %s, ops: %d",
|
hlog.Verbosef("created application seal for uid %s (%s) groups: %v, argv: %s, ops: %d",
|
||||||
seal.user.uid, seal.user.username, config.Groups, seal.container.Args, len(*seal.container.Ops))
|
seal.user.uid, seal.user.username, config.Groups, seal.container.Args, len(*seal.container.Ops))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,7 +557,7 @@ func discoverPulseCookie(sys sys.State) (string, error) {
|
|||||||
p = path.Join(p, ".pulse-cookie")
|
p = path.Join(p, ".pulse-cookie")
|
||||||
if s, err := sys.Stat(p); err != nil {
|
if s, err := sys.Stat(p); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return p, fmsg.WrapErrorSuffix(err,
|
return p, hlog.WrapErrSuffix(err,
|
||||||
fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
|
fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
|
||||||
}
|
}
|
||||||
// not found, try next method
|
// not found, try next method
|
||||||
@ -571,7 +571,7 @@ func discoverPulseCookie(sys sys.State) (string, error) {
|
|||||||
p = path.Join(p, "pulse", "cookie")
|
p = path.Join(p, "pulse", "cookie")
|
||||||
if s, err := sys.Stat(p); err != nil {
|
if s, err := sys.Stat(p); err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return p, fmsg.WrapErrorSuffix(err,
|
return p, hlog.WrapErrSuffix(err,
|
||||||
fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
|
fmt.Sprintf("cannot access PulseAudio cookie %q:", p))
|
||||||
}
|
}
|
||||||
// not found, try next method
|
// not found, try next method
|
||||||
@ -580,7 +580,7 @@ func discoverPulseCookie(sys sys.State) (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmsg.WrapError(ErrPulseCookie,
|
return "", hlog.WrapErr(ErrPulseCookie,
|
||||||
fmt.Sprintf("cannot locate PulseAudio cookie (tried $%s, $%s/pulse/cookie, $%s/.pulse-cookie)",
|
fmt.Sprintf("cannot locate PulseAudio cookie (tried $%s, $%s/pulse/cookie, $%s/.pulse-cookie)",
|
||||||
pulseCookie, xdgConfigHome, home))
|
pulseCookie, xdgConfigHome, home))
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,10 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -23,10 +23,10 @@ import (
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
static pid_t f_shim_param_ppid = -1;
|
static pid_t hakurei_shim_param_ppid = -1;
|
||||||
|
|
||||||
// this cannot unblock fmsg since Go code is not async-signal-safe
|
// this cannot unblock hlog since Go code is not async-signal-safe
|
||||||
static void f_shim_sigaction(int sig, siginfo_t *si, void *ucontext) {
|
static void hakurei_shim_sigaction(int sig, siginfo_t *si, void *ucontext) {
|
||||||
if (sig != SIGCONT || si == NULL) {
|
if (sig != SIGCONT || si == NULL) {
|
||||||
// unreachable
|
// unreachable
|
||||||
fprintf(stderr, "sigaction: sa_sigaction got invalid siginfo\n");
|
fprintf(stderr, "sigaction: sa_sigaction got invalid siginfo\n");
|
||||||
@ -34,17 +34,17 @@ static void f_shim_sigaction(int sig, siginfo_t *si, void *ucontext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// monitor requests shim exit
|
// monitor requests shim exit
|
||||||
if (si->si_pid == f_shim_param_ppid)
|
if (si->si_pid == hakurei_shim_param_ppid)
|
||||||
exit(254);
|
exit(254);
|
||||||
|
|
||||||
fprintf(stderr, "sigaction: got SIGCONT from process %d\n", si->si_pid);
|
fprintf(stderr, "sigaction: got SIGCONT from process %d\n", si->si_pid);
|
||||||
|
|
||||||
// shim orphaned before monitor delivers a signal
|
// shim orphaned before monitor delivers a signal
|
||||||
if (getppid() != f_shim_param_ppid)
|
if (getppid() != hakurei_shim_param_ppid)
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void f_shim_setup_cont_signal(pid_t ppid) {
|
void hakurei_shim_setup_cont_signal(pid_t ppid) {
|
||||||
struct sigaction new_action = {0}, old_action = {0};
|
struct sigaction new_action = {0}, old_action = {0};
|
||||||
if (sigaction(SIGCONT, NULL, &old_action) != 0)
|
if (sigaction(SIGCONT, NULL, &old_action) != 0)
|
||||||
return;
|
return;
|
||||||
@ -53,7 +53,7 @@ void f_shim_setup_cont_signal(pid_t ppid) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_action.sa_sigaction = f_shim_sigaction;
|
new_action.sa_sigaction = hakurei_shim_sigaction;
|
||||||
if (sigemptyset(&new_action.sa_mask) != 0)
|
if (sigemptyset(&new_action.sa_mask) != 0)
|
||||||
return;
|
return;
|
||||||
new_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
new_action.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
||||||
@ -62,12 +62,12 @@ void f_shim_setup_cont_signal(pid_t ppid) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
f_shim_param_ppid = ppid;
|
hakurei_shim_param_ppid = ppid;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
const shimEnv = "FORTIFY_SHIM"
|
const shimEnv = "HAKUREI_SHIM"
|
||||||
|
|
||||||
type shimParams struct {
|
type shimParams struct {
|
||||||
// monitor pid, checked against ppid in signal handler
|
// monitor pid, checked against ppid in signal handler
|
||||||
@ -84,7 +84,7 @@ type shimParams struct {
|
|||||||
|
|
||||||
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
|
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
|
||||||
func ShimMain() {
|
func ShimMain() {
|
||||||
fmsg.Prepare("shim")
|
hlog.Prepare("shim")
|
||||||
|
|
||||||
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
|
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
|
||||||
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
|
log.Fatalf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||||
@ -99,7 +99,7 @@ func ShimMain() {
|
|||||||
log.Fatal("invalid config descriptor")
|
log.Fatal("invalid config descriptor")
|
||||||
}
|
}
|
||||||
if errors.Is(err, sandbox.ErrNotSet) {
|
if errors.Is(err, sandbox.ErrNotSet) {
|
||||||
log.Fatal("FORTIFY_SHIM not set")
|
log.Fatal("HAKUREI_SHIM not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Fatalf("cannot receive shim setup params: %v", err)
|
log.Fatalf("cannot receive shim setup params: %v", err)
|
||||||
@ -108,7 +108,7 @@ func ShimMain() {
|
|||||||
closeSetup = f
|
closeSetup = f
|
||||||
|
|
||||||
// the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
|
// the Go runtime does not expose siginfo_t so SIGCONT is handled in C to check si_pid
|
||||||
if _, err = C.f_shim_setup_cont_signal(C.pid_t(params.Monitor)); err != nil {
|
if _, err = C.hakurei_shim_setup_cont_signal(C.pid_t(params.Monitor)); err != nil {
|
||||||
log.Fatalf("cannot install SIGCONT handler: %v", err)
|
log.Fatalf("cannot install SIGCONT handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,11 +156,11 @@ func ShimMain() {
|
|||||||
container.WaitDelay = 2 * time.Second
|
container.WaitDelay = 2 * time.Second
|
||||||
|
|
||||||
if err := container.Start(); err != nil {
|
if err := container.Start(); err != nil {
|
||||||
fmsg.PrintBaseError(err, "cannot start container:")
|
hlog.PrintBaseError(err, "cannot start container:")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
if err := container.Serve(); err != nil {
|
if err := container.Serve(); err != nil {
|
||||||
fmsg.PrintBaseError(err, "cannot configure container:")
|
hlog.PrintBaseError(err, "cannot configure container:")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := seccomp.Load(seccomp.PresetCommon); err != nil {
|
if err := seccomp.Load(seccomp.PresetCommon); err != nil {
|
||||||
|
@ -3,7 +3,7 @@ package setuid
|
|||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
. "git.gensokyo.uk/security/fortify/internal/app"
|
. "git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }
|
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }
|
||||||
|
@ -3,7 +3,7 @@ package internal
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Exit(code int) { fmsg.BeforeExit(); os.Exit(code) }
|
func Exit(code int) { hlog.BeforeExit(); os.Exit(code) }
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package fmsg
|
package hlog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -12,13 +12,8 @@ type baseError struct {
|
|||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *baseError) Error() string {
|
func (e *baseError) Error() string { return e.Err.Error() }
|
||||||
return e.Err.Error()
|
func (e *baseError) Unwrap() error { return e.Err }
|
||||||
}
|
|
||||||
|
|
||||||
func (e *baseError) Unwrap() error {
|
|
||||||
return e.Err
|
|
||||||
}
|
|
||||||
|
|
||||||
// BaseError implements an error container with a user-facing message
|
// BaseError implements an error container with a user-facing message
|
||||||
type BaseError struct {
|
type BaseError struct {
|
||||||
@ -27,35 +22,33 @@ type BaseError struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Message returns a user-facing error message
|
// Message returns a user-facing error message
|
||||||
func (e *BaseError) Message() string {
|
func (e *BaseError) Message() string { return e.message }
|
||||||
return e.message
|
|
||||||
}
|
|
||||||
|
|
||||||
// WrapError wraps an error with a corresponding message.
|
// WrapErr wraps an error with a corresponding message.
|
||||||
func WrapError(err error, a ...any) error {
|
func WrapErr(err error, a ...any) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return wrapError(err, fmt.Sprintln(a...))
|
return wrapErr(err, fmt.Sprintln(a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WrapErrorSuffix wraps an error with a corresponding message with err at the end of the message.
|
// WrapErrSuffix wraps an error with a corresponding message with err at the end of the message.
|
||||||
func WrapErrorSuffix(err error, a ...any) error {
|
func WrapErrSuffix(err error, a ...any) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return wrapError(err, fmt.Sprintln(append(a, err)...))
|
return wrapErr(err, fmt.Sprintln(append(a, err)...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// WrapErrorFunc wraps an error with a corresponding message returned by f.
|
// WrapErrFunc wraps an error with a corresponding message returned by f.
|
||||||
func WrapErrorFunc(err error, f func(err error) string) error {
|
func WrapErrFunc(err error, f func(err error) string) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return wrapError(err, f(err))
|
return wrapErr(err, f(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapError(err error, message string) *BaseError {
|
func wrapErr(err error, message string) *BaseError {
|
||||||
return &BaseError{message, baseError{err}}
|
return &BaseError{message, baseError{err}}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
// Package fmsg provides various functions for output messages.
|
// Package hlog provides various functions for output messages.
|
||||||
package fmsg
|
package hlog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
@ -1,11 +1,11 @@
|
|||||||
package fmsg
|
package hlog
|
||||||
|
|
||||||
type Output struct{}
|
type Output struct{}
|
||||||
|
|
||||||
func (Output) IsVerbose() bool { return Load() }
|
func (Output) IsVerbose() bool { return Load() }
|
||||||
func (Output) Verbose(v ...any) { Verbose(v...) }
|
func (Output) Verbose(v ...any) { Verbose(v...) }
|
||||||
func (Output) Verbosef(format string, v ...any) { Verbosef(format, v...) }
|
func (Output) Verbosef(format string, v ...any) { Verbosef(format, v...) }
|
||||||
func (Output) WrapErr(err error, a ...any) error { return WrapError(err, a...) }
|
func (Output) WrapErr(err error, a ...any) error { return WrapErr(err, a...) }
|
||||||
func (Output) PrintBaseErr(err error, fallback string) { PrintBaseError(err, fallback) }
|
func (Output) PrintBaseErr(err error, fallback string) { PrintBaseError(err, fallback) }
|
||||||
func (Output) Suspend() { Suspend() }
|
func (Output) Suspend() { Suspend() }
|
||||||
func (Output) Resume() bool { return Resume() }
|
func (Output) Resume() bool { return Resume() }
|
@ -1,4 +1,4 @@
|
|||||||
package fmsg
|
package hlog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
@ -1,17 +1,17 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func InstallFmsg(verbose bool) {
|
func InstallFmsg(verbose bool) {
|
||||||
fmsg.Store(verbose)
|
hlog.Store(verbose)
|
||||||
sandbox.SetOutput(fmsg.Output{})
|
sandbox.SetOutput(hlog.Output{})
|
||||||
system.SetOutput(fmsg.Output{})
|
system.SetOutput(hlog.Output{})
|
||||||
if verbose {
|
if verbose {
|
||||||
seccomp.SetOutput(fmsg.Verbose)
|
seccomp.SetOutput(hlog.Verbose)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,19 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fsu = compPoison
|
hsu = compPoison
|
||||||
)
|
)
|
||||||
|
|
||||||
func MustFsuPath() string {
|
func MustHsuPath() string {
|
||||||
if name, ok := checkPath(fsu); ok {
|
if name, ok := checkPath(hsu); ok {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
fmsg.BeforeExit()
|
hlog.BeforeExit()
|
||||||
log.Fatal("invalid fsu path, this program is compiled incorrectly")
|
log.Fatal("invalid hsu path, this program is compiled incorrectly")
|
||||||
return compPoison
|
return compPoison
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fine-grained locking and access
|
// fine-grained locking and access
|
||||||
@ -86,17 +86,17 @@ func (s *multiStore) List() ([]int, error) {
|
|||||||
for _, e := range entries {
|
for _, e := range entries {
|
||||||
// skip non-directories
|
// skip non-directories
|
||||||
if !e.IsDir() {
|
if !e.IsDir() {
|
||||||
fmsg.Verbosef("skipped non-directory entry %q", e.Name())
|
hlog.Verbosef("skipped non-directory entry %q", e.Name())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip non-numerical names
|
// skip non-numerical names
|
||||||
if v, err := strconv.Atoi(e.Name()); err != nil {
|
if v, err := strconv.Atoi(e.Name()); err != nil {
|
||||||
fmsg.Verbosef("skipped non-aid entry %q", e.Name())
|
hlog.Verbosef("skipped non-aid entry %q", e.Name())
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
if v < 0 || v > 9999 {
|
if v < 0 || v > 9999 {
|
||||||
fmsg.Verbosef("skipped out of bounds entry %q", e.Name())
|
hlog.Verbosef("skipped out of bounds entry %q", e.Name())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ func (b *multiBackend) load(decode bool) (Entries, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// state file consists of an eight byte header, followed by concatenated gobs
|
// state file consists of an eight byte header, followed by concatenated gobs
|
||||||
// of [fst.Config] and [State], if [State.Config] is not nil or offset < 0,
|
// of [hst.Config] and [State], if [State.Config] is not nil or offset < 0,
|
||||||
// the first gob is skipped
|
// the first gob is skipped
|
||||||
func (b *multiBackend) decodeState(r io.ReadSeeker, state *State) error {
|
func (b *multiBackend) decodeState(r io.ReadSeeker, state *State) error {
|
||||||
offset := make([]byte, 8)
|
offset := make([]byte, 8)
|
||||||
@ -269,7 +269,7 @@ func (b *multiBackend) decodeState(r io.ReadSeeker, state *State) error {
|
|||||||
return ErrNoConfig
|
return ErrNoConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
state.Config = new(fst.Config)
|
state.Config = new(hst.Config)
|
||||||
if _, err := r.Seek(8, io.SeekStart); err != nil {
|
if _, err := r.Seek(8, io.SeekStart); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ package state_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal/state"
|
"git.gensokyo.uk/security/hakurei/internal/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMulti(t *testing.T) {
|
func TestMulti(t *testing.T) {
|
||||||
|
@ -5,8 +5,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNoConfig = errors.New("state does not contain config")
|
var ErrNoConfig = errors.New("state does not contain config")
|
||||||
@ -35,14 +35,14 @@ type Cursor interface {
|
|||||||
Len() (int, error)
|
Len() (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// State is a fortify process's state
|
// State is an instance state
|
||||||
type State struct {
|
type State struct {
|
||||||
// fortify instance id
|
// hakurei instance id
|
||||||
ID app.ID `json:"instance"`
|
ID app.ID `json:"instance"`
|
||||||
// child process PID value
|
// child process PID value
|
||||||
PID int `json:"pid"`
|
PID int `json:"pid"`
|
||||||
// sealed app configuration
|
// sealed app configuration
|
||||||
Config *fst.Config `json:"config"`
|
Config *hst.Config `json:"config"`
|
||||||
|
|
||||||
// process start time
|
// process start time
|
||||||
Time time.Time `json:"time"`
|
Time time.Time `json:"time"`
|
||||||
|
@ -10,9 +10,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/state"
|
"git.gensokyo.uk/security/hakurei/internal/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testStore(t *testing.T, s state.Store) {
|
func testStore(t *testing.T, s state.Store) {
|
||||||
@ -63,7 +63,7 @@ func testStore(t *testing.T, s state.Store) {
|
|||||||
&tc[i].state.ID)
|
&tc[i].state.ID)
|
||||||
} else {
|
} else {
|
||||||
got.Time = tc[i].state.Time
|
got.Time = tc[i].state.Time
|
||||||
tc[i].state.Config = fst.Template()
|
tc[i].state.Config = hst.Template()
|
||||||
if !reflect.DeepEqual(got, &tc[i].state) {
|
if !reflect.DeepEqual(got, &tc[i].state) {
|
||||||
t.Fatalf("Load: entry %s got %#v, want %#v",
|
t.Fatalf("Load: entry %s got %#v, want %#v",
|
||||||
&tc[i].state.ID, got, &tc[i].state)
|
&tc[i].state.ID, got, &tc[i].state)
|
||||||
@ -137,7 +137,7 @@ func makeState(t *testing.T, s *state.State, ct io.Writer) {
|
|||||||
if err := app.NewAppID(&s.ID); err != nil {
|
if err := app.NewAppID(&s.ID); err != nil {
|
||||||
t.Fatalf("cannot create dummy state: %v", err)
|
t.Fatalf("cannot create dummy state: %v", err)
|
||||||
}
|
}
|
||||||
if err := gob.NewEncoder(ct).Encode(fst.Template()); err != nil {
|
if err := gob.NewEncoder(ct).Encode(hst.Template()); err != nil {
|
||||||
t.Fatalf("cannot encode dummy config: %v", err)
|
t.Fatalf("cannot encode dummy config: %v", err)
|
||||||
}
|
}
|
||||||
s.PID = rand.Int()
|
s.PID = rand.Int()
|
||||||
|
@ -6,8 +6,8 @@ import (
|
|||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
// State provides safe interaction with operating system state.
|
// State provides safe interaction with operating system state.
|
||||||
@ -42,25 +42,25 @@ type State interface {
|
|||||||
|
|
||||||
// Paths returns a populated [Paths] struct.
|
// Paths returns a populated [Paths] struct.
|
||||||
Paths() app.Paths
|
Paths() app.Paths
|
||||||
// Uid invokes fsu and returns target uid.
|
// Uid invokes hsu and returns target uid.
|
||||||
// Any errors returned by Uid is already wrapped [fmsg.BaseError].
|
// Any errors returned by Uid is already wrapped [fmsg.BaseError].
|
||||||
Uid(aid int) (int, error)
|
Uid(aid int) (int, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CopyPaths is a generic implementation of [fst.Paths].
|
// CopyPaths is a generic implementation of [hst.Paths].
|
||||||
func CopyPaths(os State, v *app.Paths) {
|
func CopyPaths(os State, v *app.Paths) {
|
||||||
v.SharePath = path.Join(os.TempDir(), "fortify."+strconv.Itoa(os.Getuid()))
|
v.SharePath = path.Join(os.TempDir(), "hakurei."+strconv.Itoa(os.Getuid()))
|
||||||
|
|
||||||
fmsg.Verbosef("process share directory at %q", v.SharePath)
|
hlog.Verbosef("process share directory at %q", v.SharePath)
|
||||||
|
|
||||||
if r, ok := os.LookupEnv(xdgRuntimeDir); !ok || r == "" || !path.IsAbs(r) {
|
if r, ok := os.LookupEnv(xdgRuntimeDir); !ok || r == "" || !path.IsAbs(r) {
|
||||||
// fall back to path in share since fortify has no hard XDG dependency
|
// fall back to path in share since hakurei has no hard XDG dependency
|
||||||
v.RunDirPath = path.Join(v.SharePath, "run")
|
v.RunDirPath = path.Join(v.SharePath, "run")
|
||||||
v.RuntimePath = path.Join(v.RunDirPath, "compat")
|
v.RuntimePath = path.Join(v.RunDirPath, "compat")
|
||||||
} else {
|
} else {
|
||||||
v.RuntimePath = r
|
v.RuntimePath = r
|
||||||
v.RunDirPath = path.Join(v.RuntimePath, "fortify")
|
v.RunDirPath = path.Join(v.RuntimePath, "hakurei")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmsg.Verbosef("runtime directory at %q", v.RunDirPath)
|
hlog.Verbosef("runtime directory at %q", v.RunDirPath)
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Std implements System using the standard library.
|
// Std implements System using the standard library.
|
||||||
@ -43,8 +43,8 @@ func (s *Std) Stat(name string) (fs.FileInfo, error) { return os.Stat(nam
|
|||||||
func (s *Std) Open(name string) (fs.File, error) { return os.Open(name) }
|
func (s *Std) Open(name string) (fs.File, error) { return os.Open(name) }
|
||||||
func (s *Std) EvalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }
|
func (s *Std) EvalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) }
|
||||||
func (s *Std) Exit(code int) { internal.Exit(code) }
|
func (s *Std) Exit(code int) { internal.Exit(code) }
|
||||||
func (s *Std) Println(v ...any) { fmsg.Verbose(v...) }
|
func (s *Std) Println(v ...any) { hlog.Verbose(v...) }
|
||||||
func (s *Std) Printf(format string, v ...any) { fmsg.Verbosef(format, v...) }
|
func (s *Std) Printf(format string, v ...any) { hlog.Verbosef(format, v...) }
|
||||||
|
|
||||||
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
|
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
|
||||||
|
|
||||||
@ -80,12 +80,12 @@ func (s *Std) Uid(aid int) (int, error) {
|
|||||||
defer func() { s.uidCopy[aid] = u }()
|
defer func() { s.uidCopy[aid] = u }()
|
||||||
|
|
||||||
u.uid = -1
|
u.uid = -1
|
||||||
fsuPath := internal.MustFsuPath()
|
hsuPath := internal.MustHsuPath()
|
||||||
|
|
||||||
cmd := exec.Command(fsuPath)
|
cmd := exec.Command(hsuPath)
|
||||||
cmd.Path = fsuPath
|
cmd.Path = hsuPath
|
||||||
cmd.Stderr = os.Stderr // pass through fatal messages
|
cmd.Stderr = os.Stderr // pass through fatal messages
|
||||||
cmd.Env = []string{"FORTIFY_APP_ID=" + strconv.Itoa(aid)}
|
cmd.Env = []string{"HAKUREI_APP_ID=" + strconv.Itoa(aid)}
|
||||||
cmd.Dir = "/"
|
cmd.Dir = "/"
|
||||||
var (
|
var (
|
||||||
p []byte
|
p []byte
|
||||||
@ -95,12 +95,12 @@ func (s *Std) Uid(aid int) (int, error) {
|
|||||||
if p, u.err = cmd.Output(); u.err == nil {
|
if p, u.err = cmd.Output(); u.err == nil {
|
||||||
u.uid, u.err = strconv.Atoi(string(p))
|
u.uid, u.err = strconv.Atoi(string(p))
|
||||||
if u.err != nil {
|
if u.err != nil {
|
||||||
u.err = fmsg.WrapErrorSuffix(u.err, "cannot parse uid from fsu:")
|
u.err = hlog.WrapErrSuffix(u.err, "cannot parse uid from hsu:")
|
||||||
}
|
}
|
||||||
} else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
|
} else if errors.As(u.err, &exitError) && exitError != nil && exitError.ExitCode() == 1 {
|
||||||
u.err = fmsg.WrapError(syscall.EACCES, "") // fsu prints to stderr in this case
|
u.err = hlog.WrapErr(syscall.EACCES, "") // hsu prints to stderr in this case
|
||||||
} else if os.IsNotExist(u.err) {
|
} else if os.IsNotExist(u.err) {
|
||||||
u.err = fmsg.WrapError(os.ErrNotExist, fmt.Sprintf("the setuid helper is missing: %s", fsuPath))
|
u.err = hlog.WrapErr(os.ErrNotExist, fmt.Sprintf("the setuid helper is missing: %s", hsuPath))
|
||||||
}
|
}
|
||||||
return u.uid, u.err
|
return u.uid, u.err
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
const lddTimeout = 2 * time.Second
|
const lddTimeout = 2 * time.Second
|
||||||
@ -28,7 +28,7 @@ func ExecFilter(ctx context.Context,
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
container := sandbox.New(c, "ldd", p)
|
container := sandbox.New(c, "ldd", p)
|
||||||
container.CommandContext = commandContext
|
container.CommandContext = commandContext
|
||||||
container.Hostname = "fortify-ldd"
|
container.Hostname = "hakurei-ldd"
|
||||||
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
|
stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
|
||||||
container.Stdout = stdout
|
container.Stdout = stdout
|
||||||
container.Stderr = stderr
|
container.Stderr = stderr
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/ldd"
|
"git.gensokyo.uk/security/hakurei/ldd"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseError(t *testing.T) {
|
func TestParseError(t *testing.T) {
|
||||||
|
59
main.go
59
main.go
@ -15,17 +15,17 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/command"
|
"git.gensokyo.uk/security/hakurei/command"
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app/instance"
|
"git.gensokyo.uk/security/hakurei/internal/app/instance"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/internal/state"
|
"git.gensokyo.uk/security/hakurei/internal/state"
|
||||||
"git.gensokyo.uk/security/fortify/internal/sys"
|
"git.gensokyo.uk/security/hakurei/internal/sys"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/system"
|
"git.gensokyo.uk/security/hakurei/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -35,13 +35,13 @@ var (
|
|||||||
license string
|
license string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() { fmsg.Prepare("fortify") }
|
func init() { hlog.Prepare("hakurei") }
|
||||||
|
|
||||||
var std sys.State = new(sys.Std)
|
var std sys.State = new(sys.Std)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// early init path, skips root check and duplicate PR_SET_DUMPABLE
|
// early init path, skips root check and duplicate PR_SET_DUMPABLE
|
||||||
sandbox.TryArgv0(fmsg.Output{}, fmsg.Prepare, internal.InstallFmsg)
|
sandbox.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallFmsg)
|
||||||
|
|
||||||
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
|
if err := sandbox.SetDumpable(sandbox.SUID_DUMP_DISABLE); err != nil {
|
||||||
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
|
log.Printf("cannot set SUID_DUMP_DISABLE: %s", err)
|
||||||
@ -53,9 +53,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildCommand(os.Stderr).MustParse(os.Args[1:], func(err error) {
|
buildCommand(os.Stderr).MustParse(os.Args[1:], func(err error) {
|
||||||
fmsg.Verbosef("command returned %v", err)
|
hlog.Verbosef("command returned %v", err)
|
||||||
if errors.Is(err, errSuccess) {
|
if errors.Is(err, errSuccess) {
|
||||||
fmsg.BeforeExit()
|
hlog.BeforeExit()
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -67,16 +67,13 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
flagVerbose bool
|
flagVerbose bool
|
||||||
flagJSON bool
|
flagJSON bool
|
||||||
)
|
)
|
||||||
c := command.New(out, log.Printf, "fortify", func([]string) error {
|
c := command.New(out, log.Printf, "hakurei", func([]string) error { internal.InstallFmsg(flagVerbose); return nil }).
|
||||||
internal.InstallFmsg(flagVerbose)
|
Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
|
||||||
return nil
|
|
||||||
}).
|
|
||||||
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
|
|
||||||
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
|
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
|
||||||
|
|
||||||
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
|
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
|
||||||
|
|
||||||
c.Command("app", "Launch app defined by the specified config file", func(args []string) error {
|
c.Command("app", "Load app from configuration file", func(args []string) error {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
log.Fatal("app requires at least 1 argument")
|
log.Fatal("app requires at least 1 argument")
|
||||||
}
|
}
|
||||||
@ -107,7 +104,7 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
|
|
||||||
c.NewCommand("run", "Configure and start a permissive default sandbox", func(args []string) error {
|
c.NewCommand("run", "Configure and start a permissive default sandbox", func(args []string) error {
|
||||||
// initialise config from flags
|
// initialise config from flags
|
||||||
config := &fst.Config{
|
config := &hst.Config{
|
||||||
ID: fid,
|
ID: fid,
|
||||||
Args: args,
|
Args: args,
|
||||||
}
|
}
|
||||||
@ -123,19 +120,19 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
passwdFunc = func() {
|
passwdFunc = func() {
|
||||||
var us string
|
var us string
|
||||||
if uid, err := std.Uid(aid); err != nil {
|
if uid, err := std.Uid(aid); err != nil {
|
||||||
fmsg.PrintBaseError(err, "cannot obtain uid from fsu:")
|
hlog.PrintBaseError(err, "cannot obtain uid from setuid wrapper:")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
us = strconv.Itoa(uid)
|
us = strconv.Itoa(uid)
|
||||||
}
|
}
|
||||||
|
|
||||||
if u, err := user.LookupId(us); err != nil {
|
if u, err := user.LookupId(us); err != nil {
|
||||||
fmsg.Verbosef("cannot look up uid %s", us)
|
hlog.Verbosef("cannot look up uid %s", us)
|
||||||
passwd = &user.User{
|
passwd = &user.User{
|
||||||
Uid: us,
|
Uid: us,
|
||||||
Gid: us,
|
Gid: us,
|
||||||
Username: "chronos",
|
Username: "chronos",
|
||||||
Name: "Fortify",
|
Name: "Hakurei Permissive Default",
|
||||||
HomeDir: "/var/empty",
|
HomeDir: "/var/empty",
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -233,7 +230,7 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var showFlagShort bool
|
var showFlagShort bool
|
||||||
c.NewCommand("show", "Show the contents of an app configuration", func(args []string) error {
|
c.NewCommand("show", "Show live or local app configuration", func(args []string) error {
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0: // system
|
case 0: // system
|
||||||
printShowSystem(os.Stdout, showFlagShort, flagJSON)
|
printShowSystem(os.Stdout, showFlagShort, flagJSON)
|
||||||
@ -253,12 +250,12 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
}).Flag(&showFlagShort, "short", command.BoolFlag(false), "Omit filesystem information")
|
}).Flag(&showFlagShort, "short", command.BoolFlag(false), "Omit filesystem information")
|
||||||
|
|
||||||
var psFlagShort bool
|
var psFlagShort bool
|
||||||
c.NewCommand("ps", "List active apps and their state", func(args []string) error {
|
c.NewCommand("ps", "List active instances", func(args []string) error {
|
||||||
printPs(os.Stdout, time.Now().UTC(), state.NewMulti(std.Paths().RunDirPath), psFlagShort, flagJSON)
|
printPs(os.Stdout, time.Now().UTC(), state.NewMulti(std.Paths().RunDirPath), psFlagShort, flagJSON)
|
||||||
return errSuccess
|
return errSuccess
|
||||||
}).Flag(&psFlagShort, "short", command.BoolFlag(false), "Print instance id")
|
}).Flag(&psFlagShort, "short", command.BoolFlag(false), "Print instance id")
|
||||||
|
|
||||||
c.Command("version", "Show fortify version", func(args []string) error {
|
c.Command("version", "Display version information", func(args []string) error {
|
||||||
fmt.Println(internal.Version())
|
fmt.Println(internal.Version())
|
||||||
return errSuccess
|
return errSuccess
|
||||||
})
|
})
|
||||||
@ -269,7 +266,7 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
})
|
})
|
||||||
|
|
||||||
c.Command("template", "Produce a config template", func(args []string) error {
|
c.Command("template", "Produce a config template", func(args []string) error {
|
||||||
printJSON(os.Stdout, false, fst.Template())
|
printJSON(os.Stdout, false, hst.Template())
|
||||||
return errSuccess
|
return errSuccess
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -281,7 +278,7 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func runApp(config *fst.Config) {
|
func runApp(config *hst.Config) {
|
||||||
ctx, stop := signal.NotifyContext(context.Background(),
|
ctx, stop := signal.NotifyContext(context.Background(),
|
||||||
syscall.SIGINT, syscall.SIGTERM)
|
syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer stop() // unreachable
|
defer stop() // unreachable
|
||||||
@ -289,7 +286,7 @@ func runApp(config *fst.Config) {
|
|||||||
|
|
||||||
rs := new(app.RunState)
|
rs := new(app.RunState)
|
||||||
if sa, err := a.Seal(config); err != nil {
|
if sa, err := a.Seal(config); err != nil {
|
||||||
fmsg.PrintBaseError(err, "cannot seal app:")
|
hlog.PrintBaseError(err, "cannot seal app:")
|
||||||
internal.Exit(1)
|
internal.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
internal.Exit(instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs)))
|
internal.Exit(instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs)))
|
||||||
|
14
main_test.go
14
main_test.go
@ -6,7 +6,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/command"
|
"git.gensokyo.uk/security/hakurei/command"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestHelp(t *testing.T) {
|
func TestHelp(t *testing.T) {
|
||||||
@ -17,14 +17,14 @@ func TestHelp(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
"main", []string{}, `
|
"main", []string{}, `
|
||||||
Usage: fortify [-h | --help] [-v] [--json] COMMAND [OPTIONS]
|
Usage: hakurei [-h | --help] [-v] [--json] COMMAND [OPTIONS]
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
app Launch app defined by the specified config file
|
app Load app from configuration file
|
||||||
run Configure and start a permissive default sandbox
|
run Configure and start a permissive default sandbox
|
||||||
show Show the contents of an app configuration
|
show Show live or local app configuration
|
||||||
ps List active apps and their state
|
ps List active instances
|
||||||
version Show fortify version
|
version Display version information
|
||||||
license Show full license text
|
license Show full license text
|
||||||
template Produce a config template
|
template Produce a config template
|
||||||
help Show this help message
|
help Show this help message
|
||||||
@ -33,7 +33,7 @@ Commands:
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"run", []string{"run", "-h"}, `
|
"run", []string{"run", "-h"}, `
|
||||||
Usage: fortify run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--wayland] [-X] [--dbus] [--pulse] COMMAND [OPTIONS]
|
Usage: hakurei run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--wayland] [-X] [--dbus] [--pulse] COMMAND [OPTIONS]
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-X Enable direct connection to X11
|
-X Enable direct connection to X11
|
||||||
|
15
nixos.nix
15
nixos.nix
@ -18,7 +18,7 @@ let
|
|||||||
optionals
|
optionals
|
||||||
;
|
;
|
||||||
|
|
||||||
cfg = config.environment.fortify;
|
cfg = config.environment.hakurei;
|
||||||
|
|
||||||
getsubuid = fid: aid: 1000000 + fid * 10000 + aid;
|
getsubuid = fid: aid: 1000000 + fid * 10000 + aid;
|
||||||
getsubname = fid: aid: "u${toString fid}_a${toString aid}";
|
getsubname = fid: aid: "u${toString fid}_a${toString aid}";
|
||||||
@ -45,20 +45,21 @@ in
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
assertion = (lists.length conflictingApps) == 0;
|
assertion = (lists.length conflictingApps) == 0;
|
||||||
message = "the following fortify apps have conflicting identities: " + (builtins.concatStringsSep ", " conflictingApps);
|
message = "the following hakurei apps have conflicting identities: " + (builtins.concatStringsSep ", " conflictingApps);
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
|
|
||||||
security.wrappers.fsu = {
|
security.wrappers.hsu = {
|
||||||
source = "${cfg.fsuPackage}/bin/fsu";
|
|
||||||
|
source = "${cfg.hsuPackage}/bin/hsu";
|
||||||
setuid = true;
|
setuid = true;
|
||||||
owner = "root";
|
owner = "root";
|
||||||
setgid = true;
|
setgid = true;
|
||||||
group = "root";
|
group = "root";
|
||||||
};
|
};
|
||||||
|
|
||||||
environment.etc.fsurc = {
|
environment.etc.hsurc = {
|
||||||
mode = "0400";
|
mode = "0400";
|
||||||
text = foldlAttrs (
|
text = foldlAttrs (
|
||||||
acc: username: fid:
|
acc: username: fid:
|
||||||
@ -200,7 +201,7 @@ in
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
pkgs.writeShellScriptBin app.name ''
|
pkgs.writeShellScriptBin app.name ''
|
||||||
exec fortify${if app.verbose then " -v" else ""} app ${pkgs.writeText "fortify-${app.name}.json" (builtins.toJSON conf)} $@
|
exec hakurei${if app.verbose then " -v" else ""} app ${pkgs.writeText "hakurei-app-${app.name}.json" (builtins.toJSON conf)} $@
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
@ -281,7 +282,7 @@ in
|
|||||||
getuser = fid: aid: {
|
getuser = fid: aid: {
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
createHome = true;
|
createHome = true;
|
||||||
description = "Fortify subordinate user ${toString aid} (u${toString fid})";
|
description = "Hakurei subordinate user ${toString aid} (u${toString fid})";
|
||||||
group = getsubname fid aid;
|
group = getsubname fid aid;
|
||||||
home = getsubhome fid aid;
|
home = getsubhome fid aid;
|
||||||
uid = getsubuid fid aid;
|
uid = getsubuid fid aid;
|
||||||
|
112
options.md
112
options.md
@ -1,8 +1,8 @@
|
|||||||
## environment\.fortify\.enable
|
## environment\.hakurei\.enable
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Whether to enable fortify\.
|
Whether to enable hakurei\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -21,11 +21,11 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.package
|
## environment\.hakurei\.package
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The fortify package to use\.
|
The hakurei package to use\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -35,13 +35,13 @@ package
|
|||||||
|
|
||||||
|
|
||||||
*Default:*
|
*Default:*
|
||||||
` <derivation fortify-static-x86_64-unknown-linux-musl-0.4.1> `
|
` <derivation hakurei-static-x86_64-unknown-linux-musl-0.4.1> `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps
|
## environment\.hakurei\.apps
|
||||||
|
|
||||||
Declaratively configured fortify apps\.
|
Declaratively configured hakurei apps\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ attribute set of (submodule)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.packages
|
## environment\.hakurei\.apps\.\<name>\.packages
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ list of package
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.args
|
## environment\.hakurei\.apps\.\<name>\.args
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ null or (list of string)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.capability\.dbus
|
## environment\.hakurei\.apps\.\<name>\.capability\.dbus
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.capability\.pulse
|
## environment\.hakurei\.apps\.\<name>\.capability\.pulse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.capability\.wayland
|
## environment\.hakurei\.apps\.\<name>\.capability\.wayland
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.capability\.x11
|
## environment\.hakurei\.apps\.\<name>\.capability\.x11
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.command
|
## environment\.hakurei\.apps\.\<name>\.command
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.dbus\.session
|
## environment\.hakurei\.apps\.\<name>\.dbus\.session
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ null or (function that evaluates to a(n) anything)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.dbus\.system
|
## environment\.hakurei\.apps\.\<name>\.dbus\.system
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ null or anything
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.devel
|
## environment\.hakurei\.apps\.\<name>\.devel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.device
|
## environment\.hakurei\.apps\.\<name>\.device
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.env
|
## environment\.hakurei\.apps\.\<name>\.env
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ null or (attribute set of string)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.extraConfig
|
## environment\.hakurei\.apps\.\<name>\.extraConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -304,7 +304,7 @@ anything
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.extraPaths
|
## environment\.hakurei\.apps\.\<name>\.extraPaths
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -322,7 +322,7 @@ list of (submodule)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.dev
|
## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.dev
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -345,7 +345,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.dst
|
## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.dst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -363,7 +363,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.require
|
## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.require
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -386,7 +386,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.src
|
## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -399,7 +399,7 @@ string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.write
|
## environment\.hakurei\.apps\.\<name>\.extraPaths\.\*\.write
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.gpu
|
## environment\.hakurei\.apps\.\<name>\.gpu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -441,7 +441,7 @@ null or boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.groups
|
## environment\.hakurei\.apps\.\<name>\.groups
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -459,7 +459,7 @@ list of string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.identity
|
## environment\.hakurei\.apps\.\<name>\.identity
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -472,7 +472,7 @@ integer between 1 and 9999 (both inclusive)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.insecureWayland
|
## environment\.hakurei\.apps\.\<name>\.insecureWayland
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -495,7 +495,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.mapRealUid
|
## environment\.hakurei\.apps\.\<name>\.mapRealUid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -518,7 +518,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.multiarch
|
## environment\.hakurei\.apps\.\<name>\.multiarch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -541,7 +541,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.name
|
## environment\.hakurei\.apps\.\<name>\.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -554,7 +554,7 @@ string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.net
|
## environment\.hakurei\.apps\.\<name>\.net
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -577,7 +577,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.nix
|
## environment\.hakurei\.apps\.\<name>\.nix
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -600,7 +600,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.path
|
## environment\.hakurei\.apps\.\<name>\.path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -619,7 +619,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.script
|
## environment\.hakurei\.apps\.\<name>\.script
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -637,7 +637,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.share
|
## environment\.hakurei\.apps\.\<name>\.share
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -656,7 +656,7 @@ null or package
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.shareUid
|
## environment\.hakurei\.apps\.\<name>\.shareUid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -679,7 +679,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.tty
|
## environment\.hakurei\.apps\.\<name>\.tty
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -702,7 +702,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.useCommonPaths
|
## environment\.hakurei\.apps\.\<name>\.useCommonPaths
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -725,7 +725,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.userns
|
## environment\.hakurei\.apps\.\<name>\.userns
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -748,7 +748,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\<name>\.verbose
|
## environment\.hakurei\.apps\.\<name>\.verbose
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -771,7 +771,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.commonPaths
|
## environment\.hakurei\.commonPaths
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -789,7 +789,7 @@ list of (submodule)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.commonPaths\.\*\.dev
|
## environment\.hakurei\.commonPaths\.\*\.dev
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -812,7 +812,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.commonPaths\.\*\.dst
|
## environment\.hakurei\.commonPaths\.\*\.dst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -830,7 +830,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.commonPaths\.\*\.require
|
## environment\.hakurei\.commonPaths\.\*\.require
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -853,7 +853,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.commonPaths\.\*\.src
|
## environment\.hakurei\.commonPaths\.\*\.src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -866,7 +866,7 @@ string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.commonPaths\.\*\.write
|
## environment\.hakurei\.commonPaths\.\*\.write
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -889,7 +889,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.extraHomeConfig
|
## environment\.hakurei\.extraHomeConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -902,11 +902,11 @@ anything
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.fsuPackage
|
## environment\.hakurei\.hsuPackage
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The fsu package to use\.
|
The hsu package to use\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -916,11 +916,11 @@ package
|
|||||||
|
|
||||||
|
|
||||||
*Default:*
|
*Default:*
|
||||||
` <derivation fortify-fsu-0.4.1> `
|
` <derivation hakurei-hsu-0.4.1> `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.stateDir
|
## environment\.hakurei\.stateDir
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -933,11 +933,11 @@ string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.users
|
## environment\.hakurei\.users
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Users allowed to spawn fortify apps and their corresponding fortify fid\.
|
Users allowed to spawn hakurei apps and their corresponding hakurei identity\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
18
options.nix
18
options.nix
@ -39,19 +39,19 @@ in
|
|||||||
|
|
||||||
{
|
{
|
||||||
options = {
|
options = {
|
||||||
environment.fortify = {
|
environment.hakurei = {
|
||||||
enable = mkEnableOption "fortify";
|
enable = mkEnableOption "hakurei";
|
||||||
|
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = packages.${pkgs.system}.fortify;
|
default = packages.${pkgs.system}.hakurei;
|
||||||
description = "The fortify package to use.";
|
description = "The hakurei package to use.";
|
||||||
};
|
};
|
||||||
|
|
||||||
fsuPackage = mkOption {
|
hsuPackage = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = packages.${pkgs.system}.fsu;
|
default = packages.${pkgs.system}.hsu;
|
||||||
description = "The fsu package to use.";
|
description = "The hsu package to use.";
|
||||||
};
|
};
|
||||||
|
|
||||||
users = mkOption {
|
users = mkOption {
|
||||||
@ -61,7 +61,7 @@ in
|
|||||||
in
|
in
|
||||||
attrsOf (ints.between 0 99);
|
attrsOf (ints.between 0 99);
|
||||||
description = ''
|
description = ''
|
||||||
Users allowed to spawn fortify apps and their corresponding fortify fid.
|
Users allowed to spawn hakurei apps and their corresponding hakurei identity.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -276,7 +276,7 @@ in
|
|||||||
});
|
});
|
||||||
default = { };
|
default = { };
|
||||||
description = ''
|
description = ''
|
||||||
Declaratively configured fortify apps.
|
Declaratively configured hakurei apps.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
10
package.nix
10
package.nix
@ -30,13 +30,13 @@
|
|||||||
}:
|
}:
|
||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "fortify";
|
pname = "hakurei";
|
||||||
version = "0.4.1";
|
version = "0.4.1";
|
||||||
|
|
||||||
srcFiltered = builtins.path {
|
srcFiltered = builtins.path {
|
||||||
name = "${pname}-src";
|
name = "${pname}-src";
|
||||||
path = lib.cleanSource ./.;
|
path = lib.cleanSource ./.;
|
||||||
filter = path: type: !(type == "regular" && (lib.hasSuffix ".nix" path || lib.hasSuffix ".py" path)) && !(type == "directory" && lib.hasSuffix "/test" path) && !(type == "directory" && lib.hasSuffix "/cmd/fsu" path);
|
filter = path: type: !(type == "regular" && (lib.hasSuffix ".nix" path || lib.hasSuffix ".py" path)) && !(type == "directory" && lib.hasSuffix "/test" path) && !(type == "directory" && lib.hasSuffix "/cmd/hsu" path);
|
||||||
};
|
};
|
||||||
vendorHash = null;
|
vendorHash = null;
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ buildGoModule rec {
|
|||||||
lib.attrsets.foldlAttrs
|
lib.attrsets.foldlAttrs
|
||||||
(
|
(
|
||||||
ldflags: name: value:
|
ldflags: name: value:
|
||||||
ldflags ++ [ "-X git.gensokyo.uk/security/fortify/internal.${name}=${value}" ]
|
ldflags ++ [ "-X git.gensokyo.uk/security/hakurei/internal.${name}=${value}" ]
|
||||||
)
|
)
|
||||||
(
|
(
|
||||||
[ "-s -w" ]
|
[ "-s -w" ]
|
||||||
@ -76,7 +76,7 @@ buildGoModule rec {
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
version = "v${version}";
|
version = "v${version}";
|
||||||
fsu = "/run/wrappers/bin/fsu";
|
hsu = "/run/wrappers/bin/hsu";
|
||||||
};
|
};
|
||||||
|
|
||||||
# nix build environment does not allow acls
|
# nix build environment does not allow acls
|
||||||
@ -113,7 +113,7 @@ buildGoModule rec {
|
|||||||
mkdir "$out/libexec"
|
mkdir "$out/libexec"
|
||||||
mv "$out"/bin/* "$out/libexec/"
|
mv "$out"/bin/* "$out/libexec/"
|
||||||
|
|
||||||
makeBinaryWrapper "$out/libexec/fortify" "$out/bin/fortify" \
|
makeBinaryWrapper "$out/libexec/hakurei" "$out/bin/hakurei" \
|
||||||
--inherit-argv0 --prefix PATH : ${lib.makeBinPath appPackages}
|
--inherit-argv0 --prefix PATH : ${lib.makeBinPath appPackages}
|
||||||
|
|
||||||
makeBinaryWrapper "$out/libexec/fpkg" "$out/bin/fpkg" \
|
makeBinaryWrapper "$out/libexec/fpkg" "$out/bin/fpkg" \
|
||||||
|
22
parse.go
22
parse.go
@ -10,19 +10,19 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/internal/state"
|
"git.gensokyo.uk/security/hakurei/internal/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func tryPath(name string) (config *fst.Config) {
|
func tryPath(name string) (config *hst.Config) {
|
||||||
var r io.Reader
|
var r io.Reader
|
||||||
config = new(fst.Config)
|
config = new(hst.Config)
|
||||||
|
|
||||||
if name != "-" {
|
if name != "-" {
|
||||||
r = tryFd(name)
|
r = tryFd(name)
|
||||||
if r == nil {
|
if r == nil {
|
||||||
fmsg.Verbose("load configuration from file")
|
hlog.Verbose("load configuration from file")
|
||||||
|
|
||||||
if f, err := os.Open(name); err != nil {
|
if f, err := os.Open(name); err != nil {
|
||||||
log.Fatalf("cannot access configuration file %q: %s", name, err)
|
log.Fatalf("cannot access configuration file %q: %s", name, err)
|
||||||
@ -51,11 +51,11 @@ func tryPath(name string) (config *fst.Config) {
|
|||||||
func tryFd(name string) io.ReadCloser {
|
func tryFd(name string) io.ReadCloser {
|
||||||
if v, err := strconv.Atoi(name); err != nil {
|
if v, err := strconv.Atoi(name); err != nil {
|
||||||
if !errors.Is(err, strconv.ErrSyntax) {
|
if !errors.Is(err, strconv.ErrSyntax) {
|
||||||
fmsg.Verbosef("name cannot be interpreted as int64: %v", err)
|
hlog.Verbosef("name cannot be interpreted as int64: %v", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
fmsg.Verbosef("trying config stream from %d", v)
|
hlog.Verbosef("trying config stream from %d", v)
|
||||||
fd := uintptr(v)
|
fd := uintptr(v)
|
||||||
if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_GETFD, 0); errno != 0 {
|
if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_GETFD, 0); errno != 0 {
|
||||||
if errors.Is(errno, syscall.EBADF) {
|
if errors.Is(errno, syscall.EBADF) {
|
||||||
@ -67,7 +67,7 @@ func tryFd(name string) io.ReadCloser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryShort(name string) (config *fst.Config, entry *state.State) {
|
func tryShort(name string) (config *hst.Config, entry *state.State) {
|
||||||
likePrefix := false
|
likePrefix := false
|
||||||
if len(name) <= 32 {
|
if len(name) <= 32 {
|
||||||
likePrefix = true
|
likePrefix = true
|
||||||
@ -85,7 +85,7 @@ func tryShort(name string) (config *fst.Config, entry *state.State) {
|
|||||||
|
|
||||||
// try to match from state store
|
// try to match from state store
|
||||||
if likePrefix && len(name) >= 8 {
|
if likePrefix && len(name) >= 8 {
|
||||||
fmsg.Verbose("argument looks like prefix")
|
hlog.Verbose("argument looks like prefix")
|
||||||
|
|
||||||
s := state.NewMulti(std.Paths().RunDirPath)
|
s := state.NewMulti(std.Paths().RunDirPath)
|
||||||
if entries, err := state.Join(s); err != nil {
|
if entries, err := state.Join(s); err != nil {
|
||||||
@ -101,7 +101,7 @@ func tryShort(name string) (config *fst.Config, entry *state.State) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fmsg.Verbosef("instance %s skipped", v)
|
hlog.Verbosef("instance %s skipped", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
print.go
20
print.go
@ -12,21 +12,21 @@ import (
|
|||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/internal/state"
|
"git.gensokyo.uk/security/hakurei/internal/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func printShowSystem(output io.Writer, short, flagJSON bool) {
|
func printShowSystem(output io.Writer, short, flagJSON bool) {
|
||||||
t := newPrinter(output)
|
t := newPrinter(output)
|
||||||
defer t.MustFlush()
|
defer t.MustFlush()
|
||||||
|
|
||||||
info := new(fst.Info)
|
info := new(hst.Info)
|
||||||
|
|
||||||
// get fid by querying uid of aid 0
|
// get fid by querying uid of aid 0
|
||||||
if uid, err := std.Uid(0); err != nil {
|
if uid, err := std.Uid(0); err != nil {
|
||||||
fmsg.PrintBaseError(err, "cannot obtain uid from fsu:")
|
hlog.PrintBaseError(err, "cannot obtain uid from setuid wrapper:")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
info.User = (uid / 10000) - 100
|
info.User = (uid / 10000) - 100
|
||||||
@ -42,7 +42,7 @@ func printShowSystem(output io.Writer, short, flagJSON bool) {
|
|||||||
|
|
||||||
func printShowInstance(
|
func printShowInstance(
|
||||||
output io.Writer, now time.Time,
|
output io.Writer, now time.Time,
|
||||||
instance *state.State, config *fst.Config,
|
instance *state.State, config *hst.Config,
|
||||||
short, flagJSON bool) {
|
short, flagJSON bool) {
|
||||||
if flagJSON {
|
if flagJSON {
|
||||||
if instance != nil {
|
if instance != nil {
|
||||||
@ -69,9 +69,9 @@ func printShowInstance(
|
|||||||
|
|
||||||
t.Printf("App\n")
|
t.Printf("App\n")
|
||||||
if config.ID != "" {
|
if config.ID != "" {
|
||||||
t.Printf(" ID:\t%d (%s)\n", config.Identity, config.ID)
|
t.Printf(" Identity:\t%d (%s)\n", config.Identity, config.ID)
|
||||||
} else {
|
} else {
|
||||||
t.Printf(" ID:\t%d\n", config.Identity)
|
t.Printf(" Identity:\t%d\n", config.Identity)
|
||||||
}
|
}
|
||||||
t.Printf(" Enablements:\t%s\n", config.Enablements.String())
|
t.Printf(" Enablements:\t%s\n", config.Enablements.String())
|
||||||
if len(config.Groups) > 0 {
|
if len(config.Groups) > 0 {
|
||||||
@ -264,7 +264,7 @@ func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON boo
|
|||||||
as = strconv.Itoa(e.Config.Identity)
|
as = strconv.Itoa(e.Config.Identity)
|
||||||
id := e.Config.ID
|
id := e.Config.ID
|
||||||
if id == "" {
|
if id == "" {
|
||||||
id = "uk.gensokyo.fortify." + e.s[:8]
|
id = "uk.gensokyo.hakurei." + e.s[:8]
|
||||||
}
|
}
|
||||||
as += " (" + id + ")"
|
as += " (" + id + ")"
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/hakurei/dbus"
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal/app"
|
"git.gensokyo.uk/security/hakurei/internal/app"
|
||||||
"git.gensokyo.uk/security/fortify/internal/state"
|
"git.gensokyo.uk/security/hakurei/internal/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -21,7 +21,7 @@ var (
|
|||||||
testState = &state.State{
|
testState = &state.State{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
PID: 0xDEADBEEF,
|
PID: 0xDEADBEEF,
|
||||||
Config: fst.Template(),
|
Config: hst.Template(),
|
||||||
Time: testAppTime,
|
Time: testAppTime,
|
||||||
}
|
}
|
||||||
testTime = time.Unix(3752, 1).UTC()
|
testTime = time.Unix(3752, 1).UTC()
|
||||||
@ -32,15 +32,15 @@ func Test_printShowInstance(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
instance *state.State
|
instance *state.State
|
||||||
config *fst.Config
|
config *hst.Config
|
||||||
short, json bool
|
short, json bool
|
||||||
want string
|
want string
|
||||||
}{
|
}{
|
||||||
{"config", nil, fst.Template(), false, false, `App
|
{"config", nil, hst.Template(), false, false, `App
|
||||||
ID: 9 (org.chromium.Chromium)
|
Identity: 9 (org.chromium.Chromium)
|
||||||
Enablements: wayland, dbus, pulseaudio
|
Enablements: wayland, dbus, pulseaudio
|
||||||
Groups: video, dialout, plugdev
|
Groups: video, dialout, plugdev
|
||||||
Data: /var/lib/fortify/u0/org.chromium.Chromium
|
Data: /var/lib/hakurei/u0/org.chromium.Chromium
|
||||||
Hostname: localhost
|
Hostname: localhost
|
||||||
Flags: userns devel net device tty mapuid autoetc
|
Flags: userns devel net device tty mapuid autoetc
|
||||||
Etc: /etc
|
Etc: /etc
|
||||||
@ -53,12 +53,12 @@ Filesystem
|
|||||||
+/run/current-system
|
+/run/current-system
|
||||||
+/run/opengl-driver
|
+/run/opengl-driver
|
||||||
+/var/db/nix-channels
|
+/var/db/nix-channels
|
||||||
w*/var/lib/fortify/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium
|
w*/var/lib/hakurei/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium
|
||||||
d+/dev/dri
|
d+/dev/dri
|
||||||
|
|
||||||
Extra ACL
|
Extra ACL
|
||||||
--x+:/var/lib/fortify/u0
|
--x+:/var/lib/hakurei/u0
|
||||||
rwx:/var/lib/fortify/u0/org.chromium.Chromium
|
rwx:/var/lib/hakurei/u0/org.chromium.Chromium
|
||||||
|
|
||||||
Session bus
|
Session bus
|
||||||
Filter: true
|
Filter: true
|
||||||
@ -72,23 +72,23 @@ System bus
|
|||||||
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
|
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
|
||||||
|
|
||||||
`},
|
`},
|
||||||
{"config pd", nil, new(fst.Config), false, false, `Warning: this configuration uses permissive defaults!
|
{"config pd", nil, new(hst.Config), false, false, `Warning: this configuration uses permissive defaults!
|
||||||
|
|
||||||
App
|
App
|
||||||
ID: 0
|
Identity: 0
|
||||||
Enablements: (no enablements)
|
Enablements: (no enablements)
|
||||||
|
|
||||||
`},
|
`},
|
||||||
{"config flag none", nil, &fst.Config{Container: new(fst.ContainerConfig)}, false, false, `App
|
{"config flag none", nil, &hst.Config{Container: new(hst.ContainerConfig)}, false, false, `App
|
||||||
ID: 0
|
Identity: 0
|
||||||
Enablements: (no enablements)
|
Enablements: (no enablements)
|
||||||
Flags: none
|
Flags: none
|
||||||
Etc: /etc
|
Etc: /etc
|
||||||
Path:
|
Path:
|
||||||
|
|
||||||
`},
|
`},
|
||||||
{"config nil entries", nil, &fst.Config{Container: &fst.ContainerConfig{Filesystem: make([]*fst.FilesystemConfig, 1)}, ExtraPerms: make([]*fst.ExtraPermConfig, 1)}, false, false, `App
|
{"config nil entries", nil, &hst.Config{Container: &hst.ContainerConfig{Filesystem: make([]*hst.FilesystemConfig, 1)}, ExtraPerms: make([]*hst.ExtraPermConfig, 1)}, false, false, `App
|
||||||
ID: 0
|
Identity: 0
|
||||||
Enablements: (no enablements)
|
Enablements: (no enablements)
|
||||||
Flags: none
|
Flags: none
|
||||||
Etc: /etc
|
Etc: /etc
|
||||||
@ -99,10 +99,10 @@ Filesystem
|
|||||||
Extra ACL
|
Extra ACL
|
||||||
|
|
||||||
`},
|
`},
|
||||||
{"config pd dbus see", nil, &fst.Config{SessionBus: &dbus.Config{See: []string{"org.example.test"}}}, false, false, `Warning: this configuration uses permissive defaults!
|
{"config pd dbus see", nil, &hst.Config{SessionBus: &dbus.Config{See: []string{"org.example.test"}}}, false, false, `Warning: this configuration uses permissive defaults!
|
||||||
|
|
||||||
App
|
App
|
||||||
ID: 0
|
Identity: 0
|
||||||
Enablements: (no enablements)
|
Enablements: (no enablements)
|
||||||
|
|
||||||
Session bus
|
Session bus
|
||||||
@ -111,15 +111,15 @@ Session bus
|
|||||||
|
|
||||||
`},
|
`},
|
||||||
|
|
||||||
{"instance", testState, fst.Template(), false, false, `State
|
{"instance", testState, hst.Template(), false, false, `State
|
||||||
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
|
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
|
||||||
Uptime: 1h2m32s
|
Uptime: 1h2m32s
|
||||||
|
|
||||||
App
|
App
|
||||||
ID: 9 (org.chromium.Chromium)
|
Identity: 9 (org.chromium.Chromium)
|
||||||
Enablements: wayland, dbus, pulseaudio
|
Enablements: wayland, dbus, pulseaudio
|
||||||
Groups: video, dialout, plugdev
|
Groups: video, dialout, plugdev
|
||||||
Data: /var/lib/fortify/u0/org.chromium.Chromium
|
Data: /var/lib/hakurei/u0/org.chromium.Chromium
|
||||||
Hostname: localhost
|
Hostname: localhost
|
||||||
Flags: userns devel net device tty mapuid autoetc
|
Flags: userns devel net device tty mapuid autoetc
|
||||||
Etc: /etc
|
Etc: /etc
|
||||||
@ -132,12 +132,12 @@ Filesystem
|
|||||||
+/run/current-system
|
+/run/current-system
|
||||||
+/run/opengl-driver
|
+/run/opengl-driver
|
||||||
+/var/db/nix-channels
|
+/var/db/nix-channels
|
||||||
w*/var/lib/fortify/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium
|
w*/var/lib/hakurei/u0/org.chromium.Chromium:/data/data/org.chromium.Chromium
|
||||||
d+/dev/dri
|
d+/dev/dri
|
||||||
|
|
||||||
Extra ACL
|
Extra ACL
|
||||||
--x+:/var/lib/fortify/u0
|
--x+:/var/lib/hakurei/u0
|
||||||
rwx:/var/lib/fortify/u0/org.chromium.Chromium
|
rwx:/var/lib/hakurei/u0/org.chromium.Chromium
|
||||||
|
|
||||||
Session bus
|
Session bus
|
||||||
Filter: true
|
Filter: true
|
||||||
@ -151,14 +151,14 @@ System bus
|
|||||||
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
|
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
|
||||||
|
|
||||||
`},
|
`},
|
||||||
{"instance pd", testState, new(fst.Config), false, false, `Warning: this configuration uses permissive defaults!
|
{"instance pd", testState, new(hst.Config), false, false, `Warning: this configuration uses permissive defaults!
|
||||||
|
|
||||||
State
|
State
|
||||||
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
|
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
|
||||||
Uptime: 1h2m32s
|
Uptime: 1h2m32s
|
||||||
|
|
||||||
App
|
App
|
||||||
ID: 0
|
Identity: 0
|
||||||
Enablements: (no enablements)
|
Enablements: (no enablements)
|
||||||
|
|
||||||
`},
|
`},
|
||||||
@ -234,16 +234,16 @@ App
|
|||||||
},
|
},
|
||||||
"username": "chronos",
|
"username": "chronos",
|
||||||
"shell": "/run/current-system/sw/bin/zsh",
|
"shell": "/run/current-system/sw/bin/zsh",
|
||||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"data": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"dir": "/data/data/org.chromium.Chromium",
|
"dir": "/data/data/org.chromium.Chromium",
|
||||||
"extra_perms": [
|
"extra_perms": [
|
||||||
{
|
{
|
||||||
"ensure": true,
|
"ensure": true,
|
||||||
"path": "/var/lib/fortify/u0",
|
"path": "/var/lib/hakurei/u0",
|
||||||
"x": true
|
"x": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"r": true,
|
"r": true,
|
||||||
"w": true,
|
"w": true,
|
||||||
"x": true
|
"x": true
|
||||||
@ -285,7 +285,7 @@ App
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"dst": "/data/data/org.chromium.Chromium",
|
"dst": "/data/data/org.chromium.Chromium",
|
||||||
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"write": true,
|
"write": true,
|
||||||
"require": true
|
"require": true
|
||||||
},
|
},
|
||||||
@ -310,7 +310,7 @@ App
|
|||||||
"time": "1970-01-01T00:00:00.000000009Z"
|
"time": "1970-01-01T00:00:00.000000009Z"
|
||||||
}
|
}
|
||||||
`},
|
`},
|
||||||
{"json config", nil, fst.Template(), false, true, `{
|
{"json config", nil, hst.Template(), false, true, `{
|
||||||
"id": "org.chromium.Chromium",
|
"id": "org.chromium.Chromium",
|
||||||
"path": "/run/current-system/sw/bin/chromium",
|
"path": "/run/current-system/sw/bin/chromium",
|
||||||
"args": [
|
"args": [
|
||||||
@ -359,16 +359,16 @@ App
|
|||||||
},
|
},
|
||||||
"username": "chronos",
|
"username": "chronos",
|
||||||
"shell": "/run/current-system/sw/bin/zsh",
|
"shell": "/run/current-system/sw/bin/zsh",
|
||||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"data": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"dir": "/data/data/org.chromium.Chromium",
|
"dir": "/data/data/org.chromium.Chromium",
|
||||||
"extra_perms": [
|
"extra_perms": [
|
||||||
{
|
{
|
||||||
"ensure": true,
|
"ensure": true,
|
||||||
"path": "/var/lib/fortify/u0",
|
"path": "/var/lib/hakurei/u0",
|
||||||
"x": true
|
"x": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"r": true,
|
"r": true,
|
||||||
"w": true,
|
"w": true,
|
||||||
"x": true
|
"x": true
|
||||||
@ -410,7 +410,7 @@ App
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"dst": "/data/data/org.chromium.Chromium",
|
"dst": "/data/data/org.chromium.Chromium",
|
||||||
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"write": true,
|
"write": true,
|
||||||
"require": true
|
"require": true
|
||||||
},
|
},
|
||||||
@ -460,8 +460,8 @@ func Test_printPs(t *testing.T) {
|
|||||||
{"nil instance", state.Entries{testID: nil}, false, false, " Instance PID Application Uptime\n"},
|
{"nil instance", state.Entries{testID: nil}, false, false, " Instance PID Application Uptime\n"},
|
||||||
{"state corruption", state.Entries{app.ID{}: testState}, false, false, " Instance PID Application Uptime\n"},
|
{"state corruption", state.Entries{app.ID{}: testState}, false, false, " Instance PID Application Uptime\n"},
|
||||||
|
|
||||||
{"valid pd", state.Entries{testID: &state.State{ID: testID, PID: 1 << 8, Config: new(fst.Config), Time: testAppTime}}, false, false, ` Instance PID Application Uptime
|
{"valid pd", state.Entries{testID: &state.State{ID: testID, PID: 1 << 8, Config: new(hst.Config), Time: testAppTime}}, false, false, ` Instance PID Application Uptime
|
||||||
8e2c76b0 256 0 (uk.gensokyo.fortify.8e2c76b0) 1h2m32s
|
8e2c76b0 256 0 (uk.gensokyo.hakurei.8e2c76b0) 1h2m32s
|
||||||
`},
|
`},
|
||||||
|
|
||||||
{"valid", state.Entries{testID: testState}, false, false, ` Instance PID Application Uptime
|
{"valid", state.Entries{testID: testState}, false, false, ` Instance PID Application Uptime
|
||||||
@ -538,16 +538,16 @@ func Test_printPs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"username": "chronos",
|
"username": "chronos",
|
||||||
"shell": "/run/current-system/sw/bin/zsh",
|
"shell": "/run/current-system/sw/bin/zsh",
|
||||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"data": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"dir": "/data/data/org.chromium.Chromium",
|
"dir": "/data/data/org.chromium.Chromium",
|
||||||
"extra_perms": [
|
"extra_perms": [
|
||||||
{
|
{
|
||||||
"ensure": true,
|
"ensure": true,
|
||||||
"path": "/var/lib/fortify/u0",
|
"path": "/var/lib/hakurei/u0",
|
||||||
"x": true
|
"x": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"r": true,
|
"r": true,
|
||||||
"w": true,
|
"w": true,
|
||||||
"x": true
|
"x": true
|
||||||
@ -589,7 +589,7 @@ func Test_printPs(t *testing.T) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"dst": "/data/data/org.chromium.Chromium",
|
"dst": "/data/data/org.chromium.Chromium",
|
||||||
"src": "/var/lib/fortify/u0/org.chromium.Chromium",
|
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
"write": true,
|
"write": true,
|
||||||
"require": true
|
"require": true
|
||||||
},
|
},
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HardeningFlags uintptr
|
type HardeningFlags uintptr
|
||||||
|
@ -12,13 +12,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/fst"
|
"git.gensokyo.uk/security/hakurei/hst"
|
||||||
"git.gensokyo.uk/security/fortify/internal"
|
"git.gensokyo.uk/security/hakurei/internal"
|
||||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
"git.gensokyo.uk/security/hakurei/internal/hlog"
|
||||||
"git.gensokyo.uk/security/fortify/ldd"
|
"git.gensokyo.uk/security/hakurei/ldd"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/vfs"
|
"git.gensokyo.uk/security/hakurei/sandbox/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -28,10 +28,10 @@ const (
|
|||||||
|
|
||||||
func TestContainer(t *testing.T) {
|
func TestContainer(t *testing.T) {
|
||||||
{
|
{
|
||||||
oldVerbose := fmsg.Load()
|
oldVerbose := hlog.Load()
|
||||||
oldOutput := sandbox.GetOutput()
|
oldOutput := sandbox.GetOutput()
|
||||||
internal.InstallFmsg(true)
|
internal.InstallFmsg(true)
|
||||||
t.Cleanup(func() { fmsg.Store(oldVerbose) })
|
t.Cleanup(func() { hlog.Store(oldVerbose) })
|
||||||
t.Cleanup(func() { sandbox.SetOutput(oldOutput) })
|
t.Cleanup(func() { sandbox.SetOutput(oldOutput) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,9 +47,9 @@ func TestContainer(t *testing.T) {
|
|||||||
new(sandbox.Ops), nil, "test-minimal"},
|
new(sandbox.Ops), nil, "test-minimal"},
|
||||||
{"tmpfs", 0,
|
{"tmpfs", 0,
|
||||||
new(sandbox.Ops).
|
new(sandbox.Ops).
|
||||||
Tmpfs(fst.Tmp, 0, 0755),
|
Tmpfs(hst.Tmp, 0, 0755),
|
||||||
[]*vfs.MountInfoEntry{
|
[]*vfs.MountInfoEntry{
|
||||||
e("/", fst.Tmp, "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
e("/", hst.Tmp, "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
||||||
}, "test-tmpfs"},
|
}, "test-tmpfs"},
|
||||||
{"dev", sandbox.FAllowTTY, // go test output is not a tty
|
{"dev", sandbox.FAllowTTY, // go test output is not a tty
|
||||||
new(sandbox.Ops).
|
new(sandbox.Ops).
|
||||||
@ -132,14 +132,14 @@ func TestContainer(t *testing.T) {
|
|||||||
container.Stdin = want
|
container.Stdin = want
|
||||||
|
|
||||||
if err := container.Start(); err != nil {
|
if err := container.Start(); err != nil {
|
||||||
fmsg.PrintBaseError(err, "start:")
|
hlog.PrintBaseError(err, "start:")
|
||||||
t.Fatalf("cannot start container: %v", err)
|
t.Fatalf("cannot start container: %v", err)
|
||||||
} else if err = container.Serve(); err != nil {
|
} else if err = container.Serve(); err != nil {
|
||||||
fmsg.PrintBaseError(err, "serve:")
|
hlog.PrintBaseError(err, "serve:")
|
||||||
t.Errorf("cannot serve setup params: %v", err)
|
t.Errorf("cannot serve setup params: %v", err)
|
||||||
}
|
}
|
||||||
if err := container.Wait(); err != nil {
|
if err := container.Wait(); err != nil {
|
||||||
fmsg.PrintBaseError(err, "wait:")
|
hlog.PrintBaseError(err, "wait:")
|
||||||
t.Fatalf("wait: %v", err)
|
t.Fatalf("wait: %v", err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -175,8 +175,8 @@ func TestHelperInit(t *testing.T) {
|
|||||||
if len(os.Args) != 5 || os.Args[4] != "init" {
|
if len(os.Args) != 5 || os.Args[4] != "init" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sandbox.SetOutput(fmsg.Output{})
|
sandbox.SetOutput(hlog.Output{})
|
||||||
sandbox.Init(fmsg.Prepare, internal.InstallFmsg)
|
sandbox.Init(hlog.Prepare, internal.InstallFmsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHelperCheckContainer(t *testing.T) {
|
func TestHelperCheckContainer(t *testing.T) {
|
||||||
|
@ -4,7 +4,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/hakurei/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExecutable(t *testing.T) {
|
func TestExecutable(t *testing.T) {
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -24,7 +24,7 @@ const (
|
|||||||
basePath = "/tmp"
|
basePath = "/tmp"
|
||||||
|
|
||||||
// setup params file descriptor
|
// setup params file descriptor
|
||||||
setupEnv = "FORTIFY_SETUP"
|
setupEnv = "HAKUREI_SETUP"
|
||||||
)
|
)
|
||||||
|
|
||||||
type initParams struct {
|
type initParams struct {
|
||||||
@ -56,7 +56,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
|||||||
log.Fatal("invalid setup descriptor")
|
log.Fatal("invalid setup descriptor")
|
||||||
}
|
}
|
||||||
if errors.Is(err, ErrNotSet) {
|
if errors.Is(err, ErrNotSet) {
|
||||||
log.Fatal("FORTIFY_SETUP not set")
|
log.Fatal("HAKUREI_SETUP not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Fatalf("cannot decode init setup payload: %v", err)
|
log.Fatalf("cannot decode init setup payload: %v", err)
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/vfs"
|
"git.gensokyo.uk/security/hakurei/sandbox/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) error {
|
func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) error {
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/vfs"
|
"git.gensokyo.uk/security/hakurei/sandbox/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -5,7 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper/proc"
|
"git.gensokyo.uk/security/hakurei/helper/proc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/hakurei/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestExport(t *testing.T) {
|
func TestExport(t *testing.T) {
|
||||||
@ -72,7 +72,7 @@ func TestExport(t *testing.T) {
|
|||||||
0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd,
|
0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd,
|
||||||
0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa,
|
0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa,
|
||||||
}, false},
|
}, false},
|
||||||
{"fortify default", seccomp.FilterExt | seccomp.FilterDenyDevel, []byte{
|
{"hakurei default", seccomp.FilterExt | seccomp.FilterDenyDevel, []byte{
|
||||||
0xc6, 0x98, 0xb0, 0x81, 0xff, 0x95, 0x7a, 0xfe,
|
0xc6, 0x98, 0xb0, 0x81, 0xff, 0x95, 0x7a, 0xfe,
|
||||||
0x17, 0xa6, 0xd9, 0x43, 0x74, 0x53, 0x7d, 0x37,
|
0x17, 0xa6, 0xd9, 0x43, 0x74, 0x53, 0x7d, 0x37,
|
||||||
0xf2, 0xa6, 0x3f, 0x6f, 0x9d, 0xd7, 0x5d, 0xa7,
|
0xf2, 0xa6, 0x3f, 0x6f, 0x9d, 0xd7, 0x5d, 0xa7,
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user