Compare commits
2 Commits
55d8c3bacb
...
c9eeafbbf0
Author | SHA1 | Date | |
---|---|---|---|
c9eeafbbf0 | |||
2f1d42c8dd |
@ -92,8 +92,6 @@ 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
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
. "syscall"
|
. "syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/container/landlock"
|
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -261,12 +260,6 @@ 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
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
int hakurei_scope_abstract_unix_sockets(int* p_errno, int fd);
|
|
@ -1,12 +1,8 @@
|
|||||||
package landlock
|
package landlock
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#cgo linux pkg-config: --static libpsx
|
|
||||||
|
|
||||||
#include <linux/landlock.h>
|
#include <linux/landlock.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
#include "landlock-helper.h"
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
@ -21,10 +17,13 @@ const (
|
|||||||
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = C.LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
|
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = C.LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
|
||||||
|
|
||||||
SYS_LANDLOCK_CREATE_RULESET = C.SYS_landlock_create_ruleset
|
SYS_LANDLOCK_CREATE_RULESET = C.SYS_landlock_create_ruleset
|
||||||
|
SYS_LANDLOCK_RESTRICT_SELF = C.SYS_landlock_restrict_self
|
||||||
)
|
)
|
||||||
|
|
||||||
type LandlockRulesetAttr = C.struct_landlock_ruleset_attr
|
type LandlockRulesetAttr = C.struct_landlock_ruleset_attr
|
||||||
|
|
||||||
|
// ScopeAbstract calls landlock_restrict_self and must be called from a goroutine wired to an m
|
||||||
|
// with the process starting from the same goroutine.
|
||||||
func ScopeAbstract() error {
|
func ScopeAbstract() error {
|
||||||
abi, _, err := syscall.Syscall(SYS_LANDLOCK_CREATE_RULESET, 0, 0, LANDLOCK_CREATE_RULESET_VERSION)
|
abi, _, err := syscall.Syscall(SYS_LANDLOCK_CREATE_RULESET, 0, 0, LANDLOCK_CREATE_RULESET_VERSION)
|
||||||
|
|
||||||
@ -48,10 +47,9 @@ func ScopeAbstract() error {
|
|||||||
|
|
||||||
defer syscall.Close(int(fd))
|
defer syscall.Close(int(fd))
|
||||||
|
|
||||||
var errno C.int
|
r, _, err := syscall.Syscall(SYS_LANDLOCK_RESTRICT_SELF, fd, 0, 0)
|
||||||
if rv := C.hakurei_scope_abstract_unix_sockets(&errno, C.int(fd)); rv != 0 {
|
if r != 0 {
|
||||||
return fmt.Errorf("could not restrict self via landlock: errno %v", errno)
|
return fmt.Errorf("could not restrict self via landlock: errno %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -416,6 +416,22 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
|||||||
seal.sys.ChangeHosts("#" + seal.user.uid.String())
|
seal.sys.ChangeHosts("#" + seal.user.uid.String())
|
||||||
seal.env[display] = d
|
seal.env[display] = d
|
||||||
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
makeBinaryWrapper,
|
makeBinaryWrapper,
|
||||||
xdg-dbus-proxy,
|
xdg-dbus-proxy,
|
||||||
pkg-config,
|
pkg-config,
|
||||||
libcap,
|
|
||||||
libffi,
|
libffi,
|
||||||
libseccomp,
|
libseccomp,
|
||||||
acl,
|
acl,
|
||||||
@ -81,16 +80,10 @@ buildGoModule rec {
|
|||||||
hsu = "/run/wrappers/bin/hsu";
|
hsu = "/run/wrappers/bin/hsu";
|
||||||
};
|
};
|
||||||
|
|
||||||
env = {
|
|
||||||
# required by libpsx
|
|
||||||
CGO_LDFLAGS_ALLOW = "-Wl,(--no-whole-archive|--whole-archive)";
|
|
||||||
|
|
||||||
# nix build environment does not allow acls
|
# nix build environment does not allow acls
|
||||||
GO_TEST_SKIP_ACL = 1;
|
env.GO_TEST_SKIP_ACL = 1;
|
||||||
};
|
|
||||||
|
|
||||||
buildInputs = [
|
buildInputs = [
|
||||||
libcap
|
|
||||||
libffi
|
libffi
|
||||||
libseccomp
|
libseccomp
|
||||||
acl
|
acl
|
||||||
|
@ -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 {
|
||||||
|
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 {
|
||||||
|
@ -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")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ in
|
|||||||
seccomp = true;
|
seccomp = true;
|
||||||
|
|
||||||
try_socket = "/tmp/.X11-unix/X0";
|
try_socket = "/tmp/.X11-unix/X0";
|
||||||
socket_abstract = true;
|
socket_abstract = false;
|
||||||
socket_pathname = true;
|
socket_pathname = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -269,7 +269,7 @@ in
|
|||||||
seccomp = true;
|
seccomp = true;
|
||||||
|
|
||||||
try_socket = "/tmp/.X11-unix/X0";
|
try_socket = "/tmp/.X11-unix/X0";
|
||||||
socket_abstract = true;
|
socket_abstract = false;
|
||||||
socket_pathname = false;
|
socket_pathname = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ in
|
|||||||
seccomp = true;
|
seccomp = true;
|
||||||
|
|
||||||
try_socket = "/tmp/.X11-unix/X0";
|
try_socket = "/tmp/.X11-unix/X0";
|
||||||
socket_abstract = true;
|
socket_abstract = false;
|
||||||
socket_pathname = false;
|
socket_pathname = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -262,7 +262,7 @@ in
|
|||||||
seccomp = true;
|
seccomp = true;
|
||||||
|
|
||||||
try_socket = "/tmp/.X11-unix/X0";
|
try_socket = "/tmp/.X11-unix/X0";
|
||||||
socket_abstract = true;
|
socket_abstract = false;
|
||||||
socket_pathname = false;
|
socket_pathname = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ in
|
|||||||
seccomp = true;
|
seccomp = true;
|
||||||
|
|
||||||
try_socket = "/tmp/.X11-unix/X0";
|
try_socket = "/tmp/.X11-unix/X0";
|
||||||
socket_abstract = true;
|
socket_abstract = false;
|
||||||
socket_pathname = true;
|
socket_pathname = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user