Compare commits

..

1 Commits

Author SHA1 Message Date
9eb6bc71c4
container: optionally isolate host abstract UNIX domain sockets via landlock
Some checks failed
Test / Hakurei (race detector) (pull_request) Failing after 41m38s
Test / Flake checks (pull_request) Has been skipped
Test / Hpkg (push) Successful in 4m16s
Test / Hpkg (pull_request) Successful in 3m27s
Test / Sandbox (race detector) (pull_request) Successful in 4m1s
Test / Sandbox (race detector) (push) Successful in 4m36s
Test / Create distribution (push) Failing after 32s
Test / Hakurei (pull_request) Failing after 20m33s
Test / Hakurei (race detector) (push) Failing after 22m25s
Test / Sandbox (push) Successful in 2m20s
Test / Sandbox (pull_request) Successful in 2m14s
Test / Create distribution (pull_request) Failing after 28s
Test / Hakurei (push) Failing after 39m36s
Test / Flake checks (push) Has been skipped
2025-08-17 17:44:14 +09:00
10 changed files with 7 additions and 126 deletions

View File

@ -12,7 +12,6 @@ import (
"path" "path"
"regexp" "regexp"
"slices" "slices"
"strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
"syscall" "syscall"
@ -391,22 +390,6 @@ 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

@ -21,17 +21,7 @@ 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, false}) sys.ops = append(sys.ops, &ACL{et, path, perms})
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
} }
@ -40,25 +30,15 @@ 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)
if err := acl.Update(a.path, sys.uid, a.perms...); err != nil { return wrapErrSuffix(acl.Update(a.path, sys.uid, a.perms...),
if !a.skipNotExist || !os.IsNotExist(err) {
return wrapErrSuffix(err,
fmt.Sprintf("cannot apply ACL entry to %q:", a.path)) 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 {
if ec.hasType(a) { if ec.hasType(a) {

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, false}}, "UpdatePerm") (&tcOp{Process, tc.path}).test(t, sys.ops, []Op{&ACL{Process, tc.path, tc.perms}}, "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, false}}, "UpdatePermType") tc.test(t, sys.ops, []Op{&ACL{tc.et, tc.path, tc.perms}}, "UpdatePermType")
}) })
} }
} }

View File

@ -15,7 +15,6 @@ import (
"errors" "errors"
"io/fs" "io/fs"
"log" "log"
"net"
"os" "os"
"syscall" "syscall"
) )
@ -34,10 +33,6 @@ 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 {
@ -130,47 +125,6 @@ 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,9 +50,6 @@ 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,7 +25,6 @@ in
mapRealUid = false; mapRealUid = false;
useCommonPaths = true; useCommonPaths = true;
userns = false; userns = false;
x11 = true;
# 0, PresetStrict # 0, PresetStrict
expectedFilter = { expectedFilter = {
@ -36,7 +35,6 @@ 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"
@ -163,9 +161,7 @@ in
} null; } null;
devices = fs "800001ed" null null; devices = fs "800001ed" null null;
} null; } null;
tmp = fs "800001f8" { tmp = fs "800001f8" { } null;
".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" {
@ -235,15 +231,10 @@ 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,7 +34,6 @@ in
mapRealUid = true; mapRealUid = true;
useCommonPaths = true; useCommonPaths = true;
userns = false; userns = false;
x11 = false;
# 0, PresetStrict # 0, PresetStrict
expectedFilter = { expectedFilter = {
@ -267,9 +266,5 @@ in
]; ];
seccomp = true; seccomp = true;
try_socket = "/tmp/.X11-unix/X0";
socket_abstract = false;
socket_pathname = false;
}; };
} }

View File

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

View File

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

View File

@ -34,7 +34,6 @@ 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 = {
@ -45,7 +44,6 @@ 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"
@ -190,9 +188,7 @@ in
} null; } null;
devices = fs "800001ed" null null; devices = fs "800001ed" null null;
} null; } null;
tmp = fs "800001f8" { tmp = fs "800001f8" { } null;
".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" {
@ -267,15 +263,10 @@ 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;
}; };
} }