fst: improve config
All checks were successful
Test / Create distribution (push) Successful in 26s
Test / Sandbox (push) Successful in 1m50s
Test / Fortify (push) Successful in 2m46s
Test / Sandbox (race detector) (push) Successful in 2m59s
Test / Fortify (race detector) (push) Successful in 4m23s
Test / Fpkg (push) Successful in 5m25s
Test / Flake checks (push) Successful in 1m1s
All checks were successful
Test / Create distribution (push) Successful in 26s
Test / Sandbox (push) Successful in 1m50s
Test / Fortify (push) Successful in 2m46s
Test / Sandbox (race detector) (push) Successful in 2m59s
Test / Fortify (race detector) (push) Successful in 4m23s
Test / Fpkg (push) Successful in 5m25s
Test / Flake checks (push) Successful in 1m1s
The config struct more or less "grew" to what it is today. This change moves things around to make more sense and fixes nonsensical comments describing obsolete behaviour. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
c460892cbd
commit
31b7ddd122
@ -19,7 +19,7 @@ type appInfo struct {
|
||||
// passed through to [fst.Config]
|
||||
ID string `json:"id"`
|
||||
// passed through to [fst.Config]
|
||||
AppID int `json:"app_id"`
|
||||
Identity int `json:"identity"`
|
||||
// passed through to [fst.Config]
|
||||
Groups []string `json:"groups,omitempty"`
|
||||
// passed through to [fst.Config]
|
||||
@ -65,16 +65,25 @@ type appInfo struct {
|
||||
func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool) *fst.Config {
|
||||
config := &fst.Config{
|
||||
ID: app.ID,
|
||||
|
||||
Path: argv[0],
|
||||
Args: argv,
|
||||
Confinement: fst.ConfinementConfig{
|
||||
AppID: app.AppID,
|
||||
Groups: app.Groups,
|
||||
|
||||
Enablements: app.Enablements,
|
||||
|
||||
SystemBus: app.SystemBus,
|
||||
SessionBus: app.SessionBus,
|
||||
DirectWayland: app.DirectWayland,
|
||||
|
||||
Username: "fortify",
|
||||
Inner: path.Join("/data/data", app.ID),
|
||||
Outer: pathSet.homeDir,
|
||||
Shell: shellPath,
|
||||
Sandbox: &fst.SandboxConfig{
|
||||
Data: pathSet.homeDir,
|
||||
Dir: path.Join("/data/data", app.ID),
|
||||
|
||||
Identity: app.Identity,
|
||||
Groups: app.Groups,
|
||||
|
||||
Container: &fst.ContainerConfig{
|
||||
Hostname: formatHostname(app.Name),
|
||||
Devel: app.Devel,
|
||||
Userns: app.Userns,
|
||||
@ -82,7 +91,6 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
|
||||
Device: app.Device,
|
||||
Tty: app.Tty || flagDropShell,
|
||||
MapRealUID: app.MapRealUID,
|
||||
DirectWayland: app.DirectWayland,
|
||||
Filesystem: []*fst.FilesystemConfig{
|
||||
{Src: path.Join(pathSet.nixPath, "store"), Dst: "/nix/store", Must: true},
|
||||
{Src: pathSet.metaPath, Dst: path.Join(fst.Tmp, "app"), Must: true},
|
||||
@ -105,16 +113,12 @@ func (app *appInfo) toFst(pathSet *appPathSet, argv []string, flagDropShell bool
|
||||
{Path: dataHome, Execute: true},
|
||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||
},
|
||||
SystemBus: app.SystemBus,
|
||||
SessionBus: app.SessionBus,
|
||||
Enablements: app.Enablements,
|
||||
},
|
||||
}
|
||||
if app.Multiarch {
|
||||
config.Confinement.Sandbox.Seccomp |= seccomp.FilterMultiarch
|
||||
config.Container.Seccomp |= seccomp.FilterMultiarch
|
||||
}
|
||||
if app.Bluetooth {
|
||||
config.Confinement.Sandbox.Seccomp |= seccomp.FilterBluetooth
|
||||
config.Container.Seccomp |= seccomp.FilterBluetooth
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
'',
|
||||
|
||||
id ? name,
|
||||
app_id ? throw "app_id is required",
|
||||
identity ? throw "identity is required",
|
||||
groups ? [ ],
|
||||
userns ? false,
|
||||
net ? true,
|
||||
@ -147,7 +147,7 @@ let
|
||||
name
|
||||
version
|
||||
id
|
||||
app_id
|
||||
identity
|
||||
launcher
|
||||
groups
|
||||
userns
|
||||
|
@ -157,11 +157,11 @@ func main() {
|
||||
return errSuccess
|
||||
}
|
||||
|
||||
// AppID determines uid
|
||||
if a.AppID != bundle.AppID {
|
||||
// identity determines uid
|
||||
if a.Identity != bundle.Identity {
|
||||
cleanup()
|
||||
log.Printf("package %q app id %d differs from installed %d",
|
||||
pkgPath, bundle.AppID, a.AppID)
|
||||
log.Printf("package %q identity %d differs from installed %d",
|
||||
pkgPath, bundle.Identity, a.Identity)
|
||||
return syscall.EBADE
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ func main() {
|
||||
"--override-input nixpkgs path:/etc/nixpkgs " +
|
||||
"path:" + a.NixGL + "#nixVulkanNvidia",
|
||||
}, true, func(config *fst.Config) *fst.Config {
|
||||
config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem, []*fst.FilesystemConfig{
|
||||
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{
|
||||
{Src: "/etc/resolv.conf"},
|
||||
{Src: "/sys/block"},
|
||||
{Src: "/sys/bus"},
|
||||
@ -324,7 +324,7 @@ func main() {
|
||||
*/
|
||||
|
||||
if a.GPU {
|
||||
config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem,
|
||||
config.Container.Filesystem = append(config.Container.Filesystem,
|
||||
&fst.FilesystemConfig{Src: path.Join(pathSet.nixPath, ".nixGL"), Dst: path.Join(fst.Tmp, "nixGL")})
|
||||
appendGPUFilesystem(config)
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ func pathSetByApp(id string) *appPathSet {
|
||||
}
|
||||
|
||||
func appendGPUFilesystem(config *fst.Config) {
|
||||
config.Confinement.Sandbox.Filesystem = append(config.Confinement.Sandbox.Filesystem, []*fst.FilesystemConfig{
|
||||
config.Container.Filesystem = append(config.Container.Filesystem, []*fst.FilesystemConfig{
|
||||
// flatpak commit 763a686d874dd668f0236f911de00b80766ffe79
|
||||
{Src: "/dev/dri", Device: true},
|
||||
// mali
|
||||
|
@ -10,7 +10,7 @@ buildPackage {
|
||||
name = "foot";
|
||||
inherit (foot) version;
|
||||
|
||||
app_id = 2;
|
||||
identity = 2;
|
||||
id = "org.codeberg.dnkl.foot";
|
||||
|
||||
modules = [
|
||||
|
@ -65,8 +65,8 @@ def check_state(name, enablements):
|
||||
if len(config['args']) != 1 or not (config['args'][0].startswith("/nix/store/")) or f"fortify-{name}-" not in (config['args'][0]):
|
||||
raise Exception(f"unexpected args {instance['config']['args']}")
|
||||
|
||||
if config['confinement']['enablements'] != enablements:
|
||||
raise Exception(f"unexpected enablements {instance['config']['confinement']['enablements']}")
|
||||
if config['enablements'] != enablements:
|
||||
raise Exception(f"unexpected enablements {instance['config']['enablements']}")
|
||||
|
||||
|
||||
start_all()
|
||||
|
@ -17,6 +17,7 @@ func withNixDaemon(
|
||||
) {
|
||||
mustRunAppDropShell(ctx, updateConfig(&fst.Config{
|
||||
ID: app.ID,
|
||||
|
||||
Path: shellPath,
|
||||
Args: []string{shellPath, "-lc", "rm -f /nix/var/nix/daemon-socket/socket && " +
|
||||
// start nix-daemon
|
||||
@ -29,13 +30,19 @@ func withNixDaemon(
|
||||
// terminate nix-daemon
|
||||
" && pkill nix-daemon",
|
||||
},
|
||||
Confinement: fst.ConfinementConfig{
|
||||
AppID: app.AppID,
|
||||
|
||||
Username: "fortify",
|
||||
Inner: path.Join("/data/data", app.ID),
|
||||
Outer: pathSet.homeDir,
|
||||
Shell: shellPath,
|
||||
Sandbox: &fst.SandboxConfig{
|
||||
Data: pathSet.homeDir,
|
||||
Dir: path.Join("/data/data", app.ID),
|
||||
ExtraPerms: []*fst.ExtraPermConfig{
|
||||
{Path: dataHome, Execute: true},
|
||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||
},
|
||||
|
||||
Identity: app.Identity,
|
||||
|
||||
Container: &fst.ContainerConfig{
|
||||
Hostname: formatHostname(app.Name) + "-" + action,
|
||||
Userns: true, // nix sandbox requires userns
|
||||
Net: net,
|
||||
@ -52,11 +59,6 @@ func withNixDaemon(
|
||||
Etc: path.Join(pathSet.cacheDir, "etc"),
|
||||
AutoEtc: true,
|
||||
},
|
||||
ExtraPerms: []*fst.ExtraPermConfig{
|
||||
{Path: dataHome, Execute: true},
|
||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||
},
|
||||
},
|
||||
}), dropShell, beforeFail)
|
||||
}
|
||||
|
||||
@ -66,15 +68,23 @@ func withCacheDir(
|
||||
app *appInfo, pathSet *appPathSet, dropShell bool, beforeFail func()) {
|
||||
mustRunAppDropShell(ctx, &fst.Config{
|
||||
ID: app.ID,
|
||||
|
||||
Path: shellPath,
|
||||
Args: []string{shellPath, "-lc", strings.Join(command, " && ")},
|
||||
Confinement: fst.ConfinementConfig{
|
||||
AppID: app.AppID,
|
||||
|
||||
Username: "nixos",
|
||||
Inner: path.Join("/data/data", app.ID, "cache"),
|
||||
Outer: pathSet.cacheDir, // this also ensures cacheDir via shim
|
||||
Shell: shellPath,
|
||||
Sandbox: &fst.SandboxConfig{
|
||||
Data: pathSet.cacheDir, // this also ensures cacheDir via shim
|
||||
Dir: path.Join("/data/data", app.ID, "cache"),
|
||||
ExtraPerms: []*fst.ExtraPermConfig{
|
||||
{Path: dataHome, Execute: true},
|
||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||
{Path: workDir, Execute: true},
|
||||
},
|
||||
|
||||
Identity: app.Identity,
|
||||
|
||||
Container: &fst.ContainerConfig{
|
||||
Hostname: formatHostname(app.Name) + "-" + action,
|
||||
Seccomp: seccomp.FilterMultiarch,
|
||||
Tty: dropShell,
|
||||
@ -90,12 +100,6 @@ func withCacheDir(
|
||||
Etc: path.Join(workDir, "etc"),
|
||||
AutoEtc: true,
|
||||
},
|
||||
ExtraPerms: []*fst.ExtraPermConfig{
|
||||
{Path: dataHome, Execute: true},
|
||||
{Ensure: true, Path: pathSet.baseDir, Read: true, Write: true, Execute: true},
|
||||
{Path: workDir, Execute: true},
|
||||
},
|
||||
},
|
||||
}, dropShell, beforeFail)
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
const Tmp = "/.fortify"
|
||||
|
||||
// Config is used to seal an app
|
||||
// Config is used to seal an app implementation.
|
||||
type Config struct {
|
||||
// reverse-DNS style arbitrary identifier string from config;
|
||||
// passed to wayland security-context-v1 as application ID
|
||||
@ -20,39 +20,40 @@ type Config struct {
|
||||
// final args passed to container init
|
||||
Args []string `json:"args"`
|
||||
|
||||
Confinement ConfinementConfig `json:"confinement"`
|
||||
}
|
||||
// system services to make available in the container
|
||||
Enablements system.Enablement `json:"enablements"`
|
||||
|
||||
// session D-Bus proxy configuration;
|
||||
// nil makes session bus proxy assume built-in defaults
|
||||
SessionBus *dbus.Config `json:"session_bus,omitempty"`
|
||||
// system D-Bus proxy configuration;
|
||||
// nil disables system bus proxy
|
||||
SystemBus *dbus.Config `json:"system_bus,omitempty"`
|
||||
// direct access to wayland socket; when this gets set no attempt is made to attach security-context-v1
|
||||
// and the bare socket is mounted to the sandbox
|
||||
DirectWayland bool `json:"direct_wayland,omitempty"`
|
||||
|
||||
// ConfinementConfig defines fortified child's confinement
|
||||
type ConfinementConfig struct {
|
||||
// numerical application id, determines uid in the init namespace
|
||||
AppID int `json:"app_id"`
|
||||
// list of supplementary groups to inherit
|
||||
Groups []string `json:"groups"`
|
||||
// passwd username in container, defaults to passwd name of target uid or chronos
|
||||
Username string `json:"username,omitempty"`
|
||||
// home directory in container, empty for outer
|
||||
Inner string `json:"home_inner"`
|
||||
// home directory in init namespace
|
||||
Outer string `json:"home"`
|
||||
// absolute path to shell, empty for host shell
|
||||
Shell string `json:"shell,omitempty"`
|
||||
// abstract sandbox configuration
|
||||
Sandbox *SandboxConfig `json:"sandbox"`
|
||||
// extra acl ops, runs after everything else
|
||||
// absolute path to home directory in the init mount namespace
|
||||
Data string `json:"data"`
|
||||
// directory to enter and use as home in the container mount namespace, empty for Data
|
||||
Dir string `json:"dir"`
|
||||
// extra acl ops, dispatches before container init
|
||||
ExtraPerms []*ExtraPermConfig `json:"extra_perms,omitempty"`
|
||||
|
||||
// reference to a system D-Bus proxy configuration,
|
||||
// nil value disables system bus proxy
|
||||
SystemBus *dbus.Config `json:"system_bus,omitempty"`
|
||||
// reference to a session D-Bus proxy configuration,
|
||||
// nil value makes session bus proxy assume built-in defaults
|
||||
SessionBus *dbus.Config `json:"session_bus,omitempty"`
|
||||
// numerical application id, used for init user namespace credentials
|
||||
Identity int `json:"identity"`
|
||||
// list of supplementary groups inherited by container processes
|
||||
Groups []string `json:"groups"`
|
||||
|
||||
// system resources to expose to the container
|
||||
Enablements system.Enablement `json:"enablements"`
|
||||
// abstract container configuration baseline
|
||||
Container *ContainerConfig `json:"container"`
|
||||
}
|
||||
|
||||
// ExtraPermConfig describes an acl update op.
|
||||
type ExtraPermConfig struct {
|
||||
Ensure bool `json:"ensure,omitempty"`
|
||||
Path string `json:"path"`
|
||||
|
@ -4,9 +4,9 @@ import (
|
||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
||||
)
|
||||
|
||||
// SandboxConfig describes resources made available to the sandbox.
|
||||
type (
|
||||
SandboxConfig struct {
|
||||
// ContainerConfig describes the container configuration baseline to which the app implementation adds upon.
|
||||
ContainerConfig struct {
|
||||
// container hostname
|
||||
Hostname string `json:"hostname,omitempty"`
|
||||
|
||||
@ -18,7 +18,7 @@ type (
|
||||
Userns bool `json:"userns,omitempty"`
|
||||
// share host net namespace
|
||||
Net bool `json:"net,omitempty"`
|
||||
// expose main process tty
|
||||
// allow dangerous terminal I/O
|
||||
Tty bool `json:"tty,omitempty"`
|
||||
// allow multiarch
|
||||
Multiarch bool `json:"multiarch,omitempty"`
|
||||
@ -28,17 +28,13 @@ type (
|
||||
// map target user uid to privileged user uid in the user namespace
|
||||
MapRealUID bool `json:"map_real_uid"`
|
||||
|
||||
// expose all devices
|
||||
// pass through all devices
|
||||
Device bool `json:"device,omitempty"`
|
||||
// container host filesystem bind mounts
|
||||
Filesystem []*FilesystemConfig `json:"filesystem"`
|
||||
// create symlinks inside container filesystem
|
||||
Link [][2]string `json:"symlink"`
|
||||
|
||||
// direct access to wayland socket; when this gets set no attempt is made to attach security-context-v1
|
||||
// and the bare socket is mounted to the sandbox
|
||||
DirectWayland bool `json:"direct_wayland,omitempty"`
|
||||
|
||||
// read-only /etc directory
|
||||
Etc string `json:"etc,omitempty"`
|
||||
// automatically set up /etc symlinks
|
||||
@ -47,7 +43,7 @@ type (
|
||||
Cover []string `json:"cover"`
|
||||
}
|
||||
|
||||
// FilesystemConfig is a representation of [sandbox.BindMount].
|
||||
// FilesystemConfig is an abstract representation of a bind mount.
|
||||
FilesystemConfig struct {
|
||||
// mount point in container, same as src if empty
|
||||
Dst string `json:"dst,omitempty"`
|
@ -10,6 +10,7 @@ import (
|
||||
func Template() *Config {
|
||||
return &Config{
|
||||
ID: "org.chromium.Chromium",
|
||||
|
||||
Path: "/run/current-system/sw/bin/chromium",
|
||||
Args: []string{
|
||||
"chromium",
|
||||
@ -18,14 +19,44 @@ func Template() *Config {
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland",
|
||||
},
|
||||
Confinement: ConfinementConfig{
|
||||
AppID: 9,
|
||||
Groups: []string{"video"},
|
||||
|
||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||
|
||||
SessionBus: &dbus.Config{
|
||||
See: nil,
|
||||
Talk: []string{"org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets", "org.kde.kwalletd5", "org.kde.kwalletd6", "org.gnome.SessionManager"},
|
||||
Own: []string{"org.chromium.Chromium.*", "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"},
|
||||
Call: map[string]string{"org.freedesktop.portal.*": "*"},
|
||||
Broadcast: map[string]string{"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"},
|
||||
Log: false,
|
||||
Filter: true,
|
||||
},
|
||||
SystemBus: &dbus.Config{
|
||||
See: nil,
|
||||
Talk: []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"},
|
||||
Own: nil,
|
||||
Call: nil,
|
||||
Broadcast: nil,
|
||||
Log: false,
|
||||
Filter: true,
|
||||
},
|
||||
DirectWayland: false,
|
||||
|
||||
Username: "chronos",
|
||||
Outer: "/var/lib/persist/home/org.chromium.Chromium",
|
||||
Inner: "/var/lib/fortify",
|
||||
Shell: "/run/current-system/sw/bin/zsh",
|
||||
Sandbox: &SandboxConfig{
|
||||
Data: "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
Dir: "/data/data/org.chromium.Chromium",
|
||||
ExtraPerms: []*ExtraPermConfig{
|
||||
{Path: "/var/lib/fortify/u0", Ensure: true, Execute: true},
|
||||
{Path: "/var/lib/fortify/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
|
||||
},
|
||||
|
||||
Identity: 9,
|
||||
Groups: []string{"video", "dialout", "plugdev"},
|
||||
|
||||
Container: &ContainerConfig{
|
||||
Hostname: "localhost",
|
||||
Devel: true,
|
||||
Userns: true,
|
||||
@ -35,7 +66,6 @@ func Template() *Config {
|
||||
Tty: true,
|
||||
Multiarch: true,
|
||||
MapRealUID: true,
|
||||
DirectWayland: false,
|
||||
// example API credentials pulled from Google Chrome
|
||||
// DO NOT USE THESE IN A REAL BROWSER
|
||||
Env: map[string]string{
|
||||
@ -57,31 +87,5 @@ func Template() *Config {
|
||||
AutoEtc: true,
|
||||
Cover: []string{"/var/run/nscd"},
|
||||
},
|
||||
ExtraPerms: []*ExtraPermConfig{
|
||||
{Path: "/var/lib/fortify/u0", Ensure: true, Execute: true},
|
||||
{Path: "/var/lib/fortify/u0/org.chromium.Chromium", Read: true, Write: true, Execute: true},
|
||||
},
|
||||
SystemBus: &dbus.Config{
|
||||
See: nil,
|
||||
Talk: []string{"org.bluez", "org.freedesktop.Avahi", "org.freedesktop.UPower"},
|
||||
Own: nil,
|
||||
Call: nil,
|
||||
Broadcast: nil,
|
||||
Log: false,
|
||||
Filter: true,
|
||||
},
|
||||
SessionBus: &dbus.Config{
|
||||
See: nil,
|
||||
Talk: []string{"org.freedesktop.Notifications", "org.freedesktop.FileManager1", "org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets", "org.kde.kwalletd5", "org.kde.kwalletd6", "org.gnome.SessionManager"},
|
||||
Own: []string{"org.chromium.Chromium.*", "org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"},
|
||||
Call: map[string]string{"org.freedesktop.portal.*": "*"},
|
||||
Broadcast: map[string]string{"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"},
|
||||
Log: false,
|
||||
Filter: true,
|
||||
},
|
||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -18,16 +18,67 @@ func TestTemplate(t *testing.T) {
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
],
|
||||
"confinement": {
|
||||
"app_id": 9,
|
||||
"groups": [
|
||||
"video"
|
||||
"enablements": 13,
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"username": "chronos",
|
||||
"home_inner": "/var/lib/fortify",
|
||||
"home": "/var/lib/persist/home/org.chromium.Chromium",
|
||||
"shell": "/run/current-system/sw/bin/zsh",
|
||||
"sandbox": {
|
||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"dir": "/data/data/org.chromium.Chromium",
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"identity": 9,
|
||||
"groups": [
|
||||
"video",
|
||||
"dialout",
|
||||
"plugdev"
|
||||
],
|
||||
"container": {
|
||||
"hostname": "localhost",
|
||||
"seccomp": 32,
|
||||
"devel": true,
|
||||
@ -77,57 +128,6 @@ func TestTemplate(t *testing.T) {
|
||||
"cover": [
|
||||
"/var/run/nscd"
|
||||
]
|
||||
},
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"enablements": 13
|
||||
}
|
||||
}`
|
||||
|
||||
|
@ -16,9 +16,9 @@ import (
|
||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
||||
)
|
||||
|
||||
// NewContainer initialises [sandbox.Params] via [fst.SandboxConfig].
|
||||
// NewContainer initialises [sandbox.Params] via [fst.ContainerConfig].
|
||||
// Note that remaining container setup must be queued by the caller.
|
||||
func NewContainer(s *fst.SandboxConfig, os sys.State, uid, gid *int) (*sandbox.Params, map[string]string, error) {
|
||||
func NewContainer(s *fst.ContainerConfig, os sys.State, uid, gid *int) (*sandbox.Params, map[string]string, error) {
|
||||
if s == nil {
|
||||
return nil, nil, syscall.EBADE
|
||||
}
|
||||
|
@ -15,11 +15,10 @@ var testCasesNixos = []sealTestCase{
|
||||
&fst.Config{
|
||||
ID: "org.chromium.Chromium",
|
||||
Path: "/nix/store/yqivzpzzn7z5x0lq9hmbzygh45d8rhqd-chromium-start",
|
||||
Confinement: fst.ConfinementConfig{
|
||||
AppID: 1, Groups: []string{}, Username: "u0_a1",
|
||||
Outer: "/var/lib/persist/module/fortify/0/1",
|
||||
Sandbox: &fst.SandboxConfig{
|
||||
Userns: true, Net: true, MapRealUID: true, DirectWayland: true, Env: nil, AutoEtc: true,
|
||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||
|
||||
Container: &fst.ContainerConfig{
|
||||
Userns: true, Net: true, MapRealUID: true, Env: nil, AutoEtc: true,
|
||||
Filesystem: []*fst.FilesystemConfig{
|
||||
{Src: "/bin", Must: true}, {Src: "/usr/bin", Must: true},
|
||||
{Src: "/nix/store", Must: true}, {Src: "/run/current-system", Must: true},
|
||||
@ -46,8 +45,11 @@ var testCasesNixos = []sealTestCase{
|
||||
Call: map[string]string{}, Broadcast: map[string]string{},
|
||||
Filter: true,
|
||||
},
|
||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||
},
|
||||
DirectWayland: true,
|
||||
|
||||
Username: "u0_a1",
|
||||
Data: "/var/lib/persist/module/fortify/0/1",
|
||||
Identity: 1, Groups: []string{},
|
||||
},
|
||||
app.ID{
|
||||
0x8e, 0x2c, 0x76, 0xb0,
|
||||
|
@ -14,13 +14,7 @@ import (
|
||||
var testCasesPd = []sealTestCase{
|
||||
{
|
||||
"nixos permissive defaults no enablements", new(stubNixOS),
|
||||
&fst.Config{
|
||||
Confinement: fst.ConfinementConfig{
|
||||
AppID: 0,
|
||||
Username: "chronos",
|
||||
Outer: "/home/chronos",
|
||||
},
|
||||
},
|
||||
&fst.Config{Username: "chronos", Data: "/home/chronos"},
|
||||
app.ID{
|
||||
0x4a, 0x45, 0x0b, 0x65,
|
||||
0x96, 0xd7, 0xbc, 0x15,
|
||||
@ -79,11 +73,10 @@ var testCasesPd = []sealTestCase{
|
||||
&fst.Config{
|
||||
ID: "org.chromium.Chromium",
|
||||
Args: []string{"zsh", "-c", "exec chromium "},
|
||||
Confinement: fst.ConfinementConfig{
|
||||
AppID: 9,
|
||||
Identity: 9,
|
||||
Groups: []string{"video"},
|
||||
Username: "chronos",
|
||||
Outer: "/home/chronos",
|
||||
Data: "/home/chronos",
|
||||
SessionBus: &dbus.Config{
|
||||
Talk: []string{
|
||||
"org.freedesktop.Notifications",
|
||||
@ -117,7 +110,6 @@ var testCasesPd = []sealTestCase{
|
||||
},
|
||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||
},
|
||||
},
|
||||
app.ID{
|
||||
0xeb, 0xf0, 0x83, 0xd1,
|
||||
0xb1, 0x75, 0x91, 0x17,
|
||||
|
@ -65,7 +65,7 @@ func (seal *outcome) Run(rs *RunState) error {
|
||||
// accumulate enablements of remaining launchers
|
||||
for i, s := range states {
|
||||
if s.Config != nil {
|
||||
rt |= s.Config.Confinement.Enablements
|
||||
rt |= s.Config.Enablements
|
||||
} else {
|
||||
log.Printf("state entry %d does not contain config", i)
|
||||
}
|
||||
|
@ -169,16 +169,16 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
}
|
||||
|
||||
// allowed aid range 0 to 9999, this is checked again in fsu
|
||||
if config.Confinement.AppID < 0 || config.Confinement.AppID > 9999 {
|
||||
if config.Identity < 0 || config.Identity > 9999 {
|
||||
return fmsg.WrapError(ErrUser,
|
||||
fmt.Sprintf("aid %d out of range", config.Confinement.AppID))
|
||||
fmt.Sprintf("identity %d out of range", config.Identity))
|
||||
}
|
||||
|
||||
seal.user = fsuUser{
|
||||
aid: newInt(config.Confinement.AppID),
|
||||
data: config.Confinement.Outer,
|
||||
home: config.Confinement.Inner,
|
||||
username: config.Confinement.Username,
|
||||
aid: newInt(config.Identity),
|
||||
data: config.Data,
|
||||
home: config.Dir,
|
||||
username: config.Username,
|
||||
}
|
||||
if seal.user.username == "" {
|
||||
seal.user.username = "chronos"
|
||||
@ -199,8 +199,8 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
} else {
|
||||
seal.user.uid = newInt(u)
|
||||
}
|
||||
seal.user.supp = make([]string, len(config.Confinement.Groups))
|
||||
for i, name := range config.Confinement.Groups {
|
||||
seal.user.supp = make([]string, len(config.Groups))
|
||||
for i, name := range config.Groups {
|
||||
if g, err := sys.LookupGroup(name); err != nil {
|
||||
return fmsg.WrapError(err,
|
||||
fmt.Sprintf("unknown group %q", name))
|
||||
@ -210,17 +210,17 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
}
|
||||
|
||||
// this also falls back to host path if encountering an invalid path
|
||||
if !path.IsAbs(config.Confinement.Shell) {
|
||||
config.Confinement.Shell = "/bin/sh"
|
||||
if !path.IsAbs(config.Shell) {
|
||||
config.Shell = "/bin/sh"
|
||||
if s, ok := sys.LookupEnv(shell); ok && path.IsAbs(s) {
|
||||
config.Confinement.Shell = s
|
||||
config.Shell = s
|
||||
}
|
||||
}
|
||||
// do not use the value of shell before this point
|
||||
|
||||
// permissive defaults
|
||||
if config.Confinement.Sandbox == nil {
|
||||
fmsg.Verbose("sandbox configuration not supplied, PROCEED WITH CAUTION")
|
||||
if config.Container == nil {
|
||||
fmsg.Verbose("container configuration not supplied, PROCEED WITH CAUTION")
|
||||
|
||||
// fsu clears the environment so resolve paths early
|
||||
if !path.IsAbs(config.Path) {
|
||||
@ -231,11 +231,11 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
config.Path = p
|
||||
}
|
||||
} else {
|
||||
config.Path = config.Confinement.Shell
|
||||
config.Path = config.Shell
|
||||
}
|
||||
}
|
||||
|
||||
conf := &fst.SandboxConfig{
|
||||
conf := &fst.ContainerConfig{
|
||||
Userns: true,
|
||||
Net: true,
|
||||
Tty: true,
|
||||
@ -268,20 +268,20 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
conf.Cover = append(conf.Cover, nscd)
|
||||
}
|
||||
// bind GPU stuff
|
||||
if config.Confinement.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})
|
||||
}
|
||||
// opportunistically bind kvm
|
||||
conf.Filesystem = append(conf.Filesystem, &fst.FilesystemConfig{Src: "/dev/kvm", Device: true})
|
||||
|
||||
config.Confinement.Sandbox = conf
|
||||
config.Container = conf
|
||||
}
|
||||
|
||||
var mapuid, mapgid *stringPair[int]
|
||||
{
|
||||
var uid, gid int
|
||||
var err error
|
||||
seal.container, seal.env, err = common.NewContainer(config.Confinement.Sandbox, sys, &uid, &gid)
|
||||
seal.container, seal.env, err = common.NewContainer(config.Container, sys, &uid, &gid)
|
||||
if err != nil {
|
||||
return fmsg.WrapErrorSuffix(err,
|
||||
"cannot initialise container configuration:")
|
||||
@ -303,12 +303,12 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
}
|
||||
}
|
||||
|
||||
if !config.Confinement.Sandbox.AutoEtc {
|
||||
if config.Confinement.Sandbox.Etc != "" {
|
||||
seal.container.Bind(config.Confinement.Sandbox.Etc, "/etc", 0)
|
||||
if !config.Container.AutoEtc {
|
||||
if config.Container.Etc != "" {
|
||||
seal.container.Bind(config.Container.Etc, "/etc", 0)
|
||||
}
|
||||
} else {
|
||||
etcPath := config.Confinement.Sandbox.Etc
|
||||
etcPath := config.Container.Etc
|
||||
if etcPath == "" {
|
||||
etcPath = "/etc"
|
||||
}
|
||||
@ -352,10 +352,10 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
seal.container.Dir = homeDir
|
||||
seal.env["HOME"] = homeDir
|
||||
seal.env["USER"] = username
|
||||
seal.env[shell] = config.Confinement.Shell
|
||||
seal.env[shell] = config.Shell
|
||||
|
||||
seal.container.Place("/etc/passwd",
|
||||
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Fortify:"+homeDir+":"+config.Confinement.Shell+"\n"))
|
||||
[]byte(username+":x:"+mapuid.String()+":"+mapgid.String()+":Fortify:"+homeDir+":"+config.Shell+"\n"))
|
||||
seal.container.Place("/etc/group",
|
||||
[]byte("fortify:x:"+mapgid.String()+":\n"))
|
||||
}
|
||||
@ -365,7 +365,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
seal.env[term] = t
|
||||
}
|
||||
|
||||
if config.Confinement.Enablements&system.EWayland != 0 {
|
||||
if config.Enablements&system.EWayland != 0 {
|
||||
// outer wayland socket (usually `/run/user/%d/wayland-%d`)
|
||||
var socketPath string
|
||||
if name, ok := sys.LookupEnv(wl.WaylandDisplay); !ok {
|
||||
@ -380,7 +380,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
innerPath := path.Join(innerRuntimeDir, wl.FallbackName)
|
||||
seal.env[wl.WaylandDisplay] = wl.FallbackName
|
||||
|
||||
if !config.Confinement.Sandbox.DirectWayland { // set up security-context-v1
|
||||
if !config.DirectWayland { // set up security-context-v1
|
||||
appID := config.ID
|
||||
if appID == "" {
|
||||
// use instance ID in case app id is not set
|
||||
@ -398,7 +398,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
}
|
||||
}
|
||||
|
||||
if config.Confinement.Enablements&system.EX11 != 0 {
|
||||
if config.Enablements&system.EX11 != 0 {
|
||||
if d, ok := sys.LookupEnv(display); !ok {
|
||||
return fmsg.WrapError(ErrXDisplay,
|
||||
"DISPLAY is not set")
|
||||
@ -409,7 +409,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
}
|
||||
}
|
||||
|
||||
if config.Confinement.Enablements&system.EPulse != 0 {
|
||||
if config.Enablements&system.EPulse != 0 {
|
||||
// PulseAudio runtime directory (usually `/run/user/%d/pulse`)
|
||||
pulseRuntimeDir := path.Join(share.sc.RuntimePath, "pulse")
|
||||
// PulseAudio socket (usually `/run/user/%d/pulse/native`)
|
||||
@ -458,10 +458,10 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
}
|
||||
}
|
||||
|
||||
if config.Confinement.Enablements&system.EDBus != 0 {
|
||||
if config.Enablements&system.EDBus != 0 {
|
||||
// ensure dbus session bus defaults
|
||||
if config.Confinement.SessionBus == nil {
|
||||
config.Confinement.SessionBus = dbus.NewConfig(config.ID, true, true)
|
||||
if config.SessionBus == nil {
|
||||
config.SessionBus = dbus.NewConfig(config.ID, true, true)
|
||||
}
|
||||
|
||||
// downstream socket paths
|
||||
@ -470,7 +470,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
|
||||
// configure dbus proxy
|
||||
if f, err := seal.sys.ProxyDBus(
|
||||
config.Confinement.SessionBus, config.Confinement.SystemBus,
|
||||
config.SessionBus, config.SystemBus,
|
||||
sessionPath, systemPath,
|
||||
); err != nil {
|
||||
return err
|
||||
@ -483,7 +483,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
seal.env[dbusSessionBusAddress] = "unix:path=" + sessionInner
|
||||
seal.container.Bind(sessionPath, sessionInner, 0)
|
||||
seal.sys.UpdatePerm(sessionPath, acl.Read, acl.Write)
|
||||
if config.Confinement.SystemBus != nil {
|
||||
if config.SystemBus != nil {
|
||||
systemInner := "/run/dbus/system_bus_socket"
|
||||
seal.env[dbusSystemBusAddress] = "unix:path=" + systemInner
|
||||
seal.container.Bind(systemPath, systemInner, 0)
|
||||
@ -491,12 +491,12 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
}
|
||||
}
|
||||
|
||||
for _, dest := range config.Confinement.Sandbox.Cover {
|
||||
for _, dest := range config.Container.Cover {
|
||||
seal.container.Tmpfs(dest, 1<<13, 0755)
|
||||
}
|
||||
|
||||
// append ExtraPerms last
|
||||
for _, p := range config.Confinement.ExtraPerms {
|
||||
for _, p := range config.ExtraPerms {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
@ -530,7 +530,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *fst.Co
|
||||
slices.Sort(seal.container.Env)
|
||||
|
||||
fmsg.Verbosef("created application seal for uid %s (%s) groups: %v, argv: %s",
|
||||
seal.user.uid, seal.user.username, config.Confinement.Groups, seal.container.Args)
|
||||
seal.user.uid, seal.user.username, config.Groups, seal.container.Args)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
26
main.go
26
main.go
@ -154,33 +154,33 @@ func buildCommand(out io.Writer) command.Command {
|
||||
userName = passwd.Username
|
||||
}
|
||||
|
||||
config.Confinement.AppID = aid
|
||||
config.Confinement.Groups = groups
|
||||
config.Confinement.Outer = homeDir
|
||||
config.Confinement.Username = userName
|
||||
config.Identity = aid
|
||||
config.Groups = groups
|
||||
config.Data = homeDir
|
||||
config.Username = userName
|
||||
|
||||
if wayland {
|
||||
config.Confinement.Enablements |= system.EWayland
|
||||
config.Enablements |= system.EWayland
|
||||
}
|
||||
if x11 {
|
||||
config.Confinement.Enablements |= system.EX11
|
||||
config.Enablements |= system.EX11
|
||||
}
|
||||
if dBus {
|
||||
config.Confinement.Enablements |= system.EDBus
|
||||
config.Enablements |= system.EDBus
|
||||
}
|
||||
if pulse {
|
||||
config.Confinement.Enablements |= system.EPulse
|
||||
config.Enablements |= system.EPulse
|
||||
}
|
||||
|
||||
// parse D-Bus config file from flags if applicable
|
||||
if dBus {
|
||||
if dbusConfigSession == "builtin" {
|
||||
config.Confinement.SessionBus = dbus.NewConfig(fid, true, mpris)
|
||||
config.SessionBus = dbus.NewConfig(fid, true, mpris)
|
||||
} else {
|
||||
if conf, err := dbus.NewConfigFromFile(dbusConfigSession); err != nil {
|
||||
log.Fatalf("cannot load session bus proxy config from %q: %s", dbusConfigSession, err)
|
||||
} else {
|
||||
config.Confinement.SessionBus = conf
|
||||
config.SessionBus = conf
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,14 +189,14 @@ func buildCommand(out io.Writer) command.Command {
|
||||
if conf, err := dbus.NewConfigFromFile(dbusConfigSystem); err != nil {
|
||||
log.Fatalf("cannot load system bus proxy config from %q: %s", dbusConfigSystem, err)
|
||||
} else {
|
||||
config.Confinement.SystemBus = conf
|
||||
config.SystemBus = conf
|
||||
}
|
||||
}
|
||||
|
||||
// override log from configuration
|
||||
if dbusVerbose {
|
||||
config.Confinement.SessionBus.Log = true
|
||||
config.Confinement.SystemBus.Log = true
|
||||
config.SessionBus.Log = true
|
||||
config.SystemBus.Log = true
|
||||
}
|
||||
}
|
||||
|
||||
|
21
nixos.nix
21
nixos.nix
@ -88,6 +88,7 @@ in
|
||||
|
||||
conf = {
|
||||
inherit (app) id;
|
||||
|
||||
path =
|
||||
if app.path == null then
|
||||
pkgs.writeScript "${app.name}-start" ''
|
||||
@ -98,12 +99,18 @@ in
|
||||
app.path;
|
||||
args = if app.args == null then [ "${app.name}-start" ] else app.args;
|
||||
|
||||
confinement = {
|
||||
app_id = aid;
|
||||
inherit (app) groups;
|
||||
inherit enablements;
|
||||
|
||||
inherit (dbusConfig) session_bus system_bus;
|
||||
direct_wayland = app.insecureWayland;
|
||||
|
||||
username = getsubname fid aid;
|
||||
home = getsubhome fid aid;
|
||||
sandbox = {
|
||||
data = getsubhome fid aid;
|
||||
|
||||
identity = aid;
|
||||
inherit (app) groups;
|
||||
|
||||
container = {
|
||||
inherit (app)
|
||||
devel
|
||||
userns
|
||||
@ -114,7 +121,6 @@ in
|
||||
env
|
||||
;
|
||||
map_real_uid = app.mapRealUid;
|
||||
direct_wayland = app.insecureWayland;
|
||||
|
||||
filesystem =
|
||||
let
|
||||
@ -177,9 +183,6 @@ in
|
||||
);
|
||||
};
|
||||
|
||||
inherit enablements;
|
||||
inherit (dbusConfig) session_bus system_bus;
|
||||
};
|
||||
};
|
||||
in
|
||||
pkgs.writeShellScriptBin app.name ''
|
||||
|
68
print.go
68
print.go
@ -56,7 +56,7 @@ func printShowInstance(
|
||||
t := newPrinter(output)
|
||||
defer t.MustFlush()
|
||||
|
||||
if config.Confinement.Sandbox == nil {
|
||||
if config.Container == nil {
|
||||
mustPrint(output, "Warning: this configuration uses permissive defaults!\n\n")
|
||||
}
|
||||
|
||||
@ -69,21 +69,21 @@ func printShowInstance(
|
||||
|
||||
t.Printf("App\n")
|
||||
if config.ID != "" {
|
||||
t.Printf(" ID:\t%d (%s)\n", config.Confinement.AppID, config.ID)
|
||||
t.Printf(" ID:\t%d (%s)\n", config.Identity, config.ID)
|
||||
} else {
|
||||
t.Printf(" ID:\t%d\n", config.Confinement.AppID)
|
||||
t.Printf(" ID:\t%d\n", config.Identity)
|
||||
}
|
||||
t.Printf(" Enablements:\t%s\n", config.Confinement.Enablements.String())
|
||||
if len(config.Confinement.Groups) > 0 {
|
||||
t.Printf(" Groups:\t%q\n", config.Confinement.Groups)
|
||||
t.Printf(" Enablements:\t%s\n", config.Enablements.String())
|
||||
if len(config.Groups) > 0 {
|
||||
t.Printf(" Groups:\t%s\n", strings.Join(config.Groups, ", "))
|
||||
}
|
||||
if config.Confinement.Outer != "" {
|
||||
t.Printf(" Directory:\t%s\n", config.Confinement.Outer)
|
||||
if config.Data != "" {
|
||||
t.Printf(" Data:\t%s\n", config.Data)
|
||||
}
|
||||
if config.Confinement.Sandbox != nil {
|
||||
sandbox := config.Confinement.Sandbox
|
||||
if sandbox.Hostname != "" {
|
||||
t.Printf(" Hostname:\t%q\n", sandbox.Hostname)
|
||||
if config.Container != nil {
|
||||
container := config.Container
|
||||
if container.Hostname != "" {
|
||||
t.Printf(" Hostname:\t%s\n", container.Hostname)
|
||||
}
|
||||
flags := make([]string, 0, 7)
|
||||
writeFlag := func(name string, value bool) {
|
||||
@ -91,33 +91,29 @@ func printShowInstance(
|
||||
flags = append(flags, name)
|
||||
}
|
||||
}
|
||||
writeFlag("userns", sandbox.Userns)
|
||||
writeFlag("devel", sandbox.Devel)
|
||||
writeFlag("net", sandbox.Net)
|
||||
writeFlag("device", sandbox.Device)
|
||||
writeFlag("tty", sandbox.Tty)
|
||||
writeFlag("mapuid", sandbox.MapRealUID)
|
||||
writeFlag("directwl", sandbox.DirectWayland)
|
||||
writeFlag("autoetc", sandbox.AutoEtc)
|
||||
writeFlag("userns", container.Userns)
|
||||
writeFlag("devel", container.Devel)
|
||||
writeFlag("net", container.Net)
|
||||
writeFlag("device", container.Device)
|
||||
writeFlag("tty", container.Tty)
|
||||
writeFlag("mapuid", container.MapRealUID)
|
||||
writeFlag("directwl", config.DirectWayland)
|
||||
writeFlag("autoetc", container.AutoEtc)
|
||||
if len(flags) == 0 {
|
||||
flags = append(flags, "none")
|
||||
}
|
||||
t.Printf(" Flags:\t%s\n", strings.Join(flags, " "))
|
||||
|
||||
etc := sandbox.Etc
|
||||
etc := container.Etc
|
||||
if etc == "" {
|
||||
etc = "/etc"
|
||||
}
|
||||
t.Printf(" Etc:\t%s\n", etc)
|
||||
|
||||
if len(sandbox.Cover) > 0 {
|
||||
t.Printf(" Cover:\t%s\n", strings.Join(sandbox.Cover, " "))
|
||||
if len(container.Cover) > 0 {
|
||||
t.Printf(" Cover:\t%s\n", strings.Join(container.Cover, " "))
|
||||
}
|
||||
|
||||
// Env map[string]string `json:"env"`
|
||||
// Link [][2]string `json:"symlink"`
|
||||
}
|
||||
if config.Confinement.Sandbox != nil {
|
||||
t.Printf(" Path:\t%s\n", config.Path)
|
||||
}
|
||||
if len(config.Args) > 0 {
|
||||
@ -126,9 +122,9 @@ func printShowInstance(
|
||||
t.Printf("\n")
|
||||
|
||||
if !short {
|
||||
if config.Confinement.Sandbox != nil && len(config.Confinement.Sandbox.Filesystem) > 0 {
|
||||
if config.Container != nil && len(config.Container.Filesystem) > 0 {
|
||||
t.Printf("Filesystem\n")
|
||||
for _, f := range config.Confinement.Sandbox.Filesystem {
|
||||
for _, f := range config.Container.Filesystem {
|
||||
if f == nil {
|
||||
continue
|
||||
}
|
||||
@ -156,9 +152,9 @@ func printShowInstance(
|
||||
}
|
||||
t.Printf("\n")
|
||||
}
|
||||
if len(config.Confinement.ExtraPerms) > 0 {
|
||||
if len(config.ExtraPerms) > 0 {
|
||||
t.Printf("Extra ACL\n")
|
||||
for _, p := range config.Confinement.ExtraPerms {
|
||||
for _, p := range config.ExtraPerms {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
@ -186,14 +182,14 @@ func printShowInstance(
|
||||
t.Printf(" Broadcast:\t%q\n", c.Broadcast)
|
||||
}
|
||||
}
|
||||
if config.Confinement.SessionBus != nil {
|
||||
if config.SessionBus != nil {
|
||||
t.Printf("Session bus\n")
|
||||
printDBus(config.Confinement.SessionBus)
|
||||
printDBus(config.SessionBus)
|
||||
t.Printf("\n")
|
||||
}
|
||||
if config.Confinement.SystemBus != nil {
|
||||
if config.SystemBus != nil {
|
||||
t.Printf("System bus\n")
|
||||
printDBus(config.Confinement.SystemBus)
|
||||
printDBus(config.SystemBus)
|
||||
t.Printf("\n")
|
||||
}
|
||||
}
|
||||
@ -265,7 +261,7 @@ func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON boo
|
||||
|
||||
as := "(No configuration information)"
|
||||
if e.Config != nil {
|
||||
as = strconv.Itoa(e.Config.Confinement.AppID)
|
||||
as = strconv.Itoa(e.Config.Identity)
|
||||
id := e.Config.ID
|
||||
if id == "" {
|
||||
id = "uk.gensokyo.fortify." + e.s[:8]
|
||||
|
366
print_test.go
366
print_test.go
@ -39,9 +39,9 @@ func Test_printShowInstance(t *testing.T) {
|
||||
{"config", nil, fst.Template(), false, false, `App
|
||||
ID: 9 (org.chromium.Chromium)
|
||||
Enablements: wayland, dbus, pulseaudio
|
||||
Groups: ["video"]
|
||||
Directory: /var/lib/persist/home/org.chromium.Chromium
|
||||
Hostname: "localhost"
|
||||
Groups: video, dialout, plugdev
|
||||
Data: /var/lib/fortify/u0/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Flags: userns devel net device tty mapuid autoetc
|
||||
Etc: /etc
|
||||
Cover: /var/run/nscd
|
||||
@ -79,7 +79,7 @@ App
|
||||
Enablements: (no enablements)
|
||||
|
||||
`},
|
||||
{"config flag none", nil, &fst.Config{Confinement: fst.ConfinementConfig{Sandbox: new(fst.SandboxConfig)}}, false, false, `App
|
||||
{"config flag none", nil, &fst.Config{Container: new(fst.ContainerConfig)}, false, false, `App
|
||||
ID: 0
|
||||
Enablements: (no enablements)
|
||||
Flags: none
|
||||
@ -87,7 +87,7 @@ App
|
||||
Path:
|
||||
|
||||
`},
|
||||
{"config nil entries", nil, &fst.Config{Confinement: fst.ConfinementConfig{Sandbox: &fst.SandboxConfig{Filesystem: make([]*fst.FilesystemConfig, 1)}, ExtraPerms: make([]*fst.ExtraPermConfig, 1)}}, false, false, `App
|
||||
{"config nil entries", nil, &fst.Config{Container: &fst.ContainerConfig{Filesystem: make([]*fst.FilesystemConfig, 1)}, ExtraPerms: make([]*fst.ExtraPermConfig, 1)}, false, false, `App
|
||||
ID: 0
|
||||
Enablements: (no enablements)
|
||||
Flags: none
|
||||
@ -99,7 +99,7 @@ Filesystem
|
||||
Extra ACL
|
||||
|
||||
`},
|
||||
{"config pd dbus see", nil, &fst.Config{Confinement: fst.ConfinementConfig{SessionBus: &dbus.Config{See: []string{"org.example.test"}}}}, false, false, `Warning: this configuration uses permissive defaults!
|
||||
{"config pd dbus see", nil, &fst.Config{SessionBus: &dbus.Config{See: []string{"org.example.test"}}}, false, false, `Warning: this configuration uses permissive defaults!
|
||||
|
||||
App
|
||||
ID: 0
|
||||
@ -118,9 +118,9 @@ Session bus
|
||||
App
|
||||
ID: 9 (org.chromium.Chromium)
|
||||
Enablements: wayland, dbus, pulseaudio
|
||||
Groups: ["video"]
|
||||
Directory: /var/lib/persist/home/org.chromium.Chromium
|
||||
Hostname: "localhost"
|
||||
Groups: video, dialout, plugdev
|
||||
Data: /var/lib/fortify/u0/org.chromium.Chromium
|
||||
Hostname: localhost
|
||||
Flags: userns devel net device tty mapuid autoetc
|
||||
Etc: /etc
|
||||
Cover: /var/run/nscd
|
||||
@ -195,16 +195,67 @@ App
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
],
|
||||
"confinement": {
|
||||
"app_id": 9,
|
||||
"groups": [
|
||||
"video"
|
||||
"enablements": 13,
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"username": "chronos",
|
||||
"home_inner": "/var/lib/fortify",
|
||||
"home": "/var/lib/persist/home/org.chromium.Chromium",
|
||||
"shell": "/run/current-system/sw/bin/zsh",
|
||||
"sandbox": {
|
||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"dir": "/data/data/org.chromium.Chromium",
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"identity": 9,
|
||||
"groups": [
|
||||
"video",
|
||||
"dialout",
|
||||
"plugdev"
|
||||
],
|
||||
"container": {
|
||||
"hostname": "localhost",
|
||||
"seccomp": 32,
|
||||
"devel": true,
|
||||
@ -254,57 +305,6 @@ App
|
||||
"cover": [
|
||||
"/var/run/nscd"
|
||||
]
|
||||
},
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"enablements": 13
|
||||
}
|
||||
},
|
||||
"time": "1970-01-01T00:00:00.000000009Z"
|
||||
@ -320,16 +320,67 @@ App
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
],
|
||||
"confinement": {
|
||||
"app_id": 9,
|
||||
"groups": [
|
||||
"video"
|
||||
"enablements": 13,
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"username": "chronos",
|
||||
"home_inner": "/var/lib/fortify",
|
||||
"home": "/var/lib/persist/home/org.chromium.Chromium",
|
||||
"shell": "/run/current-system/sw/bin/zsh",
|
||||
"sandbox": {
|
||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"dir": "/data/data/org.chromium.Chromium",
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"identity": 9,
|
||||
"groups": [
|
||||
"video",
|
||||
"dialout",
|
||||
"plugdev"
|
||||
],
|
||||
"container": {
|
||||
"hostname": "localhost",
|
||||
"seccomp": 32,
|
||||
"devel": true,
|
||||
@ -379,57 +430,6 @@ App
|
||||
"cover": [
|
||||
"/var/run/nscd"
|
||||
]
|
||||
},
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"enablements": 13
|
||||
}
|
||||
}
|
||||
`},
|
||||
@ -499,16 +499,67 @@ func Test_printPs(t *testing.T) {
|
||||
"--enable-features=UseOzonePlatform",
|
||||
"--ozone-platform=wayland"
|
||||
],
|
||||
"confinement": {
|
||||
"app_id": 9,
|
||||
"groups": [
|
||||
"video"
|
||||
"enablements": 13,
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"username": "chronos",
|
||||
"home_inner": "/var/lib/fortify",
|
||||
"home": "/var/lib/persist/home/org.chromium.Chromium",
|
||||
"shell": "/run/current-system/sw/bin/zsh",
|
||||
"sandbox": {
|
||||
"data": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"dir": "/data/data/org.chromium.Chromium",
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"identity": 9,
|
||||
"groups": [
|
||||
"video",
|
||||
"dialout",
|
||||
"plugdev"
|
||||
],
|
||||
"container": {
|
||||
"hostname": "localhost",
|
||||
"seccomp": 32,
|
||||
"devel": true,
|
||||
@ -558,57 +609,6 @@ func Test_printPs(t *testing.T) {
|
||||
"cover": [
|
||||
"/var/run/nscd"
|
||||
]
|
||||
},
|
||||
"extra_perms": [
|
||||
{
|
||||
"ensure": true,
|
||||
"path": "/var/lib/fortify/u0",
|
||||
"x": true
|
||||
},
|
||||
{
|
||||
"path": "/var/lib/fortify/u0/org.chromium.Chromium",
|
||||
"r": true,
|
||||
"w": true,
|
||||
"x": true
|
||||
}
|
||||
],
|
||||
"system_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.bluez",
|
||||
"org.freedesktop.Avahi",
|
||||
"org.freedesktop.UPower"
|
||||
],
|
||||
"own": null,
|
||||
"call": null,
|
||||
"broadcast": null,
|
||||
"filter": true
|
||||
},
|
||||
"session_bus": {
|
||||
"see": null,
|
||||
"talk": [
|
||||
"org.freedesktop.Notifications",
|
||||
"org.freedesktop.FileManager1",
|
||||
"org.freedesktop.ScreenSaver",
|
||||
"org.freedesktop.secrets",
|
||||
"org.kde.kwalletd5",
|
||||
"org.kde.kwalletd6",
|
||||
"org.gnome.SessionManager"
|
||||
],
|
||||
"own": [
|
||||
"org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||
"org.mpris.MediaPlayer2.chromium.*"
|
||||
],
|
||||
"call": {
|
||||
"org.freedesktop.portal.*": "*"
|
||||
},
|
||||
"broadcast": {
|
||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||
},
|
||||
"filter": true
|
||||
},
|
||||
"enablements": 13
|
||||
}
|
||||
},
|
||||
"time": "1970-01-01T00:00:00.000000009Z"
|
||||
|
@ -69,8 +69,8 @@ def check_state(name, enablements):
|
||||
if len(config['args']) != 1 or config['args'][0] != command:
|
||||
raise Exception(f"unexpected args {config['args']}")
|
||||
|
||||
if config['confinement']['enablements'] != enablements:
|
||||
raise Exception(f"unexpected enablements {instance['config']['confinement']['enablements']}")
|
||||
if config['enablements'] != enablements:
|
||||
raise Exception(f"unexpected enablements {instance['config']['enablements']}")
|
||||
|
||||
|
||||
def fortify(command):
|
||||
|
Loading…
Reference in New Issue
Block a user