Compare commits
1 Commits
a6b2b9df22
...
1fa1ea5cbb
Author | SHA1 | Date | |
---|---|---|---|
1fa1ea5cbb |
@ -7,13 +7,13 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
. "syscall"
|
. "syscall"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
"hakurei.app/container/landlock"
|
"hakurei.app/container/landlock"
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
@ -94,8 +94,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.
|
// Do not [landlock.LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET].
|
||||||
ScopeAbstract bool
|
HostAbstract bool
|
||||||
// Retain CAP_SYS_ADMIN.
|
// Retain CAP_SYS_ADMIN.
|
||||||
Privileged bool
|
Privileged bool
|
||||||
}
|
}
|
||||||
@ -189,10 +189,56 @@ func (p *Container) Start() error {
|
|||||||
"prctl(PR_SET_NO_NEW_PRIVS):")
|
"prctl(PR_SET_NO_NEW_PRIVS):")
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.ScopeAbstract {
|
// landlock: depends on per-thread state but acts on a process group
|
||||||
if err := landlock.ScopeAbstract(); err != nil {
|
{
|
||||||
log.Fatalf("could not scope abstract unix sockets: %v", err)
|
scoped := landlock.LANDLOCK_SCOPE_SIGNAL
|
||||||
|
if !p.HostAbstract {
|
||||||
|
scoped |= landlock.LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
|
||||||
}
|
}
|
||||||
|
rulesetAttr := landlock.NewRulesetAttr(scoped)
|
||||||
|
|
||||||
|
if abi, _, errno := Syscall(seccomp.SYS_LANDLOCK_CREATE_RULESET, 0, 0, landlock.LANDLOCK_CREATE_RULESET_VERSION); abi < 0 {
|
||||||
|
if p.HostAbstract {
|
||||||
|
// landlock can be skipped here as it restricts access to resources
|
||||||
|
// already covered by namespaces (pid)
|
||||||
|
goto landlockOut
|
||||||
|
}
|
||||||
|
return wrapErrSuffix(errno,
|
||||||
|
"landlock does not appear to be enabled:")
|
||||||
|
} else if abi < 6 {
|
||||||
|
if p.HostAbstract {
|
||||||
|
// see above comment
|
||||||
|
goto landlockOut
|
||||||
|
}
|
||||||
|
return msg.WrapErr(ENOSYS,
|
||||||
|
"kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET")
|
||||||
|
} else {
|
||||||
|
msg.Verbosef("landlock abi version %d", abi)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rulesetFd, _, errno := Syscall(seccomp.SYS_LANDLOCK_CREATE_RULESET,
|
||||||
|
uintptr(unsafe.Pointer(&rulesetAttr)),
|
||||||
|
unsafe.Sizeof(rulesetAttr), 0,
|
||||||
|
); rulesetFd < 0 {
|
||||||
|
return wrapErrSuffix(errno,
|
||||||
|
"cannot create landlock ruleset:")
|
||||||
|
} else {
|
||||||
|
CloseOnExec(int(rulesetFd))
|
||||||
|
|
||||||
|
var r uintptr
|
||||||
|
if r, _, errno = Syscall(seccomp.SYS_LANDLOCK_RESTRICT_SELF, rulesetFd, 0, 0); r != 0 {
|
||||||
|
_ = Close(int(rulesetFd))
|
||||||
|
return wrapErrSuffix(errno,
|
||||||
|
"cannot enforce landlock ruleset:")
|
||||||
|
}
|
||||||
|
msg.Verbosef("enforced landlock ruleset scoped %#x", int(scoped))
|
||||||
|
if err := Close(int(rulesetFd)); err != nil {
|
||||||
|
msg.Verbosef("cannot close landlock ruleset: %v", err)
|
||||||
|
// not fatal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
landlockOut:
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Verbose("starting container init")
|
msg.Verbose("starting container init")
|
||||||
|
@ -6,50 +6,12 @@ package landlock
|
|||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LANDLOCK_CREATE_RULESET_VERSION = C.LANDLOCK_CREATE_RULESET_VERSION
|
LANDLOCK_CREATE_RULESET_VERSION = C.LANDLOCK_CREATE_RULESET_VERSION
|
||||||
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = C.LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
|
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET = C.LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET
|
||||||
|
LANDLOCK_SCOPE_SIGNAL = C.LANDLOCK_SCOPE_SIGNAL
|
||||||
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 RulesetAttr = C.struct_landlock_ruleset_attr
|
||||||
|
|
||||||
// ScopeAbstract calls landlock_restrict_self and must be called from a goroutine wired to an m
|
func NewRulesetAttr(scoped int) RulesetAttr { return RulesetAttr{scoped: C.__u64(scoped)} }
|
||||||
// with the process starting from the same goroutine.
|
|
||||||
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))
|
|
||||||
|
|
||||||
r, _, err := syscall.Syscall(SYS_LANDLOCK_RESTRICT_SELF, fd, 0, 0)
|
|
||||||
if r != 0 {
|
|
||||||
return fmt.Errorf("could not restrict self via landlock: errno %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -79,8 +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
|
// share abstract unix socket scope
|
||||||
ScopeAbstract bool `json:"scope_abstract,omitempty"`
|
Abstract bool `json:"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
|
||||||
|
@ -33,7 +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,
|
HostAbstract: s.Abstract,
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -65,8 +65,8 @@ func (p *Proxy) Start() error {
|
|||||||
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
|
// xdg-dbus-proxy fails with scoped abstract unix sockets despite pathname socket being available
|
||||||
z.ScopeAbstract = false
|
z.HostAbstract = true
|
||||||
|
|
||||||
z.Hostname = "hakurei-dbus"
|
z.Hostname = "hakurei-dbus"
|
||||||
if p.output != nil {
|
if p.output != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user