Compare commits
9 Commits
d6cf736abf
...
6c1205106d
Author | SHA1 | Date | |
---|---|---|---|
6c1205106d | |||
2ffca6984a | |||
dde2516304 | |||
f30a439bcd | |||
008e9e7fc5 | |||
23aefcd759 | |||
cb8b886446 | |||
5979d8b1e0 | |||
e587112e63 |
50
README.md
50
README.md
@ -62,16 +62,27 @@ This adds the `environment.fortify` option:
|
|||||||
{
|
{
|
||||||
environment.fortify = {
|
environment.fortify = {
|
||||||
enable = true;
|
enable = true;
|
||||||
stateDir = "/var/lib/persist/module/fortify";
|
stateDir = "/var/lib/fortify";
|
||||||
users = {
|
users = {
|
||||||
alice = 0;
|
alice = 0;
|
||||||
nixos = 10;
|
nixos = 10;
|
||||||
};
|
};
|
||||||
|
|
||||||
apps = [
|
commonPaths = [
|
||||||
{
|
{
|
||||||
|
src = "/sdcard";
|
||||||
|
write = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
extraHomeConfig = {
|
||||||
|
home.stateVersion = "23.05";
|
||||||
|
};
|
||||||
|
|
||||||
|
apps = {
|
||||||
|
"org.chromium.Chromium" = {
|
||||||
name = "chromium";
|
name = "chromium";
|
||||||
id = "org.chromium.Chromium";
|
identity = 1;
|
||||||
packages = [ pkgs.chromium ];
|
packages = [ pkgs.chromium ];
|
||||||
userns = true;
|
userns = true;
|
||||||
mapRealUid = true;
|
mapRealUid = true;
|
||||||
@ -104,16 +115,20 @@ This adds the `environment.fortify` option:
|
|||||||
broadcast = { };
|
broadcast = { };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"org.claws_mail.Claws-Mail" = {
|
||||||
name = "claws-mail";
|
name = "claws-mail";
|
||||||
id = "org.claws_mail.Claws-Mail";
|
identity = 2;
|
||||||
packages = [ pkgs.claws-mail ];
|
packages = [ pkgs.claws-mail ];
|
||||||
gpu = false;
|
gpu = false;
|
||||||
capability.pulse = false;
|
capability.pulse = false;
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"org.weechat" = {
|
||||||
name = "weechat";
|
name = "weechat";
|
||||||
|
identity = 3;
|
||||||
|
shareUid = true;
|
||||||
packages = [ pkgs.weechat ];
|
packages = [ pkgs.weechat ];
|
||||||
capability = {
|
capability = {
|
||||||
wayland = false;
|
wayland = false;
|
||||||
@ -121,10 +136,12 @@ This adds the `environment.fortify` option:
|
|||||||
dbus = true;
|
dbus = true;
|
||||||
pulse = false;
|
pulse = false;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"dev.vencord.Vesktop" = {
|
||||||
name = "discord";
|
name = "discord";
|
||||||
id = "dev.vencord.Vesktop";
|
identity = 3;
|
||||||
|
shareUid = true;
|
||||||
packages = [ pkgs.vesktop ];
|
packages = [ pkgs.vesktop ];
|
||||||
share = pkgs.vesktop;
|
share = pkgs.vesktop;
|
||||||
command = "vesktop --ozone-platform-hint=wayland";
|
command = "vesktop --ozone-platform-hint=wayland";
|
||||||
@ -142,9 +159,12 @@ This adds the `environment.fortify` option:
|
|||||||
};
|
};
|
||||||
system.filter = true;
|
system.filter = true;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"io.looking-glass" = {
|
||||||
name = "looking-glass-client";
|
name = "looking-glass-client";
|
||||||
|
identity = 4;
|
||||||
|
useCommonPaths = false;
|
||||||
groups = [ "plugdev" ];
|
groups = [ "plugdev" ];
|
||||||
extraPaths = [
|
extraPaths = [
|
||||||
{
|
{
|
||||||
@ -155,8 +175,8 @@ This adds the `environment.fortify` option:
|
|||||||
extraConfig = {
|
extraConfig = {
|
||||||
programs.looking-glass-client.enable = true;
|
programs.looking-glass-client.enable = true;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
];
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -55,6 +55,8 @@
|
|||||||
stateDir = "/var/lib/fortify";
|
stateDir = "/var/lib/fortify";
|
||||||
users.alice = 0;
|
users.alice = 0;
|
||||||
|
|
||||||
home-manager = _: _: { home.stateVersion = "23.05"; };
|
extraHomeConfig = {
|
||||||
|
home.stateVersion = "23.05";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -7,24 +7,24 @@ _fortify_app() {
|
|||||||
|
|
||||||
_fortify_run() {
|
_fortify_run() {
|
||||||
_arguments \
|
_arguments \
|
||||||
'--id[App ID, leave empty to disable security context app_id]:id' \
|
'--id[Reverse-DNS style Application identifier, leave empty to inherit instance identifier]:id' \
|
||||||
'-a[Fortify application ID]: :_numbers' \
|
'-a[Application identity]: :_numbers' \
|
||||||
'-g[Groups inherited by the app process]: :_groups' \
|
'-g[Groups inherited by all container processes]: :_groups' \
|
||||||
'-d[Application home directory]: :_files -/' \
|
'-d[Container home directory]: :_files -/' \
|
||||||
'-u[Passwd name within sandbox]: :_users' \
|
'-u[Passwd user name within sandbox]: :_users' \
|
||||||
'--wayland[Share Wayland socket]' \
|
'--wayland[Enable connection to Wayland via security-context-v1]' \
|
||||||
'-X[Share X11 socket and allow connection]' \
|
'-X[Enable direct connection to X11]' \
|
||||||
'--dbus[Proxy D-Bus connection]' \
|
'--dbus[Enable proxied connection to D-Bus]' \
|
||||||
'--pulse[Share PulseAudio socket and cookie]' \
|
'--pulse[Enable direct connection to PulseAudio]' \
|
||||||
'--dbus-config[Path to D-Bus proxy config file]: :_files -g "*.json"' \
|
'--dbus-config[Path to session bus proxy config file]: :_files -g "*.json"' \
|
||||||
'--dbus-system[Path to system D-Bus proxy config file]: :_files -g "*.json"' \
|
'--dbus-system[Path to system bus proxy config file]: :_files -g "*.json"' \
|
||||||
'--mpris[Allow owning MPRIS D-Bus path]' \
|
'--mpris[Allow owning MPRIS D-Bus path]' \
|
||||||
'--dbus-log[Force logging in the D-Bus proxy]'
|
'--dbus-log[Force buffered logging in the D-Bus proxy]'
|
||||||
}
|
}
|
||||||
|
|
||||||
_fortify_ps() {
|
_fortify_ps() {
|
||||||
_arguments \
|
_arguments \
|
||||||
'--short[Print instance id]'
|
'--short[List instances only]'
|
||||||
}
|
}
|
||||||
|
|
||||||
_fortify_show() {
|
_fortify_show() {
|
||||||
@ -78,5 +78,5 @@ __fortify_instances() {
|
|||||||
|
|
||||||
_arguments -C \
|
_arguments -C \
|
||||||
'-v[Verbose output]' \
|
'-v[Verbose output]' \
|
||||||
'--json[Format output in JSON when applicable]' \
|
'--json[Serialise output in JSON when applicable]' \
|
||||||
'*::fortify command:_fortify_commands'
|
'*::fortify command:_fortify_commands'
|
@ -5,8 +5,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ProxyPair is an upstream dbus address and a downstream socket path.
|
||||||
|
type ProxyPair [2]string
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// See set 'see' policy for NAME (--see=NAME)
|
// See set 'see' policy for NAME (--see=NAME)
|
||||||
See []string `json:"see"`
|
See []string `json:"see"`
|
||||||
@ -24,7 +28,62 @@ type Config struct {
|
|||||||
Filter bool `json:"filter"`
|
Filter bool `json:"filter"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Args(bus [2]string) (args []string) {
|
func (c *Config) interfaces(yield func(string) bool) {
|
||||||
|
for _, iface := range c.See {
|
||||||
|
if !yield(iface) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, iface := range c.Talk {
|
||||||
|
if !yield(iface) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, iface := range c.Own {
|
||||||
|
if !yield(iface) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for iface := range c.Call {
|
||||||
|
if !yield(iface) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for iface := range c.Broadcast {
|
||||||
|
if !yield(iface) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) checkInterfaces(segment string) error {
|
||||||
|
for iface := range c.interfaces {
|
||||||
|
/*
|
||||||
|
xdg-dbus-proxy fails without output when this condition is not met:
|
||||||
|
char *dot = strrchr (filter->interface, '.');
|
||||||
|
if (dot != NULL)
|
||||||
|
{
|
||||||
|
*dot = 0;
|
||||||
|
if (strcmp (dot + 1, "*") != 0)
|
||||||
|
filter->member = g_strdup (dot + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
trim ".*" since they are removed before searching for '.':
|
||||||
|
if (g_str_has_suffix (name, ".*"))
|
||||||
|
{
|
||||||
|
name[strlen (name) - 2] = 0;
|
||||||
|
wildcard = TRUE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if strings.IndexByte(strings.TrimSuffix(iface, ".*"), '.') == -1 {
|
||||||
|
return &BadInterfaceError{iface, segment}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) Args(bus ProxyPair) (args []string) {
|
||||||
argc := 2 + len(c.See) + len(c.Talk) + len(c.Own) + len(c.Call) + len(c.Broadcast)
|
argc := 2 + len(c.See) + len(c.Talk) + len(c.Own) + len(c.Call) + len(c.Broadcast)
|
||||||
if c.Log {
|
if c.Log {
|
||||||
argc++
|
argc++
|
||||||
@ -60,9 +119,7 @@ func (c *Config) Args(bus [2]string) (args []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) Load(r io.Reader) error {
|
func (c *Config) Load(r io.Reader) error { return json.NewDecoder(r).Decode(&c) }
|
||||||
return json.NewDecoder(r).Decode(&c)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewConfigFromFile opens the target config file at path and parses its contents into *Config.
|
// NewConfigFromFile opens the target config file at path and parses its contents into *Config.
|
||||||
func NewConfigFromFile(path string) (*Config, error) {
|
func NewConfigFromFile(path string) (*Config, error) {
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
@ -19,64 +20,21 @@ import (
|
|||||||
"git.gensokyo.uk/security/fortify/sandbox"
|
"git.gensokyo.uk/security/fortify/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNew(t *testing.T) {
|
func TestFinalise(t *testing.T) {
|
||||||
for _, tc := range [][2][2]string{
|
if _, err := dbus.Finalise(dbus.ProxyPair{}, dbus.ProxyPair{}, nil, nil); !errors.Is(err, syscall.EBADE) {
|
||||||
{
|
t.Errorf("Finalise: error = %v, want %v",
|
||||||
{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/1ca5d183ef4c99e74c3e544715f32702/bus"},
|
err, syscall.EBADE)
|
||||||
{"unix:path=/run/dbus/system_bus_socket", "/tmp/fortify.1971/1ca5d183ef4c99e74c3e544715f32702/system_bus_socket"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/881ac3796ff3f3bf0a773824383187a0/bus"},
|
|
||||||
{"unix:path=/run/dbus/system_bus_socket", "/tmp/fortify.1971/881ac3796ff3f3bf0a773824383187a0/system_bus_socket"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/3d1a5084520ef79c0c6a49a675bac701/bus"},
|
|
||||||
{"unix:path=/run/dbus/system_bus_socket", "/tmp/fortify.1971/3d1a5084520ef79c0c6a49a675bac701/system_bus_socket"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{"unix:path=/run/user/1971/bus", "/tmp/fortify.1971/2a1639bab712799788ea0ff7aa280c35/bus"},
|
|
||||||
{"unix:path=/run/dbus/system_bus_socket", "/tmp/fortify.1971/2a1639bab712799788ea0ff7aa280c35/system_bus_socket"},
|
|
||||||
},
|
|
||||||
} {
|
|
||||||
t.Run("create instance for "+tc[0][0]+" and "+tc[1][0], func(t *testing.T) {
|
|
||||||
if got := dbus.New(tc[0], tc[1]); !got.CompareTestNew(tc[0], tc[1]) {
|
|
||||||
t.Errorf("New(%q, %q) = %v",
|
|
||||||
tc[0], tc[1],
|
|
||||||
got)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestProxy_Seal(t *testing.T) {
|
|
||||||
t.Run("double seal panic", func(t *testing.T) {
|
|
||||||
defer func() {
|
|
||||||
want := "dbus proxy sealed twice"
|
|
||||||
if r := recover(); r != want {
|
|
||||||
t.Errorf("Seal: panic = %q, want %q",
|
|
||||||
r, want)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
p := dbus.New([2]string{}, [2]string{})
|
|
||||||
_ = p.Seal(dbus.NewConfig("", true, false), nil)
|
|
||||||
_ = p.Seal(dbus.NewConfig("", true, false), nil)
|
|
||||||
})
|
|
||||||
|
|
||||||
ep := dbus.New([2]string{}, [2]string{})
|
|
||||||
if err := ep.Seal(nil, nil); !errors.Is(err, dbus.ErrConfig) {
|
|
||||||
t.Errorf("Seal(nil, nil) error = %v, want %v",
|
|
||||||
err, dbus.ErrConfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for id, tc := range testCasePairs() {
|
for id, tc := range testCasePairs() {
|
||||||
t.Run("create seal for "+id, func(t *testing.T) {
|
t.Run("create final for "+id, func(t *testing.T) {
|
||||||
p := dbus.New(tc[0].bus, tc[1].bus)
|
var wt io.WriterTo
|
||||||
if err := p.Seal(tc[0].c, tc[1].c); (errors.Is(err, syscall.EINVAL)) != tc[0].wantErr {
|
if v, err := dbus.Finalise(tc[0].bus, tc[1].bus, tc[0].c, tc[1].c); (errors.Is(err, syscall.EINVAL)) != tc[0].wantErr {
|
||||||
t.Errorf("Seal(%p, %p) error = %v, wantErr %v",
|
t.Errorf("Finalise: error = %v, wantErr %v",
|
||||||
tc[0].c, tc[1].c,
|
|
||||||
err, tc[0].wantErr)
|
err, tc[0].wantErr)
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
wt = v
|
||||||
}
|
}
|
||||||
|
|
||||||
// rest of the tests happen for sealed instances
|
// rest of the tests happen for sealed instances
|
||||||
@ -89,25 +47,23 @@ func TestProxy_Seal(t *testing.T) {
|
|||||||
args := append(tc[0].want, tc[1].want...)
|
args := append(tc[0].want, tc[1].want...)
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
want.WriteString(arg)
|
want.WriteString(arg)
|
||||||
want.WriteByte('\x00')
|
want.WriteByte(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
wt := p.AccessTestProxySeal()
|
|
||||||
got := new(strings.Builder)
|
got := new(strings.Builder)
|
||||||
if _, err := wt.WriteTo(got); err != nil {
|
if _, err := wt.WriteTo(got); err != nil {
|
||||||
t.Errorf("p.seal.WriteTo(): %v", err)
|
t.Errorf("WriteTo: error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if want.String() != got.String() {
|
if want.String() != got.String() {
|
||||||
t.Errorf("Seal(%p, %p) seal = %v, want %v",
|
t.Errorf("Seal: %q, want %q",
|
||||||
tc[0].c, tc[1].c,
|
|
||||||
got.String(), want.String())
|
got.String(), want.String())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProxy_Start_Wait_Close_String(t *testing.T) {
|
func TestProxyStartWaitCloseString(t *testing.T) {
|
||||||
oldWaitDelay := helper.WaitDelay
|
oldWaitDelay := helper.WaitDelay
|
||||||
helper.WaitDelay = 16 * time.Second
|
helper.WaitDelay = 16 * time.Second
|
||||||
t.Cleanup(func() { helper.WaitDelay = oldWaitDelay })
|
t.Cleanup(func() { helper.WaitDelay = oldWaitDelay })
|
||||||
@ -116,29 +72,62 @@ func TestProxy_Start_Wait_Close_String(t *testing.T) {
|
|||||||
proxyName := dbus.ProxyName
|
proxyName := dbus.ProxyName
|
||||||
dbus.ProxyName = os.Args[0]
|
dbus.ProxyName = os.Args[0]
|
||||||
t.Cleanup(func() { dbus.ProxyName = proxyName })
|
t.Cleanup(func() { dbus.ProxyName = proxyName })
|
||||||
testProxyStartWaitCloseString(t, true)
|
testProxyFinaliseStartWaitCloseString(t, true)
|
||||||
})
|
})
|
||||||
t.Run("direct", func(t *testing.T) { testProxyStartWaitCloseString(t, false) })
|
t.Run("direct", func(t *testing.T) { testProxyFinaliseStartWaitCloseString(t, false) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProxyStartWaitCloseString(t *testing.T, useSandbox bool) {
|
func testProxyFinaliseStartWaitCloseString(t *testing.T, useSandbox bool) {
|
||||||
|
var p *dbus.Proxy
|
||||||
|
|
||||||
|
t.Run("string for nil proxy", func(t *testing.T) {
|
||||||
|
want := "(invalid dbus proxy)"
|
||||||
|
if got := p.String(); got != want {
|
||||||
|
t.Errorf("String: %q, want %q",
|
||||||
|
got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("invalid start", func(t *testing.T) {
|
||||||
|
if !useSandbox {
|
||||||
|
p = dbus.NewDirect(context.TODO(), nil, nil)
|
||||||
|
} else {
|
||||||
|
p = dbus.New(context.TODO(), nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.Start(); !errors.Is(err, syscall.ENOTRECOVERABLE) {
|
||||||
|
t.Errorf("Start: error = %q, wantErr %q",
|
||||||
|
err, syscall.ENOTRECOVERABLE)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
for id, tc := range testCasePairs() {
|
for id, tc := range testCasePairs() {
|
||||||
// this test does not test errors
|
// this test does not test errors
|
||||||
if tc[0].wantErr {
|
if tc[0].wantErr {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("string for nil proxy", func(t *testing.T) {
|
|
||||||
var p *dbus.Proxy
|
|
||||||
want := "(invalid dbus proxy)"
|
|
||||||
if got := p.String(); got != want {
|
|
||||||
t.Errorf("String() = %v, want %v",
|
|
||||||
got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("proxy for "+id, func(t *testing.T) {
|
t.Run("proxy for "+id, func(t *testing.T) {
|
||||||
p := dbus.New(tc[0].bus, tc[1].bus)
|
var final *dbus.Final
|
||||||
|
t.Run("finalise", func(t *testing.T) {
|
||||||
|
if v, err := dbus.Finalise(tc[0].bus, tc[1].bus, tc[0].c, tc[1].c); err != nil {
|
||||||
|
t.Errorf("Finalise: error = %v, wantErr %v",
|
||||||
|
err, tc[0].wantErr)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
final = v
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if !useSandbox {
|
||||||
|
p = dbus.NewDirect(ctx, final, nil)
|
||||||
|
} else {
|
||||||
|
p = dbus.New(ctx, final, nil)
|
||||||
|
}
|
||||||
|
|
||||||
p.CommandContext = func(ctx context.Context) (cmd *exec.Cmd) {
|
p.CommandContext = func(ctx context.Context) (cmd *exec.Cmd) {
|
||||||
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
||||||
"-test.run=TestHelperInit", "--", "init")
|
"-test.run=TestHelperInit", "--", "init")
|
||||||
@ -163,79 +152,52 @@ func testProxyStartWaitCloseString(t *testing.T, useSandbox bool) {
|
|||||||
p.FilterF = func(v []byte) []byte { return bytes.SplitN(v, []byte("TestHelperInit\n"), 2)[1] }
|
p.FilterF = func(v []byte) []byte { return bytes.SplitN(v, []byte("TestHelperInit\n"), 2)[1] }
|
||||||
output := new(strings.Builder)
|
output := new(strings.Builder)
|
||||||
|
|
||||||
t.Run("unsealed", func(t *testing.T) {
|
t.Run("invalid wait", func(t *testing.T) {
|
||||||
t.Run("string", func(t *testing.T) {
|
wantErr := "dbus: not started"
|
||||||
want := "(unsealed dbus proxy)"
|
if err := p.Wait(); err == nil || err.Error() != wantErr {
|
||||||
if got := p.String(); got != want {
|
t.Errorf("Wait: error = %v, wantErr %v",
|
||||||
t.Errorf("String() = %v, want %v",
|
err, wantErr)
|
||||||
got, want)
|
}
|
||||||
return
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("start", func(t *testing.T) {
|
t.Run("string", func(t *testing.T) {
|
||||||
want := "proxy not sealed"
|
want := "(unused dbus proxy)"
|
||||||
if err := p.Start(context.Background(), nil, useSandbox); err == nil || err.Error() != want {
|
if got := p.String(); got != want {
|
||||||
t.Errorf("Start() error = %v, wantErr %q",
|
t.Errorf("String: %q, want %q",
|
||||||
err, errors.New(want))
|
got, want)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("start", func(t *testing.T) {
|
||||||
|
if err := p.Start(); err != nil {
|
||||||
|
t.Fatalf("Start: error = %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("string", func(t *testing.T) {
|
||||||
|
wantSubstr := fmt.Sprintf("%s -test.run=TestHelperStub -- --args=3 --fd=4", os.Args[0])
|
||||||
|
if useSandbox {
|
||||||
|
wantSubstr = fmt.Sprintf(`argv: ["%s" "-test.run=TestHelperStub" "--" "--args=3" "--fd=4"], flags: 0x0, seccomp: 0x3e`, os.Args[0])
|
||||||
|
}
|
||||||
|
if got := p.String(); !strings.Contains(got, wantSubstr) {
|
||||||
|
t.Errorf("String: %q, want %q",
|
||||||
|
got, wantSubstr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("wait", func(t *testing.T) {
|
t.Run("wait", func(t *testing.T) {
|
||||||
wantErr := "dbus: not started"
|
done := make(chan struct{})
|
||||||
if err := p.Wait(); err == nil || err.Error() != wantErr {
|
go func() {
|
||||||
t.Errorf("Wait() error = %v, wantErr %v",
|
|
||||||
err, wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("seal with "+id, func(t *testing.T) {
|
|
||||||
if err := p.Seal(tc[0].c, tc[1].c); err != nil {
|
|
||||||
t.Errorf("Seal(%p, %p) error = %v, wantErr %v",
|
|
||||||
tc[0].c, tc[1].c,
|
|
||||||
err, tc[0].wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("sealed", func(t *testing.T) {
|
|
||||||
want := strings.Join(append(tc[0].want, tc[1].want...), " ")
|
|
||||||
if got := p.String(); got != want {
|
|
||||||
t.Errorf("String() = %v, want %v",
|
|
||||||
got, want)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("start", func(t *testing.T) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
if err := p.Start(ctx, output, useSandbox); err != nil {
|
|
||||||
t.Fatalf("Start(nil, nil) error = %v",
|
|
||||||
err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("string", func(t *testing.T) {
|
|
||||||
wantSubstr := fmt.Sprintf("%s -test.run=TestHelperStub -- --args=3 --fd=4", os.Args[0])
|
|
||||||
if useSandbox {
|
|
||||||
wantSubstr = fmt.Sprintf(`argv: ["%s" "-test.run=TestHelperStub" "--" "--args=3" "--fd=4"], flags: 0x0, seccomp: 0x3e`, os.Args[0])
|
|
||||||
}
|
|
||||||
if got := p.String(); !strings.Contains(got, wantSubstr) {
|
|
||||||
t.Errorf("String() = %v, want %v",
|
|
||||||
p.String(), wantSubstr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("wait", func(t *testing.T) {
|
|
||||||
p.Close()
|
|
||||||
if err := p.Wait(); err != nil {
|
if err := p.Wait(); err != nil {
|
||||||
t.Errorf("Wait() error = %v\noutput: %s",
|
t.Errorf("Wait: error = %v\noutput: %s",
|
||||||
err, output.String())
|
err, output.String())
|
||||||
}
|
}
|
||||||
})
|
close(done)
|
||||||
|
}()
|
||||||
|
p.Close()
|
||||||
|
<-done
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package dbus
|
package dbus
|
||||||
|
|
||||||
import "io"
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
// CompareTestNew provides TestNew with comparison access to unexported Proxy fields.
|
// NewDirect returns a new instance of [Proxy] with its sandbox disabled.
|
||||||
func (p *Proxy) CompareTestNew(session, system [2]string) bool {
|
func NewDirect(ctx context.Context, final *Final, output io.Writer) *Proxy {
|
||||||
return session == p.session && system == p.system
|
p := New(ctx, final, output)
|
||||||
}
|
p.useSandbox = false
|
||||||
|
return p
|
||||||
// AccessTestProxySeal provides TestProxy_Seal with access to unexported Proxy seal field.
|
|
||||||
func (p *Proxy) AccessTestProxySeal() io.WriterTo {
|
|
||||||
return p.seal
|
|
||||||
}
|
}
|
||||||
|
94
dbus/proc.go
94
dbus/proc.go
@ -3,14 +3,12 @@ package dbus
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/fortify/helper"
|
||||||
@ -19,25 +17,30 @@ import (
|
|||||||
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
"git.gensokyo.uk/security/fortify/sandbox/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Start launches the D-Bus proxy.
|
// Start starts and configures a D-Bus proxy process.
|
||||||
func (p *Proxy) Start(ctx context.Context, output io.Writer, useSandbox bool) error {
|
func (p *Proxy) Start() error {
|
||||||
p.lock.Lock()
|
if p.final == nil || p.final.WriterTo == nil {
|
||||||
defer p.lock.Unlock()
|
return syscall.ENOTRECOVERABLE
|
||||||
|
|
||||||
if p.seal == nil {
|
|
||||||
return errors.New("proxy not sealed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var h helper.Helper
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
p.pmu.Lock()
|
||||||
|
defer p.pmu.Unlock()
|
||||||
|
|
||||||
c, cancel := context.WithCancelCause(ctx)
|
if p.cancel != nil || p.cause != nil {
|
||||||
if !useSandbox {
|
return errors.New("dbus: already started")
|
||||||
h = helper.NewDirect(c, p.name, p.seal, true, argF, func(cmd *exec.Cmd) {
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancelCause(p.ctx)
|
||||||
|
|
||||||
|
if !p.useSandbox {
|
||||||
|
p.helper = helper.NewDirect(ctx, p.name, p.final, true, argF, func(cmd *exec.Cmd) {
|
||||||
if p.CmdF != nil {
|
if p.CmdF != nil {
|
||||||
p.CmdF(cmd)
|
p.CmdF(cmd)
|
||||||
}
|
}
|
||||||
if output != nil {
|
if p.output != nil {
|
||||||
cmd.Stdout, cmd.Stderr = output, output
|
cmd.Stdout, cmd.Stderr = p.output, p.output
|
||||||
}
|
}
|
||||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
|
||||||
cmd.Env = make([]string, 0)
|
cmd.Env = make([]string, 0)
|
||||||
@ -59,15 +62,15 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, useSandbox bool) er
|
|||||||
libPaths = ldd.Path(entries)
|
libPaths = ldd.Path(entries)
|
||||||
}
|
}
|
||||||
|
|
||||||
h = helper.New(
|
p.helper = helper.New(
|
||||||
c, toolPath,
|
ctx, toolPath,
|
||||||
p.seal, true,
|
p.final, true,
|
||||||
argF, func(container *sandbox.Container) {
|
argF, func(container *sandbox.Container) {
|
||||||
container.Seccomp |= seccomp.FilterMultiarch
|
container.Seccomp |= seccomp.FilterMultiarch
|
||||||
container.Hostname = "fortify-dbus"
|
container.Hostname = "fortify-dbus"
|
||||||
container.CommandContext = p.CommandContext
|
container.CommandContext = p.CommandContext
|
||||||
if output != nil {
|
if p.output != nil {
|
||||||
container.Stdout, container.Stderr = output, output
|
container.Stdout, container.Stderr = p.output, p.output
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.CmdF != nil {
|
if p.CmdF != nil {
|
||||||
@ -81,10 +84,17 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, useSandbox bool) er
|
|||||||
|
|
||||||
// upstream bus directories
|
// upstream bus directories
|
||||||
upstreamPaths := make([]string, 0, 2)
|
upstreamPaths := make([]string, 0, 2)
|
||||||
for _, as := range []string{p.session[0], p.system[0]} {
|
for _, addr := range [][]AddrEntry{p.final.SessionUpstream, p.final.SystemUpstream} {
|
||||||
if len(as) > 0 && strings.HasPrefix(as, "unix:path=/") {
|
for _, ent := range addr {
|
||||||
// leave / intact
|
if ent.Method != "unix" {
|
||||||
upstreamPaths = append(upstreamPaths, path.Dir(as[10:]))
|
continue
|
||||||
|
}
|
||||||
|
for _, pair := range ent.Values {
|
||||||
|
if pair[0] != "path" || !path.IsAbs(pair[1]) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
upstreamPaths = append(upstreamPaths, path.Dir(pair[1]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slices.Sort(upstreamPaths)
|
slices.Sort(upstreamPaths)
|
||||||
@ -95,10 +105,10 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, useSandbox bool) er
|
|||||||
|
|
||||||
// parent directories of bind paths
|
// parent directories of bind paths
|
||||||
sockDirPaths := make([]string, 0, 2)
|
sockDirPaths := make([]string, 0, 2)
|
||||||
if d := path.Dir(p.session[1]); path.IsAbs(d) {
|
if d := path.Dir(p.final.Session[1]); path.IsAbs(d) {
|
||||||
sockDirPaths = append(sockDirPaths, d)
|
sockDirPaths = append(sockDirPaths, d)
|
||||||
}
|
}
|
||||||
if d := path.Dir(p.system[1]); path.IsAbs(d) {
|
if d := path.Dir(p.final.System[1]); path.IsAbs(d) {
|
||||||
sockDirPaths = append(sockDirPaths, d)
|
sockDirPaths = append(sockDirPaths, d)
|
||||||
}
|
}
|
||||||
slices.Sort(sockDirPaths)
|
slices.Sort(sockDirPaths)
|
||||||
@ -113,14 +123,13 @@ func (p *Proxy) Start(ctx context.Context, output io.Writer, useSandbox bool) er
|
|||||||
}, nil)
|
}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.Start(); err != nil {
|
if err := p.helper.Start(); err != nil {
|
||||||
cancel(err)
|
cancel(err)
|
||||||
|
p.helper = nil
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p.helper = h
|
p.cancel, p.cause = cancel, func() error { return context.Cause(ctx) }
|
||||||
p.ctx = c
|
|
||||||
p.cancel = cancel
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,28 +137,30 @@ var proxyClosed = errors.New("proxy closed")
|
|||||||
|
|
||||||
// Wait blocks until xdg-dbus-proxy exits and releases resources.
|
// Wait blocks until xdg-dbus-proxy exits and releases resources.
|
||||||
func (p *Proxy) Wait() error {
|
func (p *Proxy) Wait() error {
|
||||||
p.lock.RLock()
|
p.mu.RLock()
|
||||||
defer p.lock.RUnlock()
|
defer p.mu.RUnlock()
|
||||||
|
|
||||||
if p.helper == nil {
|
p.pmu.RLock()
|
||||||
|
if p.helper == nil || p.cancel == nil || p.cause == nil {
|
||||||
|
p.pmu.RUnlock()
|
||||||
return errors.New("dbus: not started")
|
return errors.New("dbus: not started")
|
||||||
}
|
}
|
||||||
|
|
||||||
errs := make([]error, 3)
|
errs := make([]error, 3)
|
||||||
|
|
||||||
errs[0] = p.helper.Wait()
|
errs[0] = p.helper.Wait()
|
||||||
if p.cancel == nil &&
|
if errors.Is(errs[0], context.Canceled) &&
|
||||||
errors.Is(errs[0], context.Canceled) &&
|
errors.Is(p.cause(), proxyClosed) {
|
||||||
errors.Is(context.Cause(p.ctx), proxyClosed) {
|
|
||||||
errs[0] = nil
|
errs[0] = nil
|
||||||
}
|
}
|
||||||
|
p.pmu.RUnlock()
|
||||||
|
|
||||||
// ensure socket removal so ephemeral directory is empty at revert
|
// ensure socket removal so ephemeral directory is empty at revert
|
||||||
if err := os.Remove(p.session[1]); err != nil && !errors.Is(err, os.ErrNotExist) {
|
if err := os.Remove(p.final.Session[1]); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
errs[1] = err
|
errs[1] = err
|
||||||
}
|
}
|
||||||
if p.sysP {
|
if p.final.System[1] != "" {
|
||||||
if err := os.Remove(p.system[1]); err != nil && !errors.Is(err, os.ErrNotExist) {
|
if err := os.Remove(p.final.System[1]); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||||
errs[2] = err
|
errs[2] = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,14 +170,13 @@ func (p *Proxy) Wait() error {
|
|||||||
|
|
||||||
// Close cancels the context passed to the helper instance attached to xdg-dbus-proxy.
|
// Close cancels the context passed to the helper instance attached to xdg-dbus-proxy.
|
||||||
func (p *Proxy) Close() {
|
func (p *Proxy) Close() {
|
||||||
p.lock.Lock()
|
p.pmu.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.pmu.Unlock()
|
||||||
|
|
||||||
if p.cancel == nil {
|
if p.cancel == nil {
|
||||||
panic("dbus: not started")
|
panic("dbus: not started")
|
||||||
}
|
}
|
||||||
p.cancel(proxyClosed)
|
p.cancel(proxyClosed)
|
||||||
p.cancel = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func argF(argsFd, statFd int) []string {
|
func argF(argsFd, statFd int) []string {
|
||||||
|
113
dbus/proxy.go
113
dbus/proxy.go
@ -2,11 +2,11 @@ package dbus
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/helper"
|
"git.gensokyo.uk/security/fortify/helper"
|
||||||
)
|
)
|
||||||
@ -15,84 +15,103 @@ import (
|
|||||||
// Overriding ProxyName will only affect Proxy instance created after the change.
|
// Overriding ProxyName will only affect Proxy instance created after the change.
|
||||||
var ProxyName = "xdg-dbus-proxy"
|
var ProxyName = "xdg-dbus-proxy"
|
||||||
|
|
||||||
// Proxy holds references to a xdg-dbus-proxy process, and should never be copied.
|
type BadInterfaceError struct {
|
||||||
// Once sealed, configuration changes will no longer be possible and attempting to do so will result in a panic.
|
Interface string
|
||||||
|
Segment string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *BadInterfaceError) Error() string {
|
||||||
|
return fmt.Sprintf("bad interface string %q in %s bus configuration", e.Interface, e.Segment)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Proxy holds the state of a xdg-dbus-proxy process, and should never be copied.
|
||||||
type Proxy struct {
|
type Proxy struct {
|
||||||
helper helper.Helper
|
helper helper.Helper
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelCauseFunc
|
|
||||||
|
|
||||||
name string
|
cancel context.CancelCauseFunc
|
||||||
session [2]string
|
cause func() error
|
||||||
system [2]string
|
|
||||||
CmdF func(any)
|
final *Final
|
||||||
sysP bool
|
output io.Writer
|
||||||
|
useSandbox bool
|
||||||
|
|
||||||
|
name string
|
||||||
|
CmdF func(any)
|
||||||
|
|
||||||
CommandContext func(ctx context.Context) (cmd *exec.Cmd)
|
CommandContext func(ctx context.Context) (cmd *exec.Cmd)
|
||||||
FilterF func([]byte) []byte
|
FilterF func([]byte) []byte
|
||||||
|
|
||||||
seal io.WriterTo
|
mu, pmu sync.RWMutex
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proxy) Session() [2]string { return p.session }
|
|
||||||
func (p *Proxy) System() [2]string { return p.system }
|
|
||||||
func (p *Proxy) Sealed() bool { p.lock.RLock(); defer p.lock.RUnlock(); return p.seal != nil }
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrConfig = errors.New("no configuration to seal")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p *Proxy) String() string {
|
func (p *Proxy) String() string {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return "(invalid dbus proxy)"
|
return "(invalid dbus proxy)"
|
||||||
}
|
}
|
||||||
|
|
||||||
p.lock.RLock()
|
p.mu.RLock()
|
||||||
defer p.lock.RUnlock()
|
defer p.mu.RUnlock()
|
||||||
|
|
||||||
if p.helper != nil {
|
if p.helper != nil {
|
||||||
return p.helper.String()
|
return p.helper.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.seal != nil {
|
return "(unused dbus proxy)"
|
||||||
return p.seal.(fmt.Stringer).String()
|
|
||||||
}
|
|
||||||
|
|
||||||
return "(unsealed dbus proxy)"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seal seals the Proxy instance.
|
// Final describes the outcome of a proxy configuration.
|
||||||
func (p *Proxy) Seal(session, system *Config) error {
|
type Final struct {
|
||||||
p.lock.Lock()
|
Session, System ProxyPair
|
||||||
defer p.lock.Unlock()
|
// parsed upstream address
|
||||||
|
SessionUpstream, SystemUpstream []AddrEntry
|
||||||
if p.seal != nil {
|
io.WriterTo
|
||||||
panic("dbus proxy sealed twice")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Finalise creates a checked argument writer for [Proxy].
|
||||||
|
func Finalise(sessionBus, systemBus ProxyPair, session, system *Config) (final *Final, err error) {
|
||||||
if session == nil && system == nil {
|
if session == nil && system == nil {
|
||||||
return ErrConfig
|
return nil, syscall.EBADE
|
||||||
}
|
}
|
||||||
|
|
||||||
var args []string
|
var args []string
|
||||||
if session != nil {
|
if session != nil {
|
||||||
args = append(args, session.Args(p.session)...)
|
if err = session.checkInterfaces("session"); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args = append(args, session.Args(sessionBus)...)
|
||||||
}
|
}
|
||||||
if system != nil {
|
if system != nil {
|
||||||
args = append(args, system.Args(p.system)...)
|
if err = system.checkInterfaces("system"); err != nil {
|
||||||
p.sysP = true
|
return
|
||||||
}
|
}
|
||||||
if seal, err := helper.NewCheckedArgs(args); err != nil {
|
args = append(args, system.Args(systemBus)...)
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
p.seal = seal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
final = &Final{Session: sessionBus, System: systemBus}
|
||||||
|
|
||||||
|
final.WriterTo, err = helper.NewCheckedArgs(args)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if session != nil {
|
||||||
|
final.SessionUpstream, err = Parse([]byte(final.Session[0]))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if system != nil {
|
||||||
|
final.SystemUpstream, err = Parse([]byte(final.System[0]))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a reference to a new unsealed Proxy.
|
// New returns a new instance of [Proxy].
|
||||||
func New(session, system [2]string) *Proxy {
|
func New(ctx context.Context, final *Final, output io.Writer) *Proxy {
|
||||||
return &Proxy{name: ProxyName, session: session, system: system}
|
return &Proxy{name: ProxyName, ctx: ctx, final: final, output: output, useSandbox: true}
|
||||||
}
|
}
|
||||||
|
12
flake.lock
generated
12
flake.lock
generated
@ -7,11 +7,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1742655702,
|
"lastModified": 1746171682,
|
||||||
"narHash": "sha256-jbqlw4sPArFtNtA1s3kLg7/A4fzP4GLk9bGbtUJg0JQ=",
|
"narHash": "sha256-EyXUNSa+H+YvGVuQJP1nZskXAowxKYp79RNUsNdQTj4=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "0948aeedc296f964140d9429223c7e4a0702a1ff",
|
"rev": "50eee705bbdbac942074a8c120e8194185633675",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -23,11 +23,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1743231893,
|
"lastModified": 1746557022,
|
||||||
"narHash": "sha256-tpJsHMUPEhEnzySoQxx7+kA+KUtgWqvlcUBqROYNNt0=",
|
"narHash": "sha256-QkNoyEf6TbaTW5UZYX0OkwIJ/ZMeKSSoOMnSDPQuol0=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c570c1f5304493cafe133b8d843c7c1c4a10d3a6",
|
"rev": "1d3aeb5a193b9ff13f63f4d9cc169fb88129f860",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
26
main.go
26
main.go
@ -72,7 +72,7 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
return nil
|
return nil
|
||||||
}).
|
}).
|
||||||
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
|
Flag(&flagVerbose, "v", command.BoolFlag(false), "Print debug messages to the console").
|
||||||
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output as JSON when applicable")
|
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
|
||||||
|
|
||||||
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
|
c.Command("shim", command.UsageInternal, func([]string) error { instance.ShimMain(); return errSuccess })
|
||||||
|
|
||||||
@ -205,31 +205,31 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}).
|
}).
|
||||||
Flag(&dbusConfigSession, "dbus-config", command.StringFlag("builtin"),
|
Flag(&dbusConfigSession, "dbus-config", command.StringFlag("builtin"),
|
||||||
"Path to D-Bus proxy config file, or \"builtin\" for defaults").
|
"Path to session bus proxy config file, or \"builtin\" for defaults").
|
||||||
Flag(&dbusConfigSystem, "dbus-system", command.StringFlag("nil"),
|
Flag(&dbusConfigSystem, "dbus-system", command.StringFlag("nil"),
|
||||||
"Path to system D-Bus proxy config file, or \"nil\" to disable").
|
"Path to system bus proxy config file, or \"nil\" to disable").
|
||||||
Flag(&mpris, "mpris", command.BoolFlag(false),
|
Flag(&mpris, "mpris", command.BoolFlag(false),
|
||||||
"Allow owning MPRIS D-Bus path, has no effect if custom config is available").
|
"Allow owning MPRIS D-Bus path, has no effect if custom config is available").
|
||||||
Flag(&dbusVerbose, "dbus-log", command.BoolFlag(false),
|
Flag(&dbusVerbose, "dbus-log", command.BoolFlag(false),
|
||||||
"Force logging in the D-Bus proxy").
|
"Force buffered logging in the D-Bus proxy").
|
||||||
Flag(&fid, "id", command.StringFlag(""),
|
Flag(&fid, "id", command.StringFlag(""),
|
||||||
"App ID, leave empty to disable security context app_id").
|
"Reverse-DNS style Application identifier, leave empty to inherit instance identifier").
|
||||||
Flag(&aid, "a", command.IntFlag(0),
|
Flag(&aid, "a", command.IntFlag(0),
|
||||||
"Fortify application ID").
|
"Application identity").
|
||||||
Flag(nil, "g", &groups,
|
Flag(nil, "g", &groups,
|
||||||
"Groups inherited by the app process").
|
"Groups inherited by all container processes").
|
||||||
Flag(&homeDir, "d", command.StringFlag("os"),
|
Flag(&homeDir, "d", command.StringFlag("os"),
|
||||||
"Application home directory").
|
"Container home directory").
|
||||||
Flag(&userName, "u", command.StringFlag("chronos"),
|
Flag(&userName, "u", command.StringFlag("chronos"),
|
||||||
"Passwd name within sandbox").
|
"Passwd user name within sandbox").
|
||||||
Flag(&wayland, "wayland", command.BoolFlag(false),
|
Flag(&wayland, "wayland", command.BoolFlag(false),
|
||||||
"Allow Wayland connections").
|
"Enable connection to Wayland via security-context-v1").
|
||||||
Flag(&x11, "X", command.BoolFlag(false),
|
Flag(&x11, "X", command.BoolFlag(false),
|
||||||
"Share X11 socket and allow connection").
|
"Enable direct connection to X11").
|
||||||
Flag(&dBus, "dbus", command.BoolFlag(false),
|
Flag(&dBus, "dbus", command.BoolFlag(false),
|
||||||
"Proxy D-Bus connection").
|
"Enable proxied connection to D-Bus").
|
||||||
Flag(&pulse, "pulse", command.BoolFlag(false),
|
Flag(&pulse, "pulse", command.BoolFlag(false),
|
||||||
"Share PulseAudio socket and cookie")
|
"Enable direct connection to PulseAudio")
|
||||||
}
|
}
|
||||||
|
|
||||||
var showFlagShort bool
|
var showFlagShort bool
|
||||||
|
24
main_test.go
24
main_test.go
@ -36,31 +36,31 @@ Commands:
|
|||||||
Usage: fortify run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--wayland] [-X] [--dbus] [--pulse] COMMAND [OPTIONS]
|
Usage: fortify run [-h | --help] [--dbus-config <value>] [--dbus-system <value>] [--mpris] [--dbus-log] [--id <value>] [-a <int>] [-g <value>] [-d <value>] [-u <value>] [--wayland] [-X] [--dbus] [--pulse] COMMAND [OPTIONS]
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
-X Share X11 socket and allow connection
|
-X Enable direct connection to X11
|
||||||
-a int
|
-a int
|
||||||
Fortify application ID
|
Application identity
|
||||||
-d string
|
-d string
|
||||||
Application home directory (default "os")
|
Container home directory (default "os")
|
||||||
-dbus
|
-dbus
|
||||||
Proxy D-Bus connection
|
Enable proxied connection to D-Bus
|
||||||
-dbus-config string
|
-dbus-config string
|
||||||
Path to D-Bus proxy config file, or "builtin" for defaults (default "builtin")
|
Path to session bus proxy config file, or "builtin" for defaults (default "builtin")
|
||||||
-dbus-log
|
-dbus-log
|
||||||
Force logging in the D-Bus proxy
|
Force buffered logging in the D-Bus proxy
|
||||||
-dbus-system string
|
-dbus-system string
|
||||||
Path to system D-Bus proxy config file, or "nil" to disable (default "nil")
|
Path to system bus proxy config file, or "nil" to disable (default "nil")
|
||||||
-g value
|
-g value
|
||||||
Groups inherited by the app process
|
Groups inherited by all container processes
|
||||||
-id string
|
-id string
|
||||||
App ID, leave empty to disable security context app_id
|
Reverse-DNS style Application identifier, leave empty to inherit instance identifier
|
||||||
-mpris
|
-mpris
|
||||||
Allow owning MPRIS D-Bus path, has no effect if custom config is available
|
Allow owning MPRIS D-Bus path, has no effect if custom config is available
|
||||||
-pulse
|
-pulse
|
||||||
Share PulseAudio socket and cookie
|
Enable direct connection to PulseAudio
|
||||||
-u string
|
-u string
|
||||||
Passwd name within sandbox (default "chronos")
|
Passwd user name within sandbox (default "chronos")
|
||||||
-wayland
|
-wayland
|
||||||
Allow Wayland connections
|
Enable connection to Wayland via security-context-v1
|
||||||
|
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
147
nixos.nix
147
nixos.nix
@ -8,12 +8,10 @@ packages:
|
|||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
|
lists
|
||||||
mkMerge
|
mkMerge
|
||||||
mkIf
|
mkIf
|
||||||
mapAttrs
|
mapAttrs
|
||||||
mergeAttrsList
|
|
||||||
imap1
|
|
||||||
foldr
|
|
||||||
foldlAttrs
|
foldlAttrs
|
||||||
optional
|
optional
|
||||||
optionals
|
optionals
|
||||||
@ -30,6 +28,27 @@ in
|
|||||||
imports = [ (import ./options.nix packages) ];
|
imports = [ (import ./options.nix packages) ];
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
|
assertions = [
|
||||||
|
(
|
||||||
|
let
|
||||||
|
conflictingApps = foldlAttrs (
|
||||||
|
acc: id: app:
|
||||||
|
(
|
||||||
|
acc
|
||||||
|
++ foldlAttrs (
|
||||||
|
acc': id': app':
|
||||||
|
if id == id' || app.shareUid && app'.shareUid || app.identity != app'.identity then acc' else acc' ++ [ id ]
|
||||||
|
) [ ] cfg.apps
|
||||||
|
)
|
||||||
|
) [ ] cfg.apps;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assertion = (lists.length conflictingApps) == 0;
|
||||||
|
message = "the following fortify apps have conflicting identities: " + (builtins.concatStringsSep ", " conflictingApps);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
security.wrappers.fsu = {
|
security.wrappers.fsu = {
|
||||||
source = "${cfg.fsuPackage}/bin/fsu";
|
source = "${cfg.fsuPackage}/bin/fsu";
|
||||||
setuid = true;
|
setuid = true;
|
||||||
@ -49,22 +68,19 @@ in
|
|||||||
home-manager =
|
home-manager =
|
||||||
let
|
let
|
||||||
privPackages = mapAttrs (username: fid: {
|
privPackages = mapAttrs (username: fid: {
|
||||||
home.packages =
|
home.packages = foldlAttrs (
|
||||||
let
|
acc: id: app:
|
||||||
# aid 0 is reserved
|
[
|
||||||
wrappers = imap1 (
|
(
|
||||||
aid: app:
|
|
||||||
let
|
let
|
||||||
extendDBusDefault = id: ext: {
|
extendDBusDefault = id: ext: {
|
||||||
filter = true;
|
filter = true;
|
||||||
|
|
||||||
talk = [ "org.freedesktop.Notifications" ] ++ ext.talk;
|
talk = [ "org.freedesktop.Notifications" ] ++ ext.talk;
|
||||||
own =
|
own = [
|
||||||
(optionals (app.id != null) [
|
"${id}.*"
|
||||||
"${id}.*"
|
"org.mpris.MediaPlayer2.${id}.*"
|
||||||
"org.mpris.MediaPlayer2.${id}.*"
|
] ++ ext.own;
|
||||||
])
|
|
||||||
++ ext.own;
|
|
||||||
|
|
||||||
inherit (ext) call broadcast;
|
inherit (ext) call broadcast;
|
||||||
};
|
};
|
||||||
@ -78,7 +94,7 @@ in
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
session_bus = if app.dbus.session != null then (app.dbus.session (extendDBusDefault app.id)) else (extendDBusDefault app.id default);
|
session_bus = if app.dbus.session != null then (app.dbus.session (extendDBusDefault id)) else (extendDBusDefault id default);
|
||||||
system_bus = app.dbus.system;
|
system_bus = app.dbus.system;
|
||||||
};
|
};
|
||||||
command = if app.command == null then app.name else app.command;
|
command = if app.command == null then app.name else app.command;
|
||||||
@ -87,8 +103,6 @@ in
|
|||||||
isGraphical = if app.gpu != null then app.gpu else app.capability.wayland || app.capability.x11;
|
isGraphical = if app.gpu != null then app.gpu else app.capability.wayland || app.capability.x11;
|
||||||
|
|
||||||
conf = {
|
conf = {
|
||||||
inherit (app) id;
|
|
||||||
|
|
||||||
path =
|
path =
|
||||||
if app.path == null then
|
if app.path == null then
|
||||||
pkgs.writeScript "${app.name}-start" ''
|
pkgs.writeScript "${app.name}-start" ''
|
||||||
@ -99,16 +113,15 @@ in
|
|||||||
app.path;
|
app.path;
|
||||||
args = if app.args == null then [ "${app.name}-start" ] else app.args;
|
args = if app.args == null then [ "${app.name}-start" ] else app.args;
|
||||||
|
|
||||||
inherit enablements;
|
inherit id enablements;
|
||||||
|
|
||||||
inherit (dbusConfig) session_bus system_bus;
|
inherit (dbusConfig) session_bus system_bus;
|
||||||
direct_wayland = app.insecureWayland;
|
direct_wayland = app.insecureWayland;
|
||||||
|
|
||||||
username = getsubname fid aid;
|
username = getsubname fid app.identity;
|
||||||
data = getsubhome fid aid;
|
data = getsubhome fid app.identity;
|
||||||
|
|
||||||
identity = aid;
|
inherit (app) identity groups;
|
||||||
inherit (app) groups;
|
|
||||||
|
|
||||||
container = {
|
container = {
|
||||||
inherit (app)
|
inherit (app)
|
||||||
@ -146,7 +159,6 @@ in
|
|||||||
]
|
]
|
||||||
++ optionals app.nix [
|
++ optionals app.nix [
|
||||||
(mustBind "/nix/var")
|
(mustBind "/nix/var")
|
||||||
(bind "/var/db/nix-channels")
|
|
||||||
]
|
]
|
||||||
++ optionals isGraphical [
|
++ optionals isGraphical [
|
||||||
(devBind "/dev/dri")
|
(devBind "/dev/dri")
|
||||||
@ -156,6 +168,7 @@ in
|
|||||||
(devBind "/dev/nvidia-uvm-tools")
|
(devBind "/dev/nvidia-uvm-tools")
|
||||||
(devBind "/dev/nvidia0")
|
(devBind "/dev/nvidia0")
|
||||||
]
|
]
|
||||||
|
++ optionals app.useCommonPaths cfg.commonPaths
|
||||||
++ app.extraPaths;
|
++ app.extraPaths;
|
||||||
auto_etc = true;
|
auto_etc = true;
|
||||||
cover = [ "/var/run/nscd" ];
|
cover = [ "/var/run/nscd" ];
|
||||||
@ -188,10 +201,9 @@ in
|
|||||||
pkgs.writeShellScriptBin app.name ''
|
pkgs.writeShellScriptBin app.name ''
|
||||||
exec fortify${if app.verbose then " -v" else ""} app ${pkgs.writeText "fortify-${app.name}.json" (builtins.toJSON conf)} $@
|
exec fortify${if app.verbose then " -v" else ""} app ${pkgs.writeText "fortify-${app.name}.json" (builtins.toJSON conf)} $@
|
||||||
''
|
''
|
||||||
) cfg.apps;
|
)
|
||||||
in
|
]
|
||||||
foldr (
|
++ (
|
||||||
app: acc:
|
|
||||||
let
|
let
|
||||||
pkg = if app.share != null then app.share else pkgs.${app.name};
|
pkg = if app.share != null then app.share else pkgs.${app.name};
|
||||||
copy = source: "[ -d '${source}' ] && cp -Lrv '${source}' $out/share || true";
|
copy = source: "[ -d '${source}' ] && cp -Lrv '${source}' $out/share || true";
|
||||||
@ -211,30 +223,33 @@ in
|
|||||||
fi
|
fi
|
||||||
''
|
''
|
||||||
)
|
)
|
||||||
++ acc
|
)
|
||||||
) (wrappers ++ [ cfg.package ]) cfg.apps;
|
++ acc
|
||||||
|
) [ cfg.package ] cfg.apps;
|
||||||
}) cfg.users;
|
}) cfg.users;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
useUserPackages = false; # prevent users.users entries from being added
|
useUserPackages = false; # prevent users.users entries from being added
|
||||||
|
|
||||||
users = foldlAttrs (
|
users = mkMerge (
|
||||||
acc: _: fid:
|
foldlAttrs (
|
||||||
mkMerge [
|
acc: _: fid:
|
||||||
(mergeAttrsList (
|
|
||||||
# aid 0 is reserved
|
|
||||||
imap1 (aid: app: {
|
|
||||||
${getsubname fid aid} = mkMerge [
|
|
||||||
(cfg.home-manager (getsubname fid aid) (getsubuid fid aid))
|
|
||||||
app.extraConfig
|
|
||||||
{ home.packages = app.packages; }
|
|
||||||
];
|
|
||||||
}) cfg.apps
|
|
||||||
))
|
|
||||||
{ ${getsubname fid 0} = cfg.home-manager (getsubname fid 0) (getsubuid fid 0); }
|
|
||||||
acc
|
acc
|
||||||
]
|
++ foldlAttrs (
|
||||||
) privPackages cfg.users;
|
acc': _: app:
|
||||||
|
acc'
|
||||||
|
++ [
|
||||||
|
{
|
||||||
|
${getsubname fid app.identity} = mkMerge [
|
||||||
|
cfg.extraHomeConfig
|
||||||
|
app.extraConfig
|
||||||
|
{ home.packages = app.packages; }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
]
|
||||||
|
) [ { ${getsubname fid 0} = cfg.extraHomeConfig; } ] cfg.apps
|
||||||
|
) [ privPackages ] cfg.users
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
users =
|
users =
|
||||||
@ -250,33 +265,27 @@ in
|
|||||||
getgroup = fid: aid: { gid = getsubuid fid aid; };
|
getgroup = fid: aid: { gid = getsubuid fid aid; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
users = foldlAttrs (
|
users = mkMerge (
|
||||||
acc: _: fid:
|
foldlAttrs (
|
||||||
mkMerge [
|
acc: _: fid:
|
||||||
(mergeAttrsList (
|
|
||||||
# aid 0 is reserved
|
|
||||||
imap1 (aid: _: {
|
|
||||||
${getsubname fid aid} = getuser fid aid;
|
|
||||||
}) cfg.apps
|
|
||||||
))
|
|
||||||
{ ${getsubname fid 0} = getuser fid 0; }
|
|
||||||
acc
|
acc
|
||||||
]
|
++ foldlAttrs (
|
||||||
) { } cfg.users;
|
acc': _: app:
|
||||||
|
acc' ++ [ { ${getsubname fid app.identity} = getuser fid app.identity; } ]
|
||||||
|
) [ { ${getsubname fid 0} = getuser fid 0; } ] cfg.apps
|
||||||
|
) [ ] cfg.users
|
||||||
|
);
|
||||||
|
|
||||||
groups = foldlAttrs (
|
groups = mkMerge (
|
||||||
acc: _: fid:
|
foldlAttrs (
|
||||||
mkMerge [
|
acc: _: fid:
|
||||||
(mergeAttrsList (
|
|
||||||
# aid 0 is reserved
|
|
||||||
imap1 (aid: _: {
|
|
||||||
${getsubname fid aid} = getgroup fid aid;
|
|
||||||
}) cfg.apps
|
|
||||||
))
|
|
||||||
{ ${getsubname fid 0} = getgroup fid 0; }
|
|
||||||
acc
|
acc
|
||||||
]
|
++ foldlAttrs (
|
||||||
) { } cfg.users;
|
acc': _: app:
|
||||||
|
acc' ++ [ { ${getsubname fid app.identity} = getgroup fid app.identity; } ]
|
||||||
|
) [ { ${getsubname fid 0} = getgroup fid 0; } ] cfg.apps
|
||||||
|
) [ ] cfg.users
|
||||||
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
371
options.md
371
options.md
@ -35,27 +35,27 @@ package
|
|||||||
|
|
||||||
|
|
||||||
*Default:*
|
*Default:*
|
||||||
` <derivation fortify-static-x86_64-unknown-linux-musl-0.4.0> `
|
` <derivation fortify-static-x86_64-unknown-linux-musl-0.4.1> `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps
|
## environment\.fortify\.apps
|
||||||
|
|
||||||
Declarative fortify apps\.
|
Declaratively configured fortify apps\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*Type:*
|
*Type:*
|
||||||
list of (submodule)
|
attribute set of (submodule)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*Default:*
|
*Default:*
|
||||||
` [ ] `
|
` { } `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.packages
|
## environment\.fortify\.apps\.\<name>\.packages
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ list of package
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.args
|
## environment\.fortify\.apps\.\<name>\.args
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ null or (list of string)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.capability\.dbus
|
## environment\.fortify\.apps\.\<name>\.capability\.dbus
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.capability\.pulse
|
## environment\.fortify\.apps\.\<name>\.capability\.pulse
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -128,7 +128,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.capability\.wayland
|
## environment\.fortify\.apps\.\<name>\.capability\.wayland
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.capability\.x11
|
## environment\.fortify\.apps\.\<name>\.capability\.x11
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.command
|
## environment\.fortify\.apps\.\<name>\.command
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -184,7 +184,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.dbus\.session
|
## environment\.fortify\.apps\.\<name>\.dbus\.session
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -203,7 +203,7 @@ null or (function that evaluates to a(n) anything)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.dbus\.system
|
## environment\.fortify\.apps\.\<name>\.dbus\.system
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ null or anything
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.devel
|
## environment\.fortify\.apps\.\<name>\.devel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.device
|
## environment\.fortify\.apps\.\<name>\.device
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.env
|
## environment\.fortify\.apps\.\<name>\.env
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ null or (attribute set of string)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.extraConfig
|
## environment\.fortify\.apps\.\<name>\.extraConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -304,16 +304,16 @@ anything
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.extraPaths
|
## environment\.fortify\.apps\.\<name>\.extraPaths
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Extra paths to make available to the sandbox\.
|
Extra paths to make available to the container\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*Type:*
|
*Type:*
|
||||||
list of anything
|
list of (submodule)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -322,7 +322,107 @@ list of anything
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.gpu
|
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.dev
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable use of device files\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` false `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.dst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Mount point in container, same as src if null\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
null or string
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` null `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.require
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable start failure if the bind mount cannot be established for any reason\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` false `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Host filesystem path to make available to the container\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
string
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.apps\.\<name>\.extraPaths\.\*\.write
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable mounting path as writable\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` false `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.apps\.\<name>\.gpu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -341,7 +441,7 @@ null or boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.groups
|
## environment\.fortify\.apps\.\<name>\.groups
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -359,25 +459,20 @@ list of string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.id
|
## environment\.fortify\.apps\.\<name>\.identity
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Freedesktop application ID\.
|
Application identity\. Identity 0 is reserved for system services\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*Type:*
|
*Type:*
|
||||||
null or string
|
integer between 1 and 9999 (both inclusive)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*Default:*
|
## environment\.fortify\.apps\.\<name>\.insecureWayland
|
||||||
` null `
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.insecureWayland
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -400,7 +495,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.mapRealUid
|
## environment\.fortify\.apps\.\<name>\.mapRealUid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -423,7 +518,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.multiarch
|
## environment\.fortify\.apps\.\<name>\.multiarch
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -446,7 +541,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.name
|
## environment\.fortify\.apps\.\<name>\.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -459,7 +554,7 @@ string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.net
|
## environment\.fortify\.apps\.\<name>\.net
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -482,7 +577,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.nix
|
## environment\.fortify\.apps\.\<name>\.nix
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -505,7 +600,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.path
|
## environment\.fortify\.apps\.\<name>\.path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -524,7 +619,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.script
|
## environment\.fortify\.apps\.\<name>\.script
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -542,7 +637,7 @@ null or string
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.share
|
## environment\.fortify\.apps\.\<name>\.share
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -561,7 +656,30 @@ null or package
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.tty
|
## environment\.fortify\.apps\.\<name>\.shareUid
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable sharing identity with another application\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` false `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.apps\.\<name>\.tty
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -584,7 +702,30 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.userns
|
## environment\.fortify\.apps\.\<name>\.useCommonPaths
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable common extra paths\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.apps\.\<name>\.userns
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -607,7 +748,7 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.apps\.\*\.verbose
|
## environment\.fortify\.apps\.\<name>\.verbose
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -630,6 +771,137 @@ boolean
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.commonPaths
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Common extra paths to make available to the container\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
list of (submodule)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` [ ] `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.commonPaths\.\*\.dev
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable use of device files\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` false `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.commonPaths\.\*\.dst
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Mount point in container, same as src if null\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
null or string
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` null `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.commonPaths\.\*\.require
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable start failure if the bind mount cannot be established for any reason\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` false `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.commonPaths\.\*\.src
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Host filesystem path to make available to the container\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
string
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.commonPaths\.\*\.write
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Whether to enable mounting path as writable\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Default:*
|
||||||
|
` false `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Example:*
|
||||||
|
` true `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## environment\.fortify\.extraHomeConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Extra home-manager configuration to merge with all target users\.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*Type:*
|
||||||
|
anything
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.fsuPackage
|
## environment\.fortify\.fsuPackage
|
||||||
|
|
||||||
|
|
||||||
@ -644,20 +916,7 @@ package
|
|||||||
|
|
||||||
|
|
||||||
*Default:*
|
*Default:*
|
||||||
` <derivation fortify-fsu-0.4.0> `
|
` <derivation fortify-fsu-0.4.1> `
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## environment\.fortify\.home-manager
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Target user shared home-manager configuration\.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
*Type:*
|
|
||||||
function that evaluates to a(n) function that evaluates to a(n) attribute set of anything
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
73
options.nix
73
options.nix
@ -3,6 +3,38 @@ packages:
|
|||||||
|
|
||||||
let
|
let
|
||||||
inherit (lib) types mkOption mkEnableOption;
|
inherit (lib) types mkOption mkEnableOption;
|
||||||
|
|
||||||
|
mountPoint =
|
||||||
|
let
|
||||||
|
inherit (types)
|
||||||
|
str
|
||||||
|
submodule
|
||||||
|
nullOr
|
||||||
|
listOf
|
||||||
|
;
|
||||||
|
in
|
||||||
|
listOf (submodule {
|
||||||
|
options = {
|
||||||
|
dst = mkOption {
|
||||||
|
type = nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = ''
|
||||||
|
Mount point in container, same as src if null.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
src = mkOption {
|
||||||
|
type = str;
|
||||||
|
description = ''
|
||||||
|
Host filesystem path to make available to the container.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
write = mkEnableOption "mounting path as writable";
|
||||||
|
dev = mkEnableOption "use of device files";
|
||||||
|
require = mkEnableOption "start failure if the bind mount cannot be established for any reason";
|
||||||
|
};
|
||||||
|
});
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -33,14 +65,10 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager = mkOption {
|
extraHomeConfig = mkOption {
|
||||||
type =
|
type = types.anything;
|
||||||
let
|
|
||||||
inherit (types) functionTo attrsOf anything;
|
|
||||||
in
|
|
||||||
functionTo (functionTo (attrsOf anything));
|
|
||||||
description = ''
|
description = ''
|
||||||
Target user shared home-manager configuration.
|
Extra home-manager configuration to merge with all target users.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,6 +76,7 @@ in
|
|||||||
type =
|
type =
|
||||||
let
|
let
|
||||||
inherit (types)
|
inherit (types)
|
||||||
|
ints
|
||||||
str
|
str
|
||||||
bool
|
bool
|
||||||
package
|
package
|
||||||
@ -59,7 +88,7 @@ in
|
|||||||
functionTo
|
functionTo
|
||||||
;
|
;
|
||||||
in
|
in
|
||||||
listOf (submodule {
|
attrsOf (submodule {
|
||||||
options = {
|
options = {
|
||||||
name = mkOption {
|
name = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
@ -70,13 +99,13 @@ in
|
|||||||
|
|
||||||
verbose = mkEnableOption "launchers with verbose output";
|
verbose = mkEnableOption "launchers with verbose output";
|
||||||
|
|
||||||
id = mkOption {
|
identity = mkOption {
|
||||||
type = nullOr str;
|
type = ints.between 1 9999;
|
||||||
default = null;
|
|
||||||
description = ''
|
description = ''
|
||||||
Freedesktop application ID.
|
Application identity. Identity 0 is reserved for system services.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
shareUid = mkEnableOption "sharing identity with another application";
|
||||||
|
|
||||||
packages = mkOption {
|
packages = mkOption {
|
||||||
type = listOf package;
|
type = listOf package;
|
||||||
@ -189,11 +218,15 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useCommonPaths = mkEnableOption "common extra paths" // {
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
extraPaths = mkOption {
|
extraPaths = mkOption {
|
||||||
type = listOf anything;
|
type = mountPoint;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
description = ''
|
description = ''
|
||||||
Extra paths to make available to the sandbox.
|
Extra paths to make available to the container.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -241,8 +274,18 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
default = { };
|
||||||
|
description = ''
|
||||||
|
Declaratively configured fortify apps.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
commonPaths = mkOption {
|
||||||
|
type = mountPoint;
|
||||||
default = [ ];
|
default = [ ];
|
||||||
description = "Declarative fortify apps.";
|
description = ''
|
||||||
|
Common extra paths to make available to the container.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
stateDir = mkOption {
|
stateDir = mkOption {
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "fortify";
|
pname = "fortify";
|
||||||
version = "0.4.0";
|
version = "0.4.1";
|
||||||
|
|
||||||
src = builtins.path {
|
src = builtins.path {
|
||||||
name = "${pname}-src";
|
name = "${pname}-src";
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"git.gensokyo.uk/security/fortify/dbus"
|
"git.gensokyo.uk/security/fortify/dbus"
|
||||||
)
|
)
|
||||||
@ -26,64 +27,62 @@ func (sys *I) MustProxyDBus(sessionPath string, session *dbus.Config, systemPath
|
|||||||
func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath string) (func(), error) {
|
func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath string) (func(), error) {
|
||||||
d := new(DBus)
|
d := new(DBus)
|
||||||
|
|
||||||
// session bus is mandatory
|
// session bus is required as otherwise this is effectively a very expensive noop
|
||||||
if session == nil {
|
if session == nil {
|
||||||
return nil, msg.WrapErr(ErrDBusConfig,
|
return nil, msg.WrapErr(ErrDBusConfig,
|
||||||
"attempted to seal message bus proxy without session bus config")
|
"attempted to create message bus proxy args without session bus config")
|
||||||
}
|
}
|
||||||
|
|
||||||
// system bus is optional
|
// system bus is optional
|
||||||
d.system = system != nil
|
d.system = system != nil
|
||||||
|
|
||||||
// upstream address, downstream socket path
|
d.sessionBus[0], d.systemBus[0] = dbus.Address()
|
||||||
var sessionBus, systemBus [2]string
|
d.sessionBus[1], d.systemBus[1] = sessionPath, systemPath
|
||||||
|
|
||||||
// resolve upstream bus addresses
|
|
||||||
sessionBus[0], systemBus[0] = dbus.Address()
|
|
||||||
|
|
||||||
// set paths from caller
|
|
||||||
sessionBus[1], systemBus[1] = sessionPath, systemPath
|
|
||||||
|
|
||||||
// create proxy instance
|
|
||||||
d.proxy = dbus.New(sessionBus, systemBus)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if msg.IsVerbose() && d.proxy.Sealed() {
|
|
||||||
msg.Verbose("sealed session proxy", session.Args(sessionBus))
|
|
||||||
if system != nil {
|
|
||||||
msg.Verbose("sealed system proxy", system.Args(systemBus))
|
|
||||||
}
|
|
||||||
msg.Verbose("message bus proxy final args:", d.proxy)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// queue operation
|
|
||||||
sys.ops = append(sys.ops, d)
|
|
||||||
|
|
||||||
// seal dbus proxy
|
|
||||||
d.out = &scanToFmsg{msg: new(strings.Builder)}
|
d.out = &scanToFmsg{msg: new(strings.Builder)}
|
||||||
return d.out.Dump, wrapErrSuffix(d.proxy.Seal(session, system),
|
if final, err := dbus.Finalise(d.sessionBus, d.systemBus, session, system); err != nil {
|
||||||
"cannot seal message bus proxy:")
|
if errors.Is(err, syscall.EINVAL) {
|
||||||
|
return nil, msg.WrapErr(err, "message bus proxy configuration contains NUL byte")
|
||||||
|
}
|
||||||
|
return nil, wrapErrSuffix(err, "cannot finalise message bus proxy:")
|
||||||
|
} else {
|
||||||
|
if msg.IsVerbose() {
|
||||||
|
msg.Verbose("session bus proxy:", session.Args(d.sessionBus))
|
||||||
|
if system != nil {
|
||||||
|
msg.Verbose("system bus proxy:", system.Args(d.systemBus))
|
||||||
|
}
|
||||||
|
|
||||||
|
// this calls the argsWt String method
|
||||||
|
msg.Verbose("message bus proxy final args:", final.WriterTo)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.final = final
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.ops = append(sys.ops, d)
|
||||||
|
return d.out.Dump, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type DBus struct {
|
type DBus struct {
|
||||||
proxy *dbus.Proxy
|
proxy *dbus.Proxy // populated during apply
|
||||||
|
|
||||||
out *scanToFmsg
|
final *dbus.Final
|
||||||
|
out *scanToFmsg
|
||||||
// whether system bus proxy is enabled
|
// whether system bus proxy is enabled
|
||||||
system bool
|
system bool
|
||||||
|
|
||||||
|
sessionBus, systemBus dbus.ProxyPair
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DBus) Type() Enablement { return Process }
|
func (d *DBus) Type() Enablement { return Process }
|
||||||
|
|
||||||
func (d *DBus) apply(sys *I) error {
|
func (d *DBus) apply(sys *I) error {
|
||||||
msg.Verbosef("session bus proxy on %q for upstream %q", d.proxy.Session()[1], d.proxy.Session()[0])
|
msg.Verbosef("session bus proxy on %q for upstream %q", d.sessionBus[1], d.sessionBus[0])
|
||||||
if d.system {
|
if d.system {
|
||||||
msg.Verbosef("system bus proxy on %q for upstream %q", d.proxy.System()[1], d.proxy.System()[0])
|
msg.Verbosef("system bus proxy on %q for upstream %q", d.systemBus[1], d.systemBus[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
// this starts the process and blocks until ready
|
d.proxy = dbus.New(sys.ctx, d.final, d.out)
|
||||||
if err := d.proxy.Start(sys.ctx, d.out, true); err != nil {
|
if err := d.proxy.Start(); err != nil {
|
||||||
d.out.Dump()
|
d.out.Dump()
|
||||||
return wrapErrSuffix(err,
|
return wrapErrSuffix(err,
|
||||||
"cannot start message bus proxy:")
|
"cannot start message bus proxy:")
|
||||||
|
@ -30,13 +30,9 @@
|
|||||||
|
|
||||||
environment = {
|
environment = {
|
||||||
systemPackages = with pkgs; [
|
systemPackages = with pkgs; [
|
||||||
# For glinfo and wayland-info:
|
|
||||||
mesa-demos
|
|
||||||
wayland-utils
|
|
||||||
|
|
||||||
# For D-Bus tests:
|
# For D-Bus tests:
|
||||||
libnotify
|
|
||||||
mako
|
mako
|
||||||
|
libnotify
|
||||||
];
|
];
|
||||||
|
|
||||||
variables = {
|
variables = {
|
||||||
@ -99,33 +95,51 @@
|
|||||||
stateDir = "/var/lib/fortify";
|
stateDir = "/var/lib/fortify";
|
||||||
users.alice = 0;
|
users.alice = 0;
|
||||||
|
|
||||||
home-manager = _: _: { home.stateVersion = "23.05"; };
|
extraHomeConfig = {
|
||||||
|
home.stateVersion = "23.05";
|
||||||
|
};
|
||||||
|
|
||||||
apps = [
|
apps = {
|
||||||
{
|
"cat.gensokyo.extern.foot.noEnablements" = {
|
||||||
name = "ne-foot";
|
name = "ne-foot";
|
||||||
|
identity = 1;
|
||||||
verbose = true;
|
verbose = true;
|
||||||
share = pkgs.foot;
|
share = pkgs.foot;
|
||||||
packages = [ pkgs.foot ];
|
packages = with pkgs; [
|
||||||
|
foot
|
||||||
|
|
||||||
|
# For wayland-info:
|
||||||
|
wayland-utils
|
||||||
|
];
|
||||||
command = "foot";
|
command = "foot";
|
||||||
capability = {
|
capability = {
|
||||||
dbus = false;
|
dbus = false;
|
||||||
pulse = false;
|
pulse = false;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"cat.gensokyo.extern.foot.pulseaudio" = {
|
||||||
name = "pa-foot";
|
name = "pa-foot";
|
||||||
|
identity = 2;
|
||||||
verbose = true;
|
verbose = true;
|
||||||
share = pkgs.foot;
|
share = pkgs.foot;
|
||||||
packages = [ pkgs.foot ];
|
packages = [ pkgs.foot ];
|
||||||
command = "foot";
|
command = "foot";
|
||||||
capability.dbus = false;
|
capability.dbus = false;
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"cat.gensokyo.extern.Alacritty.x11" = {
|
||||||
name = "x11-alacritty";
|
name = "x11-alacritty";
|
||||||
|
identity = 3;
|
||||||
verbose = true;
|
verbose = true;
|
||||||
share = pkgs.alacritty;
|
share = pkgs.alacritty;
|
||||||
packages = [ pkgs.alacritty ];
|
packages = with pkgs; [
|
||||||
|
# For X11 terminal emulator:
|
||||||
|
alacritty
|
||||||
|
|
||||||
|
# For glinfo:
|
||||||
|
mesa-demos
|
||||||
|
];
|
||||||
command = "alacritty";
|
command = "alacritty";
|
||||||
capability = {
|
capability = {
|
||||||
wayland = false;
|
wayland = false;
|
||||||
@ -133,21 +147,30 @@
|
|||||||
dbus = false;
|
dbus = false;
|
||||||
pulse = false;
|
pulse = false;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"cat.gensokyo.extern.foot.directWayland" = {
|
||||||
name = "da-foot";
|
name = "da-foot";
|
||||||
|
identity = 4;
|
||||||
verbose = true;
|
verbose = true;
|
||||||
insecureWayland = true;
|
insecureWayland = true;
|
||||||
share = pkgs.foot;
|
share = pkgs.foot;
|
||||||
packages = [ pkgs.foot ];
|
packages = with pkgs; [
|
||||||
|
foot
|
||||||
|
|
||||||
|
# For wayland-info:
|
||||||
|
wayland-utils
|
||||||
|
];
|
||||||
command = "foot";
|
command = "foot";
|
||||||
capability = {
|
capability = {
|
||||||
dbus = false;
|
dbus = false;
|
||||||
pulse = false;
|
pulse = false;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
{
|
|
||||||
|
"cat.gensokyo.extern.strace.wantFail" = {
|
||||||
name = "strace-failure";
|
name = "strace-failure";
|
||||||
|
identity = 5;
|
||||||
verbose = true;
|
verbose = true;
|
||||||
share = pkgs.strace;
|
share = pkgs.strace;
|
||||||
command = "strace true";
|
command = "strace true";
|
||||||
@ -157,7 +180,7 @@
|
|||||||
dbus = false;
|
dbus = false;
|
||||||
pulse = false;
|
pulse = false;
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
];
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ let
|
|||||||
};
|
};
|
||||||
|
|
||||||
callTestCase =
|
callTestCase =
|
||||||
path:
|
path: identity:
|
||||||
let
|
let
|
||||||
tc = import path {
|
tc = import path {
|
||||||
inherit
|
inherit
|
||||||
@ -36,8 +36,14 @@ let
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
name = "check-sandbox-${tc.name}";
|
name = "check-sandbox-${tc.name}";
|
||||||
|
inherit identity;
|
||||||
verbose = true;
|
verbose = true;
|
||||||
inherit (tc) tty device mapRealUid;
|
inherit (tc)
|
||||||
|
tty
|
||||||
|
device
|
||||||
|
mapRealUid
|
||||||
|
useCommonPaths
|
||||||
|
;
|
||||||
share = testProgram;
|
share = testProgram;
|
||||||
packages = [ ];
|
packages = [ ];
|
||||||
path = "${testProgram}/bin/fortify-test";
|
path = "${testProgram}/bin/fortify-test";
|
||||||
@ -46,10 +52,12 @@ let
|
|||||||
(toString (builtins.toFile "fortify-${tc.name}-want.json" (builtins.toJSON tc.want)))
|
(toString (builtins.toFile "fortify-${tc.name}-want.json" (builtins.toJSON tc.want)))
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
testCaseName = name: "cat.gensokyo.fortify.test." + name;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
preset = callTestCase ./preset.nix;
|
${testCaseName "preset"} = callTestCase ./preset.nix 1;
|
||||||
tty = callTestCase ./tty.nix;
|
${testCaseName "tty"} = callTestCase ./tty.nix 2;
|
||||||
mapuid = callTestCase ./mapuid.nix;
|
${testCaseName "mapuid"} = callTestCase ./mapuid.nix 3;
|
||||||
device = callTestCase ./device.nix;
|
${testCaseName "device"} = callTestCase ./device.nix 4;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
tty = false;
|
tty = false;
|
||||||
device = true;
|
device = true;
|
||||||
mapRealUid = false;
|
mapRealUid = false;
|
||||||
|
useCommonPaths = true;
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -140,7 +141,12 @@
|
|||||||
u0 = fs "800001c0" {
|
u0 = fs "800001c0" {
|
||||||
a4 = fs "800001c0" {
|
a4 = fs "800001c0" {
|
||||||
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
||||||
".config" = fs "800001ed" { "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null; } null;
|
".config" = fs "800001ed" {
|
||||||
|
"environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
|
||||||
|
systemd = fs "800001ed" {
|
||||||
|
user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
".local" = fs "800001ed" {
|
".local" = fs "800001ed" {
|
||||||
state = fs "800001ed" {
|
state = fs "800001ed" {
|
||||||
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
||||||
@ -164,6 +170,7 @@
|
|||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
||||||
|
cache = fs "800001ed" { private = fs "800001c0" null null; } null;
|
||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
|
|
||||||
@ -185,6 +192,7 @@
|
|||||||
(ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
(ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
(ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
(ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
(ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=4k,mode=755,uid=1000004,gid=1000004")
|
(ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=4k,mode=755,uid=1000004,gid=1000004")
|
||||||
(ent "/" "/run/user/65534" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=8192k,mode=700,uid=1000004,gid=1000004")
|
(ent "/" "/run/user/65534" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=8192k,mode=700,uid=1000004,gid=1000004")
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
tty = false;
|
tty = false;
|
||||||
device = false;
|
device = false;
|
||||||
mapRealUid = true;
|
mapRealUid = true;
|
||||||
|
useCommonPaths = true;
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -164,7 +165,12 @@
|
|||||||
u0 = fs "800001c0" {
|
u0 = fs "800001c0" {
|
||||||
a3 = fs "800001c0" {
|
a3 = fs "800001c0" {
|
||||||
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
||||||
".config" = fs "800001ed" { "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null; } null;
|
".config" = fs "800001ed" {
|
||||||
|
"environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
|
||||||
|
systemd = fs "800001ed" {
|
||||||
|
user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
".local" = fs "800001ed" {
|
".local" = fs "800001ed" {
|
||||||
state = fs "800001ed" {
|
state = fs "800001ed" {
|
||||||
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
||||||
@ -188,6 +194,7 @@
|
|||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
||||||
|
cache = fs "800001ed" { private = fs "800001c0" null null; } null;
|
||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
|
|
||||||
@ -213,6 +220,7 @@
|
|||||||
(ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
(ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
(ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
(ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
(ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=4k,mode=755,uid=1000003,gid=1000003")
|
(ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=4k,mode=755,uid=1000003,gid=1000003")
|
||||||
(ent "/" "/run/user/1000" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=8192k,mode=700,uid=1000003,gid=1000003")
|
(ent "/" "/run/user/1000" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=8192k,mode=700,uid=1000003,gid=1000003")
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
tty = false;
|
tty = false;
|
||||||
device = false;
|
device = false;
|
||||||
mapRealUid = false;
|
mapRealUid = false;
|
||||||
|
useCommonPaths = false;
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -164,7 +165,12 @@
|
|||||||
u0 = fs "800001c0" {
|
u0 = fs "800001c0" {
|
||||||
a1 = fs "800001c0" {
|
a1 = fs "800001c0" {
|
||||||
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
||||||
".config" = fs "800001ed" { "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null; } null;
|
".config" = fs "800001ed" {
|
||||||
|
"environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
|
||||||
|
systemd = fs "800001ed" {
|
||||||
|
user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
".local" = fs "800001ed" {
|
".local" = fs "800001ed" {
|
||||||
state = fs "800001ed" {
|
state = fs "800001ed" {
|
||||||
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
tty = true;
|
tty = true;
|
||||||
device = false;
|
device = false;
|
||||||
mapRealUid = false;
|
mapRealUid = false;
|
||||||
|
useCommonPaths = true;
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -165,7 +166,12 @@
|
|||||||
u0 = fs "800001c0" {
|
u0 = fs "800001c0" {
|
||||||
a2 = fs "800001c0" {
|
a2 = fs "800001c0" {
|
||||||
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
".cache" = fs "800001ed" { ".keep" = fs "80001ff" null ""; } null;
|
||||||
".config" = fs "800001ed" { "environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null; } null;
|
".config" = fs "800001ed" {
|
||||||
|
"environment.d" = fs "800001ed" { "10-home-manager.conf" = fs "80001ff" null null; } null;
|
||||||
|
systemd = fs "800001ed" {
|
||||||
|
user = fs "800001ed" { "tray.target" = fs "80001ff" null null; } null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
".local" = fs "800001ed" {
|
".local" = fs "800001ed" {
|
||||||
state = fs "800001ed" {
|
state = fs "800001ed" {
|
||||||
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
||||||
@ -189,6 +195,7 @@
|
|||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
||||||
|
cache = fs "800001ed" { private = fs "800001c0" null null; } null;
|
||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
|
|
||||||
@ -215,6 +222,7 @@
|
|||||||
(ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
(ent "/dev" "/sys/dev" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
(ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
(ent "/devices" "/sys/devices" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
(ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
(ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=4k,mode=755,uid=1000002,gid=1000002")
|
(ent "/" "/run/user" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=4k,mode=755,uid=1000002,gid=1000002")
|
||||||
(ent "/" "/run/user/65534" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=8192k,mode=700,uid=1000002,gid=1000002")
|
(ent "/" "/run/user/65534" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=8192k,mode=700,uid=1000002,gid=1000002")
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
testProgram = pkgs.callPackage ./tool/package.nix { inherit (config.environment.fortify.package) version; };
|
testProgram = pkgs.callPackage ./tool/package.nix { inherit (config.environment.fortify.package) version; };
|
||||||
testCases = import ./case lib testProgram;
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
users.users = {
|
users.users = {
|
||||||
@ -65,13 +64,17 @@ in
|
|||||||
stateDir = "/var/lib/fortify";
|
stateDir = "/var/lib/fortify";
|
||||||
users.alice = 0;
|
users.alice = 0;
|
||||||
|
|
||||||
home-manager = _: _: { home.stateVersion = "23.05"; };
|
extraHomeConfig = {
|
||||||
|
home.stateVersion = "23.05";
|
||||||
|
};
|
||||||
|
|
||||||
apps = with testCases; [
|
commonPaths = [
|
||||||
preset
|
{
|
||||||
tty
|
src = "/var/cache";
|
||||||
mapuid
|
write = true;
|
||||||
device
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
apps = import ./case lib testProgram;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,8 @@ print(machine.fail("sudo -u alice -i fortify -v run --wayland true"))
|
|||||||
fortify('-v run --wayland --dbus notify-send -a "NixOS Tests" "Test notification" "Notification from within sandbox." && touch /tmp/dbus-ok')
|
fortify('-v run --wayland --dbus notify-send -a "NixOS Tests" "Test notification" "Notification from within sandbox." && touch /tmp/dbus-ok')
|
||||||
machine.wait_for_file("/tmp/dbus-ok", timeout=15)
|
machine.wait_for_file("/tmp/dbus-ok", timeout=15)
|
||||||
collect_state_ui("dbus_notify_exited")
|
collect_state_ui("dbus_notify_exited")
|
||||||
|
# not in pid namespace, verify termination
|
||||||
|
machine.wait_until_fails("pgrep xdg-dbus-proxy")
|
||||||
machine.succeed("pkill -9 mako")
|
machine.succeed("pkill -9 mako")
|
||||||
|
|
||||||
# Check revert type selection:
|
# Check revert type selection:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user