Compare commits

...

2 Commits

Author SHA1 Message Date
a5baad9e00
container: optionally isolate host abstract UNIX domain sockets via landlock
Some checks failed
Test / Create distribution (push) Failing after 29s
Test / Sandbox (push) Successful in 2m15s
Test / Sandbox (pull_request) Successful in 1m25s
Test / Hpkg (push) Successful in 4m21s
Test / Hpkg (pull_request) Successful in 2m5s
Test / Sandbox (race detector) (push) Successful in 4m27s
Test / Sandbox (race detector) (pull_request) Successful in 2m14s
Test / Create distribution (pull_request) Failing after 27s
Test / Hakurei (push) Failing after 20m53s
Test / Hakurei (race detector) (pull_request) Failing after 22m5s
Test / Hakurei (pull_request) Failing after 39m56s
Test / Flake checks (pull_request) Has been skipped
Test / Hakurei (race detector) (push) Failing after 42m26s
Test / Flake checks (push) Has been skipped
2025-08-18 02:36:42 +09:00
551ec8c27d
app: set up acl on X11 socket
All checks were successful
Test / Hpkg (push) Successful in 42s
Test / Create distribution (push) Successful in 32s
Test / Sandbox (push) Successful in 1m50s
Test / Hakurei (push) Successful in 42s
Test / Sandbox (race detector) (push) Successful in 2m37s
Test / Hakurei (race detector) (push) Successful in 43s
Test / Flake checks (push) Successful in 1m32s
The socket is typically owned by the priv-user, and inaccessible by the target user, so just allowing access to the directory is not enough. This change fixes this oversight and add checks that will also be useful for merging #1.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2025-08-18 02:33:03 +09:00
23 changed files with 253 additions and 9 deletions

View File

@ -28,6 +28,8 @@ type appInfo struct {
// passed through to [hst.Config] // passed through to [hst.Config]
Net bool `json:"net,omitempty"` Net bool `json:"net,omitempty"`
// passed through to [hst.Config] // passed through to [hst.Config]
ScopeAbstract bool `json:"scope_abstract,omitempty"`
// passed through to [hst.Config]
Device bool `json:"dev,omitempty"` Device bool `json:"dev,omitempty"`
// passed through to [hst.Config] // passed through to [hst.Config]
Tty bool `json:"tty,omitempty"` Tty bool `json:"tty,omitempty"`

View File

@ -92,6 +92,8 @@ type (
RetainSession bool RetainSession bool
// Do not [syscall.CLONE_NEWNET]. // Do not [syscall.CLONE_NEWNET].
HostNet bool HostNet bool
// Scope abstract UNIX domain sockets using LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET.
ScopeAbstract bool
// Retain CAP_SYS_ADMIN. // Retain CAP_SYS_ADMIN.
Privileged bool Privileged bool
} }

View File

@ -13,6 +13,7 @@ import (
. "syscall" . "syscall"
"time" "time"
"hakurei.app/container/landlock"
"hakurei.app/container/seccomp" "hakurei.app/container/seccomp"
) )
@ -263,6 +264,12 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
msg.Verbose("syscall filter not configured") msg.Verbose("syscall filter not configured")
} }
if params.ScopeAbstract {
if err := landlock.ScopeAbstract(); err != nil {
log.Fatalf("could not scope abstract unix sockets: %v", err)
}
}
extraFiles := make([]*os.File, params.Count) extraFiles := make([]*os.File, params.Count)
for i := range extraFiles { for i := range extraFiles {
// setup fd is placed before all extra files // setup fd is placed before all extra files

View File

@ -0,0 +1,14 @@
#include <errno.h>
#include <linux/landlock.h>
#include <sys/psx_syscall.h>
#include <sys/syscall.h>
#include "landlock-helper.h"
int hakurei_scope_abstract_unix_sockets(int* p_errno, int fd) {
int res = psx_syscall3(SYS_landlock_restrict_self, fd, 0, 0);
*p_errno = errno;
return res;
}

View File

@ -0,0 +1,3 @@
#pragma once
int hakurei_scope_abstract_unix_sockets(int* p_errno, int fd);

View File

@ -0,0 +1,57 @@
package landlock
/*
#cgo linux pkg-config: --static libpsx
#include <linux/landlock.h>
#include <sys/syscall.h>
#include "landlock-helper.h"
*/
import "C"
import (
"fmt"
"syscall"
"unsafe"
)
const (
LANDLOCK_CREATE_RULESET_VERSION = C.LANDLOCK_CREATE_RULESET_VERSION
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = C.LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
SYS_LANDLOCK_CREATE_RULESET = C.SYS_landlock_create_ruleset
)
type LandlockRulesetAttr = C.struct_landlock_ruleset_attr
func ScopeAbstract() error {
abi, _, err := syscall.Syscall(SYS_LANDLOCK_CREATE_RULESET, 0, 0, LANDLOCK_CREATE_RULESET_VERSION)
if err != 0 {
return fmt.Errorf("could not fetch landlock ABI: errno %v", err)
}
if abi < 6 {
return fmt.Errorf("landlock ABI must be >= 6, got %d", abi)
}
attrs := LandlockRulesetAttr{
scoped: LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET,
}
fd, _, err := syscall.Syscall(SYS_LANDLOCK_CREATE_RULESET, uintptr(unsafe.Pointer(&attrs)), unsafe.Sizeof(attrs), 0)
if err != 0 {
return fmt.Errorf("could not create landlock ruleset: errno %v", err)
}
defer syscall.Close(int(fd))
var errno C.int
if rv := C.hakurei_scope_abstract_unix_sockets(&errno, C.int(fd)); rv != 0 {
return fmt.Errorf("could not restrict self via landlock: errno %v", errno)
}
return nil
}

View File

@ -79,6 +79,8 @@ type (
Userns bool `json:"userns,omitempty"` Userns bool `json:"userns,omitempty"`
// share host net namespace // share host net namespace
Net bool `json:"net,omitempty"` Net bool `json:"net,omitempty"`
// disallow accessing abstract UNIX domain sockets created outside the container
ScopeAbstract bool `json:"scope_abstract,omitempty"`
// allow dangerous terminal I/O // allow dangerous terminal I/O
Tty bool `json:"tty,omitempty"` Tty bool `json:"tty,omitempty"`
// allow multiarch // allow multiarch

View File

@ -33,6 +33,7 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
SeccompPresets: s.SeccompPresets, SeccompPresets: s.SeccompPresets,
RetainSession: s.Tty, RetainSession: s.Tty,
HostNet: s.Net, HostNet: s.Net,
ScopeAbstract: s.ScopeAbstract,
// the container is canceled when shim is requested to exit or receives an interrupt or termination signal; // the container is canceled when shim is requested to exit or receives an interrupt or termination signal;
// this behaviour is implemented in the shim // this behaviour is implemented in the shim

View File

@ -12,6 +12,7 @@ import (
"path" "path"
"regexp" "regexp"
"slices" "slices"
"strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
@ -390,6 +391,22 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
seal.env[display] = d seal.env[display] = d
socketDir := container.AbsFHSTmp.Append(".X11-unix") socketDir := container.AbsFHSTmp.Append(".X11-unix")
seal.container.Bind(socketDir, socketDir, 0) seal.container.Bind(socketDir, socketDir, 0)
// the socket file at `/tmp/.X11-unix/X%d` is typically owned by the priv user
// and not accessible by the target user
var socketPath *container.Absolute
if len(d) > 1 && d[0] == ':' { // `:%d`
if n, err := strconv.Atoi(d[1:]); err == nil && n >= 0 {
socketPath = socketDir.Append("X" + strconv.Itoa(n))
}
} else if len(d) > 5 && strings.HasPrefix(d, "unix:") { // `unix:%s`
if a, err := container.NewAbs(d[5:]); err == nil {
socketPath = a
}
}
if socketPath != nil {
seal.sys.UpdatePermTypeOptional(system.EX11, socketPath.String(), acl.Read, acl.Write, acl.Execute)
}
} }
} }

View File

@ -137,6 +137,7 @@ in
multiarch multiarch
env env
; ;
scope_abstract = app.scopeAbstract;
map_real_uid = app.mapRealUid; map_real_uid = app.mapRealUid;
filesystem = filesystem =

View File

@ -572,6 +572,28 @@ boolean
*Example:*
` true `
## environment\.hakurei\.apps\.\<name>\.scopeAbstract
Whether to restrict abstract UNIX domain socket access\.
*Type:*
boolean
*Default:*
` true `
*Example:* *Example:*
` true ` ` true `

View File

@ -182,6 +182,9 @@ in
net = mkEnableOption "network access" // { net = mkEnableOption "network access" // {
default = true; default = true;
}; };
scopeAbstract = mkEnableOption "abstract unix domain socket access" // {
default = true;
};
nix = mkEnableOption "nix daemon access"; nix = mkEnableOption "nix daemon access";
mapRealUid = mkEnableOption "mapping to priv-user uid"; mapRealUid = mkEnableOption "mapping to priv-user uid";

View File

@ -5,6 +5,7 @@
makeBinaryWrapper, makeBinaryWrapper,
xdg-dbus-proxy, xdg-dbus-proxy,
pkg-config, pkg-config,
libcap,
libffi, libffi,
libseccomp, libseccomp,
acl, acl,
@ -80,10 +81,16 @@ buildGoModule rec {
hsu = "/run/wrappers/bin/hsu"; hsu = "/run/wrappers/bin/hsu";
}; };
# nix build environment does not allow acls env = {
env.GO_TEST_SKIP_ACL = 1; # required by libpsx
CGO_LDFLAGS_ALLOW = "-Wl,(--no-whole-archive|--whole-archive)";
# nix build environment does not allow acls
GO_TEST_SKIP_ACL = 1;
};
buildInputs = [ buildInputs = [
libcap
libffi libffi
libseccomp libseccomp
acl acl

View File

@ -21,7 +21,17 @@ func (sys *I) UpdatePermType(et Enablement, path string, perms ...acl.Perm) *I {
sys.lock.Lock() sys.lock.Lock()
defer sys.lock.Unlock() defer sys.lock.Unlock()
sys.ops = append(sys.ops, &ACL{et, path, perms}) sys.ops = append(sys.ops, &ACL{et, path, perms, false})
return sys
}
// UpdatePermTypeOptional appends an acl update Op that silently continues if the target does not exist.
func (sys *I) UpdatePermTypeOptional(et Enablement, path string, perms ...acl.Perm) *I {
sys.lock.Lock()
defer sys.lock.Unlock()
sys.ops = append(sys.ops, &ACL{et, path, perms, true})
return sys return sys
} }
@ -30,14 +40,24 @@ type ACL struct {
et Enablement et Enablement
path string path string
perms acl.Perms perms acl.Perms
// since revert operations are cross-process, the success of apply must not affect the outcome of revert
skipNotExist bool
} }
func (a *ACL) Type() Enablement { return a.et } func (a *ACL) Type() Enablement { return a.et }
func (a *ACL) apply(sys *I) error { func (a *ACL) apply(sys *I) error {
msg.Verbose("applying ACL", a) msg.Verbose("applying ACL", a)
return wrapErrSuffix(acl.Update(a.path, sys.uid, a.perms...), if err := acl.Update(a.path, sys.uid, a.perms...); err != nil {
fmt.Sprintf("cannot apply ACL entry to %q:", a.path)) if !a.skipNotExist || !os.IsNotExist(err) {
return wrapErrSuffix(err,
fmt.Sprintf("cannot apply ACL entry to %q:", a.path))
}
msg.Verbosef("path %q does not exist", a.path)
return nil
}
return nil
} }
func (a *ACL) revert(sys *I, ec *Criteria) error { func (a *ACL) revert(sys *I, ec *Criteria) error {

View File

@ -20,7 +20,7 @@ func TestUpdatePerm(t *testing.T) {
t.Run(tc.path+permSubTestSuffix(tc.perms), func(t *testing.T) { t.Run(tc.path+permSubTestSuffix(tc.perms), func(t *testing.T) {
sys := New(150) sys := New(150)
sys.UpdatePerm(tc.path, tc.perms...) sys.UpdatePerm(tc.path, tc.perms...)
(&tcOp{Process, tc.path}).test(t, sys.ops, []Op{&ACL{Process, tc.path, tc.perms}}, "UpdatePerm") (&tcOp{Process, tc.path}).test(t, sys.ops, []Op{&ACL{Process, tc.path, tc.perms, false}}, "UpdatePerm")
}) })
} }
} }
@ -42,7 +42,7 @@ func TestUpdatePermType(t *testing.T) {
t.Run(tc.path+"_"+TypeString(tc.et)+permSubTestSuffix(tc.perms), func(t *testing.T) { t.Run(tc.path+"_"+TypeString(tc.et)+permSubTestSuffix(tc.perms), func(t *testing.T) {
sys := New(150) sys := New(150)
sys.UpdatePermType(tc.et, tc.path, tc.perms...) sys.UpdatePermType(tc.et, tc.path, tc.perms...)
tc.test(t, sys.ops, []Op{&ACL{tc.et, tc.path, tc.perms}}, "UpdatePermType") tc.test(t, sys.ops, []Op{&ACL{tc.et, tc.path, tc.perms, false}}, "UpdatePermType")
}) })
} }
} }

View File

@ -64,6 +64,10 @@ func (p *Proxy) Start() error {
argF, func(z *container.Container) { argF, func(z *container.Container) {
z.SeccompFlags |= seccomp.AllowMultiarch z.SeccompFlags |= seccomp.AllowMultiarch
z.SeccompPresets |= seccomp.PresetStrict z.SeccompPresets |= seccomp.PresetStrict
// xdg-dbus-proxy requires host abstract UNIX domain socket access
z.ScopeAbstract = false
z.Hostname = "hakurei-dbus" z.Hostname = "hakurei-dbus"
if p.output != nil { if p.output != nil {
z.Stdout, z.Stderr = p.output, p.output z.Stdout, z.Stderr = p.output, p.output

View File

@ -15,6 +15,7 @@ import (
"errors" "errors"
"io/fs" "io/fs"
"log" "log"
"net"
"os" "os"
"syscall" "syscall"
) )
@ -33,6 +34,10 @@ type TestCase struct {
FS *FS `json:"fs"` FS *FS `json:"fs"`
Mount []*MountinfoEntry `json:"mount"` Mount []*MountinfoEntry `json:"mount"`
Seccomp bool `json:"seccomp"` Seccomp bool `json:"seccomp"`
TrySocket string `json:"try_socket,omitempty"`
SocketAbstract bool `json:"socket_abstract,omitempty"`
SocketPathname bool `json:"socket_pathname,omitempty"`
} }
type T struct { type T struct {
@ -125,6 +130,47 @@ func (t *T) MustCheck(want *TestCase) {
} else { } else {
printf("[SKIP] skipping seccomp check") printf("[SKIP] skipping seccomp check")
} }
if want.TrySocket != "" {
abstractConn, abstractErr := net.Dial("unix", "@"+want.TrySocket)
pathnameConn, pathnameErr := net.Dial("unix", want.TrySocket)
ok := true
if abstractErr == nil {
if err := abstractConn.Close(); err != nil {
ok = false
log.Printf("Close: %v", err)
}
}
if pathnameErr == nil {
if err := pathnameConn.Close(); err != nil {
ok = false
log.Printf("Close: %v", err)
}
}
abstractWantErr := error(syscall.EPERM)
pathnameWantErr := error(syscall.ENOENT)
if want.SocketAbstract {
abstractWantErr = nil
}
if want.SocketPathname {
pathnameWantErr = nil
}
if !errors.Is(abstractErr, abstractWantErr) {
ok = false
log.Printf("abstractErr: %v, want %v", abstractErr, abstractWantErr)
}
if !errors.Is(pathnameErr, pathnameWantErr) {
ok = false
log.Printf("pathnameErr: %v, want %v", pathnameErr, pathnameWantErr)
}
if !ok {
os.Exit(1)
}
}
} }
func MustCheckFilter(pid int, want string) { func MustCheckFilter(pid int, want string) {

View File

@ -50,6 +50,9 @@ let
useCommonPaths useCommonPaths
userns userns
; ;
enablements = {
inherit (tc) x11;
};
share = testProgram; share = testProgram;
packages = [ ]; packages = [ ];
path = "${testProgram}/bin/hakurei-test"; path = "${testProgram}/bin/hakurei-test";

View File

@ -25,6 +25,7 @@ in
mapRealUid = false; mapRealUid = false;
useCommonPaths = true; useCommonPaths = true;
userns = false; userns = false;
x11 = true;
# 0, PresetStrict # 0, PresetStrict
expectedFilter = { expectedFilter = {
@ -35,6 +36,7 @@ in
want = { want = {
env = [ env = [
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus"
"DISPLAY=:0"
"HOME=/var/lib/hakurei/u0/a4" "HOME=/var/lib/hakurei/u0/a4"
"PULSE_SERVER=unix:/run/user/65534/pulse/native" "PULSE_SERVER=unix:/run/user/65534/pulse/native"
"SHELL=/run/current-system/sw/bin/bash" "SHELL=/run/current-system/sw/bin/bash"
@ -161,7 +163,9 @@ in
} null; } null;
devices = fs "800001ed" null null; devices = fs "800001ed" null null;
} null; } null;
tmp = fs "800001f8" { } null; tmp = fs "800001f8" {
".X11-unix" = fs "801001ff" { X0 = fs "10001fd" null null; } null;
} null;
usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null; usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
var = fs "800001c0" { var = fs "800001c0" {
lib = fs "800001c0" { lib = fs "800001c0" {
@ -231,10 +235,15 @@ in
(ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000004,gid=1000004") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000004,gid=1000004")
(ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000004,gid=1000004") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000004,gid=1000004")
(ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
(ent "/tmp/.X11-unix" "/tmp/.X11-unix" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
(ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "tmpfs" "tmpfs" ignore) (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "tmpfs" "tmpfs" ignore)
(ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
]; ];
seccomp = true; seccomp = true;
try_socket = "/tmp/.X11-unix/X0";
socket_abstract = false;
socket_pathname = true;
}; };
} }

View File

@ -34,6 +34,7 @@ in
mapRealUid = true; mapRealUid = true;
useCommonPaths = true; useCommonPaths = true;
userns = false; userns = false;
x11 = false;
# 0, PresetStrict # 0, PresetStrict
expectedFilter = { expectedFilter = {
@ -266,5 +267,9 @@ in
]; ];
seccomp = true; seccomp = true;
try_socket = "/tmp/.X11-unix/X0";
socket_abstract = false;
socket_pathname = false;
}; };
} }

View File

@ -34,6 +34,7 @@ in
mapRealUid = false; mapRealUid = false;
useCommonPaths = false; useCommonPaths = false;
userns = true; userns = true;
x11 = false;
# 0, PresetExt | PresetDenyDevel # 0, PresetExt | PresetDenyDevel
expectedFilter = { expectedFilter = {
@ -261,5 +262,9 @@ in
]; ];
seccomp = true; seccomp = true;
try_socket = "/tmp/.X11-unix/X0";
socket_abstract = false;
socket_pathname = false;
}; };
} }

View File

@ -34,6 +34,7 @@ in
mapRealUid = false; mapRealUid = false;
useCommonPaths = false; useCommonPaths = false;
userns = false; userns = false;
x11 = false;
# 0, PresetStrict # 0, PresetStrict
expectedFilter = { expectedFilter = {
@ -259,5 +260,9 @@ in
]; ];
seccomp = true; seccomp = true;
try_socket = "/tmp/.X11-unix/X0";
socket_abstract = false;
socket_pathname = false;
}; };
} }

View File

@ -34,6 +34,7 @@ in
mapRealUid = false; mapRealUid = false;
useCommonPaths = true; useCommonPaths = true;
userns = false; userns = false;
x11 = true;
# 0, PresetExt | PresetDenyNS | PresetDenyDevel # 0, PresetExt | PresetDenyNS | PresetDenyDevel
expectedFilter = { expectedFilter = {
@ -44,6 +45,7 @@ in
want = { want = {
env = [ env = [
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus" "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus"
"DISPLAY=:0"
"HOME=/var/lib/hakurei/u0/a2" "HOME=/var/lib/hakurei/u0/a2"
"PULSE_SERVER=unix:/run/user/65534/pulse/native" "PULSE_SERVER=unix:/run/user/65534/pulse/native"
"SHELL=/run/current-system/sw/bin/bash" "SHELL=/run/current-system/sw/bin/bash"
@ -188,7 +190,9 @@ in
} null; } null;
devices = fs "800001ed" null null; devices = fs "800001ed" null null;
} null; } null;
tmp = fs "800001f8" { } null; tmp = fs "800001f8" {
".X11-unix" = fs "801001ff" { X0 = fs "10001fd" null null; } null;
} null;
usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null; usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
var = fs "800001c0" { var = fs "800001c0" {
lib = fs "800001c0" { lib = fs "800001c0" {
@ -263,10 +267,15 @@ in
(ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002") (ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002")
(ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002") (ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000002,gid=1000002")
(ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent ignore "/run/user/65534/wayland-0" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
(ent "/tmp/.X11-unix" "/tmp/.X11-unix" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
(ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "tmpfs" "tmpfs" ignore) (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "tmpfs" "tmpfs" ignore)
(ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw") (ent ignore "/run/user/65534/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
]; ];
seccomp = true; seccomp = true;
try_socket = "/tmp/.X11-unix/X0";
socket_abstract = false;
socket_pathname = true;
}; };
} }