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

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:
Ophestra 2025-04-13 03:23:28 +09:00
parent c460892cbd
commit 31b7ddd122
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
21 changed files with 833 additions and 831 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -10,7 +10,7 @@ buildPackage {
name = "foot";
inherit (foot) version;
app_id = 2;
identity = 2;
id = "org.codeberg.dnkl.foot";
modules = [

View File

@ -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()

View File

@ -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)
}

View File

@ -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"`

View File

@ -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"`

View File

@ -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,
},
}
}

View File

@ -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
}
}`

View File

@ -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
}

View File

@ -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,

View File

@ -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,

View File

@ -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)
}

View File

@ -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
View File

@ -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
}
}

View File

@ -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 ''

View File

@ -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]

View File

@ -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"

View File

@ -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):