Compare commits
16 Commits
e6967b8bbb
...
6ba19a7ba5
Author | SHA1 | Date | |
---|---|---|---|
6ba19a7ba5 | |||
749a2779f5 | |||
e574042d76 | |||
2b44493e8a | |||
c30dd4e630 | |||
d90da1c8f5 | |||
5853d7700f | |||
d5c7523726 | |||
ddfcc51b91 | |||
8ebedbd88a | |||
84e8142a2d | |||
2c7b7ad845 | |||
72c2b66fc0 | |||
356b42a406 | |||
d9b6d48e7c | |||
087959e81b |
@ -8,7 +8,11 @@
|
|||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://pkg.go.dev/hakurei.app"><img src="https://pkg.go.dev/badge/hakurei.app.svg" alt="Go Reference" /></a>
|
<a href="https://pkg.go.dev/hakurei.app"><img src="https://pkg.go.dev/badge/hakurei.app.svg" alt="Go Reference" /></a>
|
||||||
|
<a href="https://git.gensokyo.uk/security/hakurei/actions"><img src="https://git.gensokyo.uk/security/hakurei/actions/workflows/test.yml/badge.svg?branch=staging&style=flat-square" alt="Gitea Workflow Status" /></a>
|
||||||
|
<br/>
|
||||||
|
<a href="https://git.gensokyo.uk/security/hakurei/releases"><img src="https://img.shields.io/gitea/v/release/security/hakurei?gitea_url=https%3A%2F%2Fgit.gensokyo.uk&color=purple" alt="Release" /></a>
|
||||||
<a href="https://goreportcard.com/report/hakurei.app"><img src="https://goreportcard.com/badge/hakurei.app" alt="Go Report Card" /></a>
|
<a href="https://goreportcard.com/report/hakurei.app"><img src="https://goreportcard.com/badge/hakurei.app" alt="Go Report Card" /></a>
|
||||||
|
<a href="https://hakurei.app"><img src="https://img.shields.io/website?url=https%3A%2F%2Fhakurei.app" alt="Website" /></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Hakurei is a tool for running sandboxed graphical applications as dedicated subordinate users on the Linux kernel.
|
Hakurei is a tool for running sandboxed graphical applications as dedicated subordinate users on the Linux kernel.
|
||||||
|
@ -13,12 +13,11 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app/instance"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/state"
|
|
||||||
"hakurei.app/command"
|
"hakurei.app/command"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
|
"hakurei.app/internal/app"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
@ -33,7 +32,7 @@ func buildCommand(out io.Writer) command.Command {
|
|||||||
Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
|
Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
|
||||||
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in 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 { app.ShimMain(); return errSuccess })
|
||||||
|
|
||||||
c.Command("app", "Load app from configuration file", func(args []string) error {
|
c.Command("app", "Load app from configuration file", func(args []string) error {
|
||||||
if len(args) < 1 {
|
if len(args) < 1 {
|
||||||
@ -244,14 +243,14 @@ func runApp(config *hst.Config) {
|
|||||||
ctx, stop := signal.NotifyContext(context.Background(),
|
ctx, stop := signal.NotifyContext(context.Background(),
|
||||||
syscall.SIGINT, syscall.SIGTERM)
|
syscall.SIGINT, syscall.SIGTERM)
|
||||||
defer stop() // unreachable
|
defer stop() // unreachable
|
||||||
a := instance.MustNew(instance.ISetuid, ctx, std)
|
a := app.MustNew(ctx, std)
|
||||||
|
|
||||||
rs := new(app.RunState)
|
rs := new(app.RunState)
|
||||||
if sa, err := a.Seal(config); err != nil {
|
if sa, err := a.Seal(config); err != nil {
|
||||||
hlog.PrintBaseError(err, "cannot seal app:")
|
hlog.PrintBaseError(err, "cannot seal app:")
|
||||||
internal.Exit(1)
|
internal.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
internal.Exit(instance.PrintRunStateErr(instance.ISetuid, rs, sa.Run(rs)))
|
internal.Exit(app.PrintRunStateErr(rs, sa.Run(rs)))
|
||||||
}
|
}
|
||||||
|
|
||||||
*(*int)(nil) = 0 // not reached
|
*(*int)(nil) = 0 // not reached
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
package instance
|
|
||||||
|
|
||||||
import (
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app/internal/setuid"
|
|
||||||
)
|
|
||||||
|
|
||||||
func PrintRunStateErr(whence int, rs *app.RunState, runErr error) (code int) {
|
|
||||||
switch whence {
|
|
||||||
case ISetuid:
|
|
||||||
return setuid.PrintRunStateErr(rs, runErr)
|
|
||||||
default:
|
|
||||||
panic(syscall.EINVAL)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
// Package instance exposes cross-package implementation details and provides constructors for builtin implementations.
|
|
||||||
package instance
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app/internal/setuid"
|
|
||||||
"hakurei.app/internal/sys"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ISetuid = iota
|
|
||||||
)
|
|
||||||
|
|
||||||
func New(whence int, ctx context.Context, os sys.State) (app.App, error) {
|
|
||||||
switch whence {
|
|
||||||
case ISetuid:
|
|
||||||
return setuid.New(ctx, os)
|
|
||||||
default:
|
|
||||||
return nil, syscall.EINVAL
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MustNew(whence int, ctx context.Context, os sys.State) app.App {
|
|
||||||
a, err := New(whence, ctx, os)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("cannot create app: %v", err)
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
package instance
|
|
||||||
|
|
||||||
import "hakurei.app/cmd/hakurei/internal/app/internal/setuid"
|
|
||||||
|
|
||||||
// ShimMain is the main function of the shim process and runs as the unconstrained target user.
|
|
||||||
func ShimMain() { setuid.ShimMain() }
|
|
@ -10,8 +10,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/state"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,8 +12,8 @@ import (
|
|||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/state"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
@ -5,14 +5,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/state"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testID = app.ID{
|
testID = state.ID{
|
||||||
0x8e, 0x2c, 0x76, 0xb0,
|
0x8e, 0x2c, 0x76, 0xb0,
|
||||||
0x66, 0xda, 0xbe, 0x57,
|
0x66, 0xda, 0xbe, 0x57,
|
||||||
0x4c, 0xf0, 0x73, 0xbd,
|
0x4c, 0xf0, 0x73, 0xbd,
|
||||||
@ -460,7 +459,7 @@ func Test_printPs(t *testing.T) {
|
|||||||
{"no entries", make(state.Entries), false, false, " Instance PID Application Uptime\n"},
|
{"no entries", make(state.Entries), false, false, " Instance PID Application Uptime\n"},
|
||||||
{"no entries short", make(state.Entries), true, false, ""},
|
{"no entries short", make(state.Entries), true, false, ""},
|
||||||
{"nil instance", state.Entries{testID: nil}, false, false, " Instance PID Application Uptime\n"},
|
{"nil instance", state.Entries{testID: nil}, false, false, " Instance PID Application Uptime\n"},
|
||||||
{"state corruption", state.Entries{app.ID{}: testState}, false, false, " Instance PID Application Uptime\n"},
|
{"state corruption", state.Entries{state.ID{}: testState}, false, false, " Instance PID Application Uptime\n"},
|
||||||
|
|
||||||
{"valid pd", state.Entries{testID: &state.State{ID: testID, PID: 1 << 8, Config: new(hst.Config), Time: testAppTime}}, false, false, ` Instance PID Application Uptime
|
{"valid pd", state.Entries{testID: &state.State{ID: testID, PID: 1 << 8, Config: new(hst.Config), Time: testAppTime}}, false, false, ` Instance PID Application Uptime
|
||||||
8e2c76b0 256 0 (app.hakurei.8e2c76b0) 1h2m32s
|
8e2c76b0 256 0 (app.hakurei.8e2c76b0) 1h2m32s
|
||||||
|
45
container/capability.go
Normal file
45
container/capability.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"syscall"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_LINUX_CAPABILITY_VERSION_3 = 0x20080522
|
||||||
|
|
||||||
|
PR_CAP_AMBIENT = 0x2f
|
||||||
|
PR_CAP_AMBIENT_RAISE = 0x2
|
||||||
|
PR_CAP_AMBIENT_CLEAR_ALL = 0x4
|
||||||
|
|
||||||
|
CAP_SYS_ADMIN = 0x15
|
||||||
|
CAP_SETPCAP = 0x8
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
capHeader struct {
|
||||||
|
version uint32
|
||||||
|
pid int32
|
||||||
|
}
|
||||||
|
|
||||||
|
capData struct {
|
||||||
|
effective uint32
|
||||||
|
permitted uint32
|
||||||
|
inheritable uint32
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// See CAP_TO_INDEX in linux/capability.h:
|
||||||
|
func capToIndex(cap uintptr) uintptr { return cap >> 5 }
|
||||||
|
|
||||||
|
// See CAP_TO_MASK in linux/capability.h:
|
||||||
|
func capToMask(cap uintptr) uint32 { return 1 << uint(cap&31) }
|
||||||
|
|
||||||
|
func capset(hdrp *capHeader, datap *[2]capData) error {
|
||||||
|
if _, _, errno := syscall.Syscall(syscall.SYS_CAPSET,
|
||||||
|
uintptr(unsafe.Pointer(hdrp)),
|
||||||
|
uintptr(unsafe.Pointer(&datap[0])), 0); errno != 0 {
|
||||||
|
return errno
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -20,8 +20,21 @@ const (
|
|||||||
// time to wait for linger processes after death of initial process
|
// time to wait for linger processes after death of initial process
|
||||||
residualProcessTimeout = 5 * time.Second
|
residualProcessTimeout = 5 * time.Second
|
||||||
|
|
||||||
// intermediate tmpfs mount point
|
/* intermediate tmpfs mount point
|
||||||
basePath = "/tmp"
|
|
||||||
|
this path might seem like a weird choice, however there are many good reasons to use it:
|
||||||
|
- the contents of this path is never exposed to the container:
|
||||||
|
the tmpfs root established here effectively becomes anonymous after pivot_root
|
||||||
|
- it is safe to assume this path exists and is a directory:
|
||||||
|
this program will not work correctly without a proper /proc and neither will most others
|
||||||
|
- this path belongs to the container init:
|
||||||
|
the container init is not any more privileged or trusted than the rest of the container
|
||||||
|
- this path is only accessible by init and root:
|
||||||
|
the container init sets SUID_DUMP_DISABLE and terminates if that fails;
|
||||||
|
|
||||||
|
it should be noted that none of this should become relevant at any point since the resulting
|
||||||
|
intermediate root tmpfs should be effectively anonymous */
|
||||||
|
intermediateHostPath = "/proc/self/fd"
|
||||||
|
|
||||||
// setup params file descriptor
|
// setup params file descriptor
|
||||||
setupEnv = "HAKUREI_SETUP"
|
setupEnv = "HAKUREI_SETUP"
|
||||||
@ -124,10 +137,10 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := Mount("rootfs", basePath, "tmpfs", MS_NODEV|MS_NOSUID, ""); err != nil {
|
if err := Mount("rootfs", intermediateHostPath, "tmpfs", MS_NODEV|MS_NOSUID, ""); err != nil {
|
||||||
log.Fatalf("cannot mount intermediate root: %v", err)
|
log.Fatalf("cannot mount intermediate root: %v", err)
|
||||||
}
|
}
|
||||||
if err := os.Chdir(basePath); err != nil {
|
if err := os.Chdir(intermediateHostPath); err != nil {
|
||||||
log.Fatalf("cannot enter base path: %v", err)
|
log.Fatalf("cannot enter base path: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,8 +154,8 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
|||||||
if err := os.Mkdir(hostDir, 0755); err != nil {
|
if err := os.Mkdir(hostDir, 0755); err != nil {
|
||||||
log.Fatalf("%v", err)
|
log.Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
// pivot_root uncovers basePath in hostDir
|
// pivot_root uncovers intermediateHostPath in hostDir
|
||||||
if err := PivotRoot(basePath, hostDir); err != nil {
|
if err := PivotRoot(intermediateHostPath, hostDir); err != nil {
|
||||||
log.Fatalf("cannot pivot into intermediate root: %v", err)
|
log.Fatalf("cannot pivot into intermediate root: %v", err)
|
||||||
}
|
}
|
||||||
if err := os.Chdir("/"); err != nil {
|
if err := os.Chdir("/"); err != nil {
|
||||||
@ -198,7 +211,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, _, errno := Syscall(PR_SET_NO_NEW_PRIVS, 1, 0, 0); errno != 0 {
|
if _, _, errno := Syscall(SYS_PRCTL, PR_SET_NO_NEW_PRIVS, 1, 0); errno != 0 {
|
||||||
log.Fatalf("prctl(PR_SET_NO_NEW_PRIVS): %v", errno)
|
log.Fatalf("prctl(PR_SET_NO_NEW_PRIVS): %v", errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
container/seccomp/hash_amd64_test.go
Normal file
24
container/seccomp/hash_amd64_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package seccomp_test
|
||||||
|
|
||||||
|
import . "hakurei.app/container/seccomp"
|
||||||
|
|
||||||
|
var bpfExpected = bpfLookup{
|
||||||
|
{AllowMultiarch | AllowCAN |
|
||||||
|
AllowBluetooth, PresetExt |
|
||||||
|
PresetDenyNS | PresetDenyTTY | PresetDenyDevel |
|
||||||
|
PresetLinux32}: toHash(
|
||||||
|
"e99dd345e195413473d3cbee07b4ed57b908bfa89ea2072fe93482847f50b5b758da17e74ca2bbc00813de49a2b9bf834c024ed48850be69b68a9a4c5f53a9db"),
|
||||||
|
|
||||||
|
{0, 0}: toHash(
|
||||||
|
"95ec69d017733e072160e0da80fdebecdf27ae8166f5e2a731270c98ea2d2946cb5231029063668af215879155da21aca79b070e04c0ee9acdf58f55cfa815a5"),
|
||||||
|
{0, PresetExt}: toHash(
|
||||||
|
"dc7f2e1c5e829b79ebb7efc759150f54a83a75c8df6fee4dce5dadc4736c585d4deebfeb3c7969af3a077e90b77bb4741db05d90997c8659b95891206ac9952d"),
|
||||||
|
{0, PresetStrict}: toHash(
|
||||||
|
"e880298df2bd6751d0040fc21bc0ed4c00f95dc0d7ba506c244d8b8cf6866dba8ef4a33296f287b66cccc1d78e97026597f84cc7dec1573e148960fbd35cd735"),
|
||||||
|
{0, PresetDenyNS | PresetDenyTTY | PresetDenyDevel}: toHash(
|
||||||
|
"39871b93ffafc8b979fcedc0b0c37b9e03922f5b02748dc5c3c17c92527f6e022ede1f48bff59246ea452c0d1de54827808b1a6f84f32bbde1aa02ae30eedcfa"),
|
||||||
|
{0, PresetExt | PresetDenyDevel}: toHash(
|
||||||
|
"c698b081ff957afe17a6d94374537d37f2a63f6f9dd75da7546542407a9e32476ebda3312ba7785d7f618542bcfaf27ca27dcc2dddba852069d28bcfe8cad39a"),
|
||||||
|
{0, PresetExt | PresetDenyNS | PresetDenyDevel}: toHash(
|
||||||
|
"0b76007476c1c9e25dbf674c29fdf609a1656a70063e49327654e1b5360ad3da06e1a3e32bf80e961c5516ad83d4b9e7e9bde876a93797e27627d2555c25858b"),
|
||||||
|
}
|
24
container/seccomp/hash_arm64_test.go
Normal file
24
container/seccomp/hash_arm64_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package seccomp_test
|
||||||
|
|
||||||
|
import . "hakurei.app/container/seccomp"
|
||||||
|
|
||||||
|
var bpfExpected = bpfLookup{
|
||||||
|
{AllowMultiarch | AllowCAN |
|
||||||
|
AllowBluetooth, PresetExt |
|
||||||
|
PresetDenyNS | PresetDenyTTY | PresetDenyDevel |
|
||||||
|
PresetLinux32}: toHash(
|
||||||
|
"1431c013f2ddac3adae577821cb5d351b1514e7c754d62346ddffd31f46ea02fb368e46e3f8104f81019617e721fe687ddd83f1e79580622ccc991da12622170"),
|
||||||
|
|
||||||
|
{0, 0}: toHash(
|
||||||
|
"450c21210dbf124dfa7ae56d0130f9c2e24b26f5bce8795ee75766c75850438ff9e7d91c5e73d63bbe51a5d4b06c2a0791c4de2903b2b9805f16265318183235"),
|
||||||
|
{0, PresetExt}: toHash(
|
||||||
|
"d971d0f2d30f54ac920fc6d84df2be279e9fd28cf2d48be775d7fdbd790b750e1369401cd3bb8bcf9ba3adb91874fe9792d9e3f62209b8ee59c9fdd2ddd10c7b"),
|
||||||
|
{0, PresetStrict}: toHash(
|
||||||
|
"79318538a3dc851314b6bd96f10d5861acb2aa7e13cb8de0619d0f6a76709d67f01ef3fd67e195862b02f9711e5b769bc4d1eb4fc0dfc41a723c89c968a93297"),
|
||||||
|
{0, PresetDenyNS | PresetDenyTTY | PresetDenyDevel}: toHash(
|
||||||
|
"228286c2f5df8e44463be0a57b91977b7f38b63b09e5d98dfabe5c61545b8f9ac3e5ea3d86df55d7edf2ce61875f0a5a85c0ab82800bef178c42533e8bdc9a6c"),
|
||||||
|
{0, PresetExt | PresetDenyDevel}: toHash(
|
||||||
|
"433ce9b911282d6dcc8029319fb79b816b60d5a795ec8fc94344dd027614d68f023166a91bb881faaeeedd26e3d89474e141e5a69a97e93b8984ca8f14999980"),
|
||||||
|
{0, PresetExt | PresetDenyNS | PresetDenyDevel}: toHash(
|
||||||
|
"cf1f4dc87436ba8ec95d268b663a6397bb0b4a5ac64d8557e6cc529d8b0f6f65dad3a92b62ed29d85eee9c6dde1267757a4d0f86032e8a45ca1bceadfa34cf5e"),
|
||||||
|
}
|
28
container/seccomp/hash_test.go
Normal file
28
container/seccomp/hash_test.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package seccomp_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
|
||||||
|
"hakurei.app/container/seccomp"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
bpfPreset = struct {
|
||||||
|
seccomp.ExportFlag
|
||||||
|
seccomp.FilterPreset
|
||||||
|
}
|
||||||
|
bpfLookup map[bpfPreset][]byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func toHash(s string) []byte {
|
||||||
|
if len(s) != 128 {
|
||||||
|
panic("bad sha512 string length")
|
||||||
|
}
|
||||||
|
if v, err := hex.DecodeString(s); err != nil {
|
||||||
|
panic(err.Error())
|
||||||
|
} else if len(v) != 64 {
|
||||||
|
panic("unreachable")
|
||||||
|
} else {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ package seccomp
|
|||||||
#cgo linux pkg-config: --static libseccomp
|
#cgo linux pkg-config: --static libseccomp
|
||||||
|
|
||||||
#include <libseccomp-helper.h>
|
#include <libseccomp-helper.h>
|
||||||
|
#include <sys/personality.h>
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
@ -14,6 +15,11 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PER_LINUX = C.PER_LINUX
|
||||||
|
PER_LINUX32 = C.PER_LINUX32
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidRules = errors.New("invalid native rules slice")
|
ErrInvalidRules = errors.New("invalid native rules slice")
|
||||||
)
|
)
|
||||||
|
@ -14,81 +14,28 @@ import (
|
|||||||
func TestExport(t *testing.T) {
|
func TestExport(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
presets FilterPreset
|
|
||||||
flags ExportFlag
|
flags ExportFlag
|
||||||
want []byte
|
presets FilterPreset
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
{"compat", 0, 0, []byte{
|
{"everything", AllowMultiarch | AllowCAN |
|
||||||
0x95, 0xec, 0x69, 0xd0, 0x17, 0x73, 0x3e, 0x07,
|
AllowBluetooth, PresetExt |
|
||||||
0x21, 0x60, 0xe0, 0xda, 0x80, 0xfd, 0xeb, 0xec,
|
|
||||||
0xdf, 0x27, 0xae, 0x81, 0x66, 0xf5, 0xe2, 0xa7,
|
|
||||||
0x31, 0x27, 0x0c, 0x98, 0xea, 0x2d, 0x29, 0x46,
|
|
||||||
0xcb, 0x52, 0x31, 0x02, 0x90, 0x63, 0x66, 0x8a,
|
|
||||||
0xf2, 0x15, 0x87, 0x91, 0x55, 0xda, 0x21, 0xac,
|
|
||||||
0xa7, 0x9b, 0x07, 0x0e, 0x04, 0xc0, 0xee, 0x9a,
|
|
||||||
0xcd, 0xf5, 0x8f, 0x55, 0xcf, 0xa8, 0x15, 0xa5,
|
|
||||||
}, false},
|
|
||||||
{"base", PresetExt, 0, []byte{
|
|
||||||
0xdc, 0x7f, 0x2e, 0x1c, 0x5e, 0x82, 0x9b, 0x79,
|
|
||||||
0xeb, 0xb7, 0xef, 0xc7, 0x59, 0x15, 0x0f, 0x54,
|
|
||||||
0xa8, 0x3a, 0x75, 0xc8, 0xdf, 0x6f, 0xee, 0x4d,
|
|
||||||
0xce, 0x5d, 0xad, 0xc4, 0x73, 0x6c, 0x58, 0x5d,
|
|
||||||
0x4d, 0xee, 0xbf, 0xeb, 0x3c, 0x79, 0x69, 0xaf,
|
|
||||||
0x3a, 0x07, 0x7e, 0x90, 0xb7, 0x7b, 0xb4, 0x74,
|
|
||||||
0x1d, 0xb0, 0x5d, 0x90, 0x99, 0x7c, 0x86, 0x59,
|
|
||||||
0xb9, 0x58, 0x91, 0x20, 0x6a, 0xc9, 0x95, 0x2d,
|
|
||||||
}, false},
|
|
||||||
{"everything", PresetExt |
|
|
||||||
PresetDenyNS | PresetDenyTTY | PresetDenyDevel |
|
PresetDenyNS | PresetDenyTTY | PresetDenyDevel |
|
||||||
PresetLinux32, AllowMultiarch | AllowCAN |
|
PresetLinux32, false},
|
||||||
AllowBluetooth, []byte{
|
|
||||||
0xe9, 0x9d, 0xd3, 0x45, 0xe1, 0x95, 0x41, 0x34,
|
{"compat", 0, 0, false},
|
||||||
0x73, 0xd3, 0xcb, 0xee, 0x07, 0xb4, 0xed, 0x57,
|
{"base", 0, PresetExt, false},
|
||||||
0xb9, 0x08, 0xbf, 0xa8, 0x9e, 0xa2, 0x07, 0x2f,
|
{"strict", 0, PresetStrict, false},
|
||||||
0xe9, 0x34, 0x82, 0x84, 0x7f, 0x50, 0xb5, 0xb7,
|
{"strict compat", 0, PresetDenyNS | PresetDenyTTY | PresetDenyDevel, false},
|
||||||
0x58, 0xda, 0x17, 0xe7, 0x4c, 0xa2, 0xbb, 0xc0,
|
{"hakurei default", 0, PresetExt | PresetDenyDevel, false},
|
||||||
0x08, 0x13, 0xde, 0x49, 0xa2, 0xb9, 0xbf, 0x83,
|
{"hakurei tty", 0, PresetExt | PresetDenyNS | PresetDenyDevel, false},
|
||||||
0x4c, 0x02, 0x4e, 0xd4, 0x88, 0x50, 0xbe, 0x69,
|
|
||||||
0xb6, 0x8a, 0x9a, 0x4c, 0x5f, 0x53, 0xa9, 0xdb,
|
|
||||||
}, false},
|
|
||||||
{"strict", PresetStrict, 0, []byte{
|
|
||||||
0xe8, 0x80, 0x29, 0x8d, 0xf2, 0xbd, 0x67, 0x51,
|
|
||||||
0xd0, 0x04, 0x0f, 0xc2, 0x1b, 0xc0, 0xed, 0x4c,
|
|
||||||
0x00, 0xf9, 0x5d, 0xc0, 0xd7, 0xba, 0x50, 0x6c,
|
|
||||||
0x24, 0x4d, 0x8b, 0x8c, 0xf6, 0x86, 0x6d, 0xba,
|
|
||||||
0x8e, 0xf4, 0xa3, 0x32, 0x96, 0xf2, 0x87, 0xb6,
|
|
||||||
0x6c, 0xcc, 0xc1, 0xd7, 0x8e, 0x97, 0x02, 0x65,
|
|
||||||
0x97, 0xf8, 0x4c, 0xc7, 0xde, 0xc1, 0x57, 0x3e,
|
|
||||||
0x14, 0x89, 0x60, 0xfb, 0xd3, 0x5c, 0xd7, 0x35,
|
|
||||||
}, false},
|
|
||||||
{"strict compat", 0 |
|
|
||||||
PresetDenyNS | PresetDenyTTY | PresetDenyDevel, 0, []byte{
|
|
||||||
0x39, 0x87, 0x1b, 0x93, 0xff, 0xaf, 0xc8, 0xb9,
|
|
||||||
0x79, 0xfc, 0xed, 0xc0, 0xb0, 0xc3, 0x7b, 0x9e,
|
|
||||||
0x03, 0x92, 0x2f, 0x5b, 0x02, 0x74, 0x8d, 0xc5,
|
|
||||||
0xc3, 0xc1, 0x7c, 0x92, 0x52, 0x7f, 0x6e, 0x02,
|
|
||||||
0x2e, 0xde, 0x1f, 0x48, 0xbf, 0xf5, 0x92, 0x46,
|
|
||||||
0xea, 0x45, 0x2c, 0x0d, 0x1d, 0xe5, 0x48, 0x27,
|
|
||||||
0x80, 0x8b, 0x1a, 0x6f, 0x84, 0xf3, 0x2b, 0xbd,
|
|
||||||
0xe1, 0xaa, 0x02, 0xae, 0x30, 0xee, 0xdc, 0xfa,
|
|
||||||
}, false},
|
|
||||||
{"hakurei default", PresetExt | PresetDenyDevel, 0, []byte{
|
|
||||||
0xc6, 0x98, 0xb0, 0x81, 0xff, 0x95, 0x7a, 0xfe,
|
|
||||||
0x17, 0xa6, 0xd9, 0x43, 0x74, 0x53, 0x7d, 0x37,
|
|
||||||
0xf2, 0xa6, 0x3f, 0x6f, 0x9d, 0xd7, 0x5d, 0xa7,
|
|
||||||
0x54, 0x65, 0x42, 0x40, 0x7a, 0x9e, 0x32, 0x47,
|
|
||||||
0x6e, 0xbd, 0xa3, 0x31, 0x2b, 0xa7, 0x78, 0x5d,
|
|
||||||
0x7f, 0x61, 0x85, 0x42, 0xbc, 0xfa, 0xf2, 0x7c,
|
|
||||||
0xa2, 0x7d, 0xcc, 0x2d, 0xdd, 0xba, 0x85, 0x20,
|
|
||||||
0x69, 0xd2, 0x8b, 0xcf, 0xe8, 0xca, 0xd3, 0x9a,
|
|
||||||
}, false},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, 8)
|
buf := make([]byte, 8)
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
e := New(Preset(tc.presets, tc.flags), tc.flags)
|
e := New(Preset(tc.presets, tc.flags), tc.flags)
|
||||||
|
want := bpfExpected[bpfPreset{tc.flags, tc.presets}]
|
||||||
digest := sha512.New()
|
digest := sha512.New()
|
||||||
|
|
||||||
if _, err := io.CopyBuffer(digest, e, buf); (err != nil) != tc.wantErr {
|
if _, err := io.CopyBuffer(digest, e, buf); (err != nil) != tc.wantErr {
|
||||||
@ -98,9 +45,9 @@ func TestExport(t *testing.T) {
|
|||||||
if err := e.Close(); err != nil {
|
if err := e.Close(); err != nil {
|
||||||
t.Errorf("Close: error = %v", err)
|
t.Errorf("Close: error = %v", err)
|
||||||
}
|
}
|
||||||
if got := digest.Sum(nil); !slices.Equal(got, tc.want) {
|
if got := digest.Sum(nil); !slices.Equal(got, want) {
|
||||||
t.Fatalf("Export() hash = %x, want %x",
|
t.Fatalf("Export() hash = %x, want %x",
|
||||||
got, tc.want)
|
got, want)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -4,8 +4,14 @@
|
|||||||
# license that can be found in the LICENSE file.
|
# license that can be found in the LICENSE file.
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
|
use POSIX ();
|
||||||
|
|
||||||
my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
|
my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
|
||||||
|
my $uname_arch = (POSIX::uname)[4];
|
||||||
|
my %syscall_cutoff_arch = (
|
||||||
|
"x86_64" => 302,
|
||||||
|
"aarch64" => 281,
|
||||||
|
);
|
||||||
|
|
||||||
print <<EOF;
|
print <<EOF;
|
||||||
// $command
|
// $command
|
||||||
@ -30,7 +36,7 @@ sub fmt {
|
|||||||
}
|
}
|
||||||
(my $name_upper = $name) =~ y/a-z/A-Z/;
|
(my $name_upper = $name) =~ y/a-z/A-Z/;
|
||||||
$num = $num + $offset;
|
$num = $num + $offset;
|
||||||
if($num > 302){ # not wired in Go standard library
|
if($num > $syscall_cutoff_arch{$uname_arch}){ # not wired in Go standard library
|
||||||
if($state < 0){
|
if($state < 0){
|
||||||
print " \"$name\": SYS_$name_upper,\n";
|
print " \"$name\": SYS_$name_upper,\n";
|
||||||
}
|
}
|
||||||
|
@ -4,15 +4,9 @@ package seccomp
|
|||||||
#cgo linux pkg-config: --static libseccomp
|
#cgo linux pkg-config: --static libseccomp
|
||||||
|
|
||||||
#include <seccomp.h>
|
#include <seccomp.h>
|
||||||
#include <sys/personality.h>
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
const (
|
|
||||||
PER_LINUX = C.PER_LINUX
|
|
||||||
PER_LINUX32 = C.PER_LINUX32
|
|
||||||
)
|
|
||||||
|
|
||||||
var syscallNumExtra = map[string]int{
|
var syscallNumExtra = map[string]int{
|
||||||
"umount": SYS_UMOUNT,
|
"umount": SYS_UMOUNT,
|
||||||
"subpage_prot": SYS_SUBPAGE_PROT,
|
"subpage_prot": SYS_SUBPAGE_PROT,
|
||||||
|
61
container/seccomp/syscall_extra_linux_arm64.go
Normal file
61
container/seccomp/syscall_extra_linux_arm64.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package seccomp
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo linux pkg-config: --static libseccomp
|
||||||
|
|
||||||
|
#include <seccomp.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const (
|
||||||
|
SYS_NEWFSTATAT = syscall.SYS_FSTATAT
|
||||||
|
)
|
||||||
|
|
||||||
|
var syscallNumExtra = map[string]int{
|
||||||
|
"uselib": SYS_USELIB,
|
||||||
|
"clock_adjtime64": SYS_CLOCK_ADJTIME64,
|
||||||
|
"clock_settime64": SYS_CLOCK_SETTIME64,
|
||||||
|
"umount": SYS_UMOUNT,
|
||||||
|
"chown": SYS_CHOWN,
|
||||||
|
"chown32": SYS_CHOWN32,
|
||||||
|
"fchown32": SYS_FCHOWN32,
|
||||||
|
"lchown": SYS_LCHOWN,
|
||||||
|
"lchown32": SYS_LCHOWN32,
|
||||||
|
"setgid32": SYS_SETGID32,
|
||||||
|
"setgroups32": SYS_SETGROUPS32,
|
||||||
|
"setregid32": SYS_SETREGID32,
|
||||||
|
"setresgid32": SYS_SETRESGID32,
|
||||||
|
"setresuid32": SYS_SETRESUID32,
|
||||||
|
"setreuid32": SYS_SETREUID32,
|
||||||
|
"setuid32": SYS_SETUID32,
|
||||||
|
"modify_ldt": SYS_MODIFY_LDT,
|
||||||
|
"subpage_prot": SYS_SUBPAGE_PROT,
|
||||||
|
"switch_endian": SYS_SWITCH_ENDIAN,
|
||||||
|
"vm86": SYS_VM86,
|
||||||
|
"vm86old": SYS_VM86OLD,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SYS_USELIB = C.__SNR_uselib
|
||||||
|
SYS_CLOCK_ADJTIME64 = C.__SNR_clock_adjtime64
|
||||||
|
SYS_CLOCK_SETTIME64 = C.__SNR_clock_settime64
|
||||||
|
SYS_UMOUNT = C.__SNR_umount
|
||||||
|
SYS_CHOWN = C.__SNR_chown
|
||||||
|
SYS_CHOWN32 = C.__SNR_chown32
|
||||||
|
SYS_FCHOWN32 = C.__SNR_fchown32
|
||||||
|
SYS_LCHOWN = C.__SNR_lchown
|
||||||
|
SYS_LCHOWN32 = C.__SNR_lchown32
|
||||||
|
SYS_SETGID32 = C.__SNR_setgid32
|
||||||
|
SYS_SETGROUPS32 = C.__SNR_setgroups32
|
||||||
|
SYS_SETREGID32 = C.__SNR_setregid32
|
||||||
|
SYS_SETRESGID32 = C.__SNR_setresgid32
|
||||||
|
SYS_SETRESUID32 = C.__SNR_setresuid32
|
||||||
|
SYS_SETREUID32 = C.__SNR_setreuid32
|
||||||
|
SYS_SETUID32 = C.__SNR_setuid32
|
||||||
|
SYS_MODIFY_LDT = C.__SNR_modify_ldt
|
||||||
|
SYS_SUBPAGE_PROT = C.__SNR_subpage_prot
|
||||||
|
SYS_SWITCH_ENDIAN = C.__SNR_switch_endian
|
||||||
|
SYS_VM86 = C.__SNR_vm86
|
||||||
|
SYS_VM86OLD = C.__SNR_vm86old
|
||||||
|
)
|
382
container/seccomp/syscall_linux_arm64.go
Normal file
382
container/seccomp/syscall_linux_arm64.go
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
// mksysnum_linux.pl /usr/include/asm/unistd_64.h
|
||||||
|
// Code generated by the command above; DO NOT EDIT.
|
||||||
|
|
||||||
|
package seccomp
|
||||||
|
|
||||||
|
import . "syscall"
|
||||||
|
|
||||||
|
var syscallNum = map[string]int{
|
||||||
|
"io_setup": SYS_IO_SETUP,
|
||||||
|
"io_destroy": SYS_IO_DESTROY,
|
||||||
|
"io_submit": SYS_IO_SUBMIT,
|
||||||
|
"io_cancel": SYS_IO_CANCEL,
|
||||||
|
"io_getevents": SYS_IO_GETEVENTS,
|
||||||
|
"setxattr": SYS_SETXATTR,
|
||||||
|
"lsetxattr": SYS_LSETXATTR,
|
||||||
|
"fsetxattr": SYS_FSETXATTR,
|
||||||
|
"getxattr": SYS_GETXATTR,
|
||||||
|
"lgetxattr": SYS_LGETXATTR,
|
||||||
|
"fgetxattr": SYS_FGETXATTR,
|
||||||
|
"listxattr": SYS_LISTXATTR,
|
||||||
|
"llistxattr": SYS_LLISTXATTR,
|
||||||
|
"flistxattr": SYS_FLISTXATTR,
|
||||||
|
"removexattr": SYS_REMOVEXATTR,
|
||||||
|
"lremovexattr": SYS_LREMOVEXATTR,
|
||||||
|
"fremovexattr": SYS_FREMOVEXATTR,
|
||||||
|
"getcwd": SYS_GETCWD,
|
||||||
|
"lookup_dcookie": SYS_LOOKUP_DCOOKIE,
|
||||||
|
"eventfd2": SYS_EVENTFD2,
|
||||||
|
"epoll_create1": SYS_EPOLL_CREATE1,
|
||||||
|
"epoll_ctl": SYS_EPOLL_CTL,
|
||||||
|
"epoll_pwait": SYS_EPOLL_PWAIT,
|
||||||
|
"dup": SYS_DUP,
|
||||||
|
"dup3": SYS_DUP3,
|
||||||
|
"fcntl": SYS_FCNTL,
|
||||||
|
"inotify_init1": SYS_INOTIFY_INIT1,
|
||||||
|
"inotify_add_watch": SYS_INOTIFY_ADD_WATCH,
|
||||||
|
"inotify_rm_watch": SYS_INOTIFY_RM_WATCH,
|
||||||
|
"ioctl": SYS_IOCTL,
|
||||||
|
"ioprio_set": SYS_IOPRIO_SET,
|
||||||
|
"ioprio_get": SYS_IOPRIO_GET,
|
||||||
|
"flock": SYS_FLOCK,
|
||||||
|
"mknodat": SYS_MKNODAT,
|
||||||
|
"mkdirat": SYS_MKDIRAT,
|
||||||
|
"unlinkat": SYS_UNLINKAT,
|
||||||
|
"symlinkat": SYS_SYMLINKAT,
|
||||||
|
"linkat": SYS_LINKAT,
|
||||||
|
"renameat": SYS_RENAMEAT,
|
||||||
|
"umount2": SYS_UMOUNT2,
|
||||||
|
"mount": SYS_MOUNT,
|
||||||
|
"pivot_root": SYS_PIVOT_ROOT,
|
||||||
|
"nfsservctl": SYS_NFSSERVCTL,
|
||||||
|
"statfs": SYS_STATFS,
|
||||||
|
"fstatfs": SYS_FSTATFS,
|
||||||
|
"truncate": SYS_TRUNCATE,
|
||||||
|
"ftruncate": SYS_FTRUNCATE,
|
||||||
|
"fallocate": SYS_FALLOCATE,
|
||||||
|
"faccessat": SYS_FACCESSAT,
|
||||||
|
"chdir": SYS_CHDIR,
|
||||||
|
"fchdir": SYS_FCHDIR,
|
||||||
|
"chroot": SYS_CHROOT,
|
||||||
|
"fchmod": SYS_FCHMOD,
|
||||||
|
"fchmodat": SYS_FCHMODAT,
|
||||||
|
"fchownat": SYS_FCHOWNAT,
|
||||||
|
"fchown": SYS_FCHOWN,
|
||||||
|
"openat": SYS_OPENAT,
|
||||||
|
"close": SYS_CLOSE,
|
||||||
|
"vhangup": SYS_VHANGUP,
|
||||||
|
"pipe2": SYS_PIPE2,
|
||||||
|
"quotactl": SYS_QUOTACTL,
|
||||||
|
"getdents64": SYS_GETDENTS64,
|
||||||
|
"lseek": SYS_LSEEK,
|
||||||
|
"read": SYS_READ,
|
||||||
|
"write": SYS_WRITE,
|
||||||
|
"readv": SYS_READV,
|
||||||
|
"writev": SYS_WRITEV,
|
||||||
|
"pread64": SYS_PREAD64,
|
||||||
|
"pwrite64": SYS_PWRITE64,
|
||||||
|
"preadv": SYS_PREADV,
|
||||||
|
"pwritev": SYS_PWRITEV,
|
||||||
|
"sendfile": SYS_SENDFILE,
|
||||||
|
"pselect6": SYS_PSELECT6,
|
||||||
|
"ppoll": SYS_PPOLL,
|
||||||
|
"signalfd4": SYS_SIGNALFD4,
|
||||||
|
"vmsplice": SYS_VMSPLICE,
|
||||||
|
"splice": SYS_SPLICE,
|
||||||
|
"tee": SYS_TEE,
|
||||||
|
"readlinkat": SYS_READLINKAT,
|
||||||
|
"newfstatat": SYS_NEWFSTATAT,
|
||||||
|
"fstat": SYS_FSTAT,
|
||||||
|
"sync": SYS_SYNC,
|
||||||
|
"fsync": SYS_FSYNC,
|
||||||
|
"fdatasync": SYS_FDATASYNC,
|
||||||
|
"sync_file_range": SYS_SYNC_FILE_RANGE,
|
||||||
|
"timerfd_create": SYS_TIMERFD_CREATE,
|
||||||
|
"timerfd_settime": SYS_TIMERFD_SETTIME,
|
||||||
|
"timerfd_gettime": SYS_TIMERFD_GETTIME,
|
||||||
|
"utimensat": SYS_UTIMENSAT,
|
||||||
|
"acct": SYS_ACCT,
|
||||||
|
"capget": SYS_CAPGET,
|
||||||
|
"capset": SYS_CAPSET,
|
||||||
|
"personality": SYS_PERSONALITY,
|
||||||
|
"exit": SYS_EXIT,
|
||||||
|
"exit_group": SYS_EXIT_GROUP,
|
||||||
|
"waitid": SYS_WAITID,
|
||||||
|
"set_tid_address": SYS_SET_TID_ADDRESS,
|
||||||
|
"unshare": SYS_UNSHARE,
|
||||||
|
"futex": SYS_FUTEX,
|
||||||
|
"set_robust_list": SYS_SET_ROBUST_LIST,
|
||||||
|
"get_robust_list": SYS_GET_ROBUST_LIST,
|
||||||
|
"nanosleep": SYS_NANOSLEEP,
|
||||||
|
"getitimer": SYS_GETITIMER,
|
||||||
|
"setitimer": SYS_SETITIMER,
|
||||||
|
"kexec_load": SYS_KEXEC_LOAD,
|
||||||
|
"init_module": SYS_INIT_MODULE,
|
||||||
|
"delete_module": SYS_DELETE_MODULE,
|
||||||
|
"timer_create": SYS_TIMER_CREATE,
|
||||||
|
"timer_gettime": SYS_TIMER_GETTIME,
|
||||||
|
"timer_getoverrun": SYS_TIMER_GETOVERRUN,
|
||||||
|
"timer_settime": SYS_TIMER_SETTIME,
|
||||||
|
"timer_delete": SYS_TIMER_DELETE,
|
||||||
|
"clock_settime": SYS_CLOCK_SETTIME,
|
||||||
|
"clock_gettime": SYS_CLOCK_GETTIME,
|
||||||
|
"clock_getres": SYS_CLOCK_GETRES,
|
||||||
|
"clock_nanosleep": SYS_CLOCK_NANOSLEEP,
|
||||||
|
"syslog": SYS_SYSLOG,
|
||||||
|
"ptrace": SYS_PTRACE,
|
||||||
|
"sched_setparam": SYS_SCHED_SETPARAM,
|
||||||
|
"sched_setscheduler": SYS_SCHED_SETSCHEDULER,
|
||||||
|
"sched_getscheduler": SYS_SCHED_GETSCHEDULER,
|
||||||
|
"sched_getparam": SYS_SCHED_GETPARAM,
|
||||||
|
"sched_setaffinity": SYS_SCHED_SETAFFINITY,
|
||||||
|
"sched_getaffinity": SYS_SCHED_GETAFFINITY,
|
||||||
|
"sched_yield": SYS_SCHED_YIELD,
|
||||||
|
"sched_get_priority_max": SYS_SCHED_GET_PRIORITY_MAX,
|
||||||
|
"sched_get_priority_min": SYS_SCHED_GET_PRIORITY_MIN,
|
||||||
|
"sched_rr_get_interval": SYS_SCHED_RR_GET_INTERVAL,
|
||||||
|
"restart_syscall": SYS_RESTART_SYSCALL,
|
||||||
|
"kill": SYS_KILL,
|
||||||
|
"tkill": SYS_TKILL,
|
||||||
|
"tgkill": SYS_TGKILL,
|
||||||
|
"sigaltstack": SYS_SIGALTSTACK,
|
||||||
|
"rt_sigsuspend": SYS_RT_SIGSUSPEND,
|
||||||
|
"rt_sigaction": SYS_RT_SIGACTION,
|
||||||
|
"rt_sigprocmask": SYS_RT_SIGPROCMASK,
|
||||||
|
"rt_sigpending": SYS_RT_SIGPENDING,
|
||||||
|
"rt_sigtimedwait": SYS_RT_SIGTIMEDWAIT,
|
||||||
|
"rt_sigqueueinfo": SYS_RT_SIGQUEUEINFO,
|
||||||
|
"rt_sigreturn": SYS_RT_SIGRETURN,
|
||||||
|
"setpriority": SYS_SETPRIORITY,
|
||||||
|
"getpriority": SYS_GETPRIORITY,
|
||||||
|
"reboot": SYS_REBOOT,
|
||||||
|
"setregid": SYS_SETREGID,
|
||||||
|
"setgid": SYS_SETGID,
|
||||||
|
"setreuid": SYS_SETREUID,
|
||||||
|
"setuid": SYS_SETUID,
|
||||||
|
"setresuid": SYS_SETRESUID,
|
||||||
|
"getresuid": SYS_GETRESUID,
|
||||||
|
"setresgid": SYS_SETRESGID,
|
||||||
|
"getresgid": SYS_GETRESGID,
|
||||||
|
"setfsuid": SYS_SETFSUID,
|
||||||
|
"setfsgid": SYS_SETFSGID,
|
||||||
|
"times": SYS_TIMES,
|
||||||
|
"setpgid": SYS_SETPGID,
|
||||||
|
"getpgid": SYS_GETPGID,
|
||||||
|
"getsid": SYS_GETSID,
|
||||||
|
"setsid": SYS_SETSID,
|
||||||
|
"getgroups": SYS_GETGROUPS,
|
||||||
|
"setgroups": SYS_SETGROUPS,
|
||||||
|
"uname": SYS_UNAME,
|
||||||
|
"sethostname": SYS_SETHOSTNAME,
|
||||||
|
"setdomainname": SYS_SETDOMAINNAME,
|
||||||
|
"getrlimit": SYS_GETRLIMIT,
|
||||||
|
"setrlimit": SYS_SETRLIMIT,
|
||||||
|
"getrusage": SYS_GETRUSAGE,
|
||||||
|
"umask": SYS_UMASK,
|
||||||
|
"prctl": SYS_PRCTL,
|
||||||
|
"getcpu": SYS_GETCPU,
|
||||||
|
"gettimeofday": SYS_GETTIMEOFDAY,
|
||||||
|
"settimeofday": SYS_SETTIMEOFDAY,
|
||||||
|
"adjtimex": SYS_ADJTIMEX,
|
||||||
|
"getpid": SYS_GETPID,
|
||||||
|
"getppid": SYS_GETPPID,
|
||||||
|
"getuid": SYS_GETUID,
|
||||||
|
"geteuid": SYS_GETEUID,
|
||||||
|
"getgid": SYS_GETGID,
|
||||||
|
"getegid": SYS_GETEGID,
|
||||||
|
"gettid": SYS_GETTID,
|
||||||
|
"sysinfo": SYS_SYSINFO,
|
||||||
|
"mq_open": SYS_MQ_OPEN,
|
||||||
|
"mq_unlink": SYS_MQ_UNLINK,
|
||||||
|
"mq_timedsend": SYS_MQ_TIMEDSEND,
|
||||||
|
"mq_timedreceive": SYS_MQ_TIMEDRECEIVE,
|
||||||
|
"mq_notify": SYS_MQ_NOTIFY,
|
||||||
|
"mq_getsetattr": SYS_MQ_GETSETATTR,
|
||||||
|
"msgget": SYS_MSGGET,
|
||||||
|
"msgctl": SYS_MSGCTL,
|
||||||
|
"msgrcv": SYS_MSGRCV,
|
||||||
|
"msgsnd": SYS_MSGSND,
|
||||||
|
"semget": SYS_SEMGET,
|
||||||
|
"semctl": SYS_SEMCTL,
|
||||||
|
"semtimedop": SYS_SEMTIMEDOP,
|
||||||
|
"semop": SYS_SEMOP,
|
||||||
|
"shmget": SYS_SHMGET,
|
||||||
|
"shmctl": SYS_SHMCTL,
|
||||||
|
"shmat": SYS_SHMAT,
|
||||||
|
"shmdt": SYS_SHMDT,
|
||||||
|
"socket": SYS_SOCKET,
|
||||||
|
"socketpair": SYS_SOCKETPAIR,
|
||||||
|
"bind": SYS_BIND,
|
||||||
|
"listen": SYS_LISTEN,
|
||||||
|
"accept": SYS_ACCEPT,
|
||||||
|
"connect": SYS_CONNECT,
|
||||||
|
"getsockname": SYS_GETSOCKNAME,
|
||||||
|
"getpeername": SYS_GETPEERNAME,
|
||||||
|
"sendto": SYS_SENDTO,
|
||||||
|
"recvfrom": SYS_RECVFROM,
|
||||||
|
"setsockopt": SYS_SETSOCKOPT,
|
||||||
|
"getsockopt": SYS_GETSOCKOPT,
|
||||||
|
"shutdown": SYS_SHUTDOWN,
|
||||||
|
"sendmsg": SYS_SENDMSG,
|
||||||
|
"recvmsg": SYS_RECVMSG,
|
||||||
|
"readahead": SYS_READAHEAD,
|
||||||
|
"brk": SYS_BRK,
|
||||||
|
"munmap": SYS_MUNMAP,
|
||||||
|
"mremap": SYS_MREMAP,
|
||||||
|
"add_key": SYS_ADD_KEY,
|
||||||
|
"request_key": SYS_REQUEST_KEY,
|
||||||
|
"keyctl": SYS_KEYCTL,
|
||||||
|
"clone": SYS_CLONE,
|
||||||
|
"execve": SYS_EXECVE,
|
||||||
|
"mmap": SYS_MMAP,
|
||||||
|
"fadvise64": SYS_FADVISE64,
|
||||||
|
"swapon": SYS_SWAPON,
|
||||||
|
"swapoff": SYS_SWAPOFF,
|
||||||
|
"mprotect": SYS_MPROTECT,
|
||||||
|
"msync": SYS_MSYNC,
|
||||||
|
"mlock": SYS_MLOCK,
|
||||||
|
"munlock": SYS_MUNLOCK,
|
||||||
|
"mlockall": SYS_MLOCKALL,
|
||||||
|
"munlockall": SYS_MUNLOCKALL,
|
||||||
|
"mincore": SYS_MINCORE,
|
||||||
|
"madvise": SYS_MADVISE,
|
||||||
|
"remap_file_pages": SYS_REMAP_FILE_PAGES,
|
||||||
|
"mbind": SYS_MBIND,
|
||||||
|
"get_mempolicy": SYS_GET_MEMPOLICY,
|
||||||
|
"set_mempolicy": SYS_SET_MEMPOLICY,
|
||||||
|
"migrate_pages": SYS_MIGRATE_PAGES,
|
||||||
|
"move_pages": SYS_MOVE_PAGES,
|
||||||
|
"rt_tgsigqueueinfo": SYS_RT_TGSIGQUEUEINFO,
|
||||||
|
"perf_event_open": SYS_PERF_EVENT_OPEN,
|
||||||
|
"accept4": SYS_ACCEPT4,
|
||||||
|
"recvmmsg": SYS_RECVMMSG,
|
||||||
|
"wait4": SYS_WAIT4,
|
||||||
|
"prlimit64": SYS_PRLIMIT64,
|
||||||
|
"fanotify_init": SYS_FANOTIFY_INIT,
|
||||||
|
"fanotify_mark": SYS_FANOTIFY_MARK,
|
||||||
|
"name_to_handle_at": SYS_NAME_TO_HANDLE_AT,
|
||||||
|
"open_by_handle_at": SYS_OPEN_BY_HANDLE_AT,
|
||||||
|
"clock_adjtime": SYS_CLOCK_ADJTIME,
|
||||||
|
"syncfs": SYS_SYNCFS,
|
||||||
|
"setns": SYS_SETNS,
|
||||||
|
"sendmmsg": SYS_SENDMMSG,
|
||||||
|
"process_vm_readv": SYS_PROCESS_VM_READV,
|
||||||
|
"process_vm_writev": SYS_PROCESS_VM_WRITEV,
|
||||||
|
"kcmp": SYS_KCMP,
|
||||||
|
"finit_module": SYS_FINIT_MODULE,
|
||||||
|
"sched_setattr": SYS_SCHED_SETATTR,
|
||||||
|
"sched_getattr": SYS_SCHED_GETATTR,
|
||||||
|
"renameat2": SYS_RENAMEAT2,
|
||||||
|
"seccomp": SYS_SECCOMP,
|
||||||
|
"getrandom": SYS_GETRANDOM,
|
||||||
|
"memfd_create": SYS_MEMFD_CREATE,
|
||||||
|
"bpf": SYS_BPF,
|
||||||
|
"execveat": SYS_EXECVEAT,
|
||||||
|
"userfaultfd": SYS_USERFAULTFD,
|
||||||
|
"membarrier": SYS_MEMBARRIER,
|
||||||
|
"mlock2": SYS_MLOCK2,
|
||||||
|
"copy_file_range": SYS_COPY_FILE_RANGE,
|
||||||
|
"preadv2": SYS_PREADV2,
|
||||||
|
"pwritev2": SYS_PWRITEV2,
|
||||||
|
"pkey_mprotect": SYS_PKEY_MPROTECT,
|
||||||
|
"pkey_alloc": SYS_PKEY_ALLOC,
|
||||||
|
"pkey_free": SYS_PKEY_FREE,
|
||||||
|
"statx": SYS_STATX,
|
||||||
|
"io_pgetevents": SYS_IO_PGETEVENTS,
|
||||||
|
"rseq": SYS_RSEQ,
|
||||||
|
"kexec_file_load": SYS_KEXEC_FILE_LOAD,
|
||||||
|
"pidfd_send_signal": SYS_PIDFD_SEND_SIGNAL,
|
||||||
|
"io_uring_setup": SYS_IO_URING_SETUP,
|
||||||
|
"io_uring_enter": SYS_IO_URING_ENTER,
|
||||||
|
"io_uring_register": SYS_IO_URING_REGISTER,
|
||||||
|
"open_tree": SYS_OPEN_TREE,
|
||||||
|
"move_mount": SYS_MOVE_MOUNT,
|
||||||
|
"fsopen": SYS_FSOPEN,
|
||||||
|
"fsconfig": SYS_FSCONFIG,
|
||||||
|
"fsmount": SYS_FSMOUNT,
|
||||||
|
"fspick": SYS_FSPICK,
|
||||||
|
"pidfd_open": SYS_PIDFD_OPEN,
|
||||||
|
"clone3": SYS_CLONE3,
|
||||||
|
"close_range": SYS_CLOSE_RANGE,
|
||||||
|
"openat2": SYS_OPENAT2,
|
||||||
|
"pidfd_getfd": SYS_PIDFD_GETFD,
|
||||||
|
"faccessat2": SYS_FACCESSAT2,
|
||||||
|
"process_madvise": SYS_PROCESS_MADVISE,
|
||||||
|
"epoll_pwait2": SYS_EPOLL_PWAIT2,
|
||||||
|
"mount_setattr": SYS_MOUNT_SETATTR,
|
||||||
|
"quotactl_fd": SYS_QUOTACTL_FD,
|
||||||
|
"landlock_create_ruleset": SYS_LANDLOCK_CREATE_RULESET,
|
||||||
|
"landlock_add_rule": SYS_LANDLOCK_ADD_RULE,
|
||||||
|
"landlock_restrict_self": SYS_LANDLOCK_RESTRICT_SELF,
|
||||||
|
"memfd_secret": SYS_MEMFD_SECRET,
|
||||||
|
"process_mrelease": SYS_PROCESS_MRELEASE,
|
||||||
|
"futex_waitv": SYS_FUTEX_WAITV,
|
||||||
|
"set_mempolicy_home_node": SYS_SET_MEMPOLICY_HOME_NODE,
|
||||||
|
"cachestat": SYS_CACHESTAT,
|
||||||
|
"fchmodat2": SYS_FCHMODAT2,
|
||||||
|
"map_shadow_stack": SYS_MAP_SHADOW_STACK,
|
||||||
|
"futex_wake": SYS_FUTEX_WAKE,
|
||||||
|
"futex_wait": SYS_FUTEX_WAIT,
|
||||||
|
"futex_requeue": SYS_FUTEX_REQUEUE,
|
||||||
|
"statmount": SYS_STATMOUNT,
|
||||||
|
"listmount": SYS_LISTMOUNT,
|
||||||
|
"lsm_get_self_attr": SYS_LSM_GET_SELF_ATTR,
|
||||||
|
"lsm_set_self_attr": SYS_LSM_SET_SELF_ATTR,
|
||||||
|
"lsm_list_modules": SYS_LSM_LIST_MODULES,
|
||||||
|
"mseal": SYS_MSEAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SYS_USERFAULTFD = 282
|
||||||
|
SYS_MEMBARRIER = 283
|
||||||
|
SYS_MLOCK2 = 284
|
||||||
|
SYS_COPY_FILE_RANGE = 285
|
||||||
|
SYS_PREADV2 = 286
|
||||||
|
SYS_PWRITEV2 = 287
|
||||||
|
SYS_PKEY_MPROTECT = 288
|
||||||
|
SYS_PKEY_ALLOC = 289
|
||||||
|
SYS_PKEY_FREE = 290
|
||||||
|
SYS_STATX = 291
|
||||||
|
SYS_IO_PGETEVENTS = 292
|
||||||
|
SYS_RSEQ = 293
|
||||||
|
SYS_KEXEC_FILE_LOAD = 294
|
||||||
|
SYS_PIDFD_SEND_SIGNAL = 424
|
||||||
|
SYS_IO_URING_SETUP = 425
|
||||||
|
SYS_IO_URING_ENTER = 426
|
||||||
|
SYS_IO_URING_REGISTER = 427
|
||||||
|
SYS_OPEN_TREE = 428
|
||||||
|
SYS_MOVE_MOUNT = 429
|
||||||
|
SYS_FSOPEN = 430
|
||||||
|
SYS_FSCONFIG = 431
|
||||||
|
SYS_FSMOUNT = 432
|
||||||
|
SYS_FSPICK = 433
|
||||||
|
SYS_PIDFD_OPEN = 434
|
||||||
|
SYS_CLONE3 = 435
|
||||||
|
SYS_CLOSE_RANGE = 436
|
||||||
|
SYS_OPENAT2 = 437
|
||||||
|
SYS_PIDFD_GETFD = 438
|
||||||
|
SYS_FACCESSAT2 = 439
|
||||||
|
SYS_PROCESS_MADVISE = 440
|
||||||
|
SYS_EPOLL_PWAIT2 = 441
|
||||||
|
SYS_MOUNT_SETATTR = 442
|
||||||
|
SYS_QUOTACTL_FD = 443
|
||||||
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_MEMFD_SECRET = 447
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
|
SYS_FUTEX_WAITV = 449
|
||||||
|
SYS_SET_MEMPOLICY_HOME_NODE = 450
|
||||||
|
SYS_CACHESTAT = 451
|
||||||
|
SYS_FCHMODAT2 = 452
|
||||||
|
SYS_MAP_SHADOW_STACK = 453
|
||||||
|
SYS_FUTEX_WAKE = 454
|
||||||
|
SYS_FUTEX_WAIT = 455
|
||||||
|
SYS_FUTEX_REQUEUE = 456
|
||||||
|
SYS_STATMOUNT = 457
|
||||||
|
SYS_LISTMOUNT = 458
|
||||||
|
SYS_LSM_GET_SELF_ATTR = 459
|
||||||
|
SYS_LSM_SET_SELF_ATTR = 460
|
||||||
|
SYS_LSM_LIST_MODULES = 461
|
||||||
|
SYS_MSEAL = 462
|
||||||
|
)
|
@ -2,16 +2,6 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
O_PATH = 0x200000
|
|
||||||
|
|
||||||
PR_SET_NO_NEW_PRIVS = 0x26
|
|
||||||
|
|
||||||
CAP_SYS_ADMIN = 0x15
|
|
||||||
CAP_SETPCAP = 0x8
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -28,42 +18,6 @@ func SetDumpable(dumpable uintptr) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
_LINUX_CAPABILITY_VERSION_3 = 0x20080522
|
|
||||||
|
|
||||||
PR_CAP_AMBIENT = 0x2f
|
|
||||||
PR_CAP_AMBIENT_RAISE = 0x2
|
|
||||||
PR_CAP_AMBIENT_CLEAR_ALL = 0x4
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
capHeader struct {
|
|
||||||
version uint32
|
|
||||||
pid int32
|
|
||||||
}
|
|
||||||
|
|
||||||
capData struct {
|
|
||||||
effective uint32
|
|
||||||
permitted uint32
|
|
||||||
inheritable uint32
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// See CAP_TO_INDEX in linux/capability.h:
|
|
||||||
func capToIndex(cap uintptr) uintptr { return cap >> 5 }
|
|
||||||
|
|
||||||
// See CAP_TO_MASK in linux/capability.h:
|
|
||||||
func capToMask(cap uintptr) uint32 { return 1 << uint(cap&31) }
|
|
||||||
|
|
||||||
func capset(hdrp *capHeader, datap *[2]capData) error {
|
|
||||||
if _, _, errno := syscall.Syscall(syscall.SYS_CAPSET,
|
|
||||||
uintptr(unsafe.Pointer(hdrp)),
|
|
||||||
uintptr(unsafe.Pointer(&datap[0])), 0); errno != 0 {
|
|
||||||
return errno
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IgnoringEINTR makes a function call and repeats it if it returns an
|
// IgnoringEINTR makes a function call and repeats it if it returns an
|
||||||
// EINTR error. This appears to be required even though we install all
|
// EINTR error. This appears to be required even though we install all
|
||||||
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
|
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
|
||||||
|
7
container/syscall_amd64.go
Normal file
7
container/syscall_amd64.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
const (
|
||||||
|
O_PATH = 0x200000
|
||||||
|
|
||||||
|
PR_SET_NO_NEW_PRIVS = 0x26
|
||||||
|
)
|
28
flake.nix
28
flake.nix
@ -185,17 +185,23 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
generateSyscallTable = pkgs.mkShell {
|
generateSyscallTable =
|
||||||
# this should be made cross-platform via nix
|
let
|
||||||
shellHook = "exec ${pkgs.writeShellScript "generate-syscall-table" ''
|
GOARCH = {
|
||||||
set -e
|
x86_64-linux = "amd64";
|
||||||
${pkgs.perl}/bin/perl \
|
aarch64-linux = "arm64";
|
||||||
sandbox/seccomp/mksysnum_linux.pl \
|
};
|
||||||
${pkgs.linuxHeaders}/include/asm/unistd_64.h | \
|
in
|
||||||
${pkgs.go}/bin/gofmt > \
|
pkgs.mkShell {
|
||||||
sandbox/seccomp/syscall_linux_amd64.go
|
shellHook = "exec ${pkgs.writeShellScript "generate-syscall-table" ''
|
||||||
''}";
|
set -e
|
||||||
};
|
${pkgs.perl}/bin/perl \
|
||||||
|
container/seccomp/mksysnum_linux.pl \
|
||||||
|
${pkgs.linuxHeaders}/include/asm/unistd_64.h | \
|
||||||
|
${pkgs.go}/bin/gofmt > \
|
||||||
|
container/seccomp/syscall_linux_${GOARCH.${system}}.go
|
||||||
|
''}";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,15 +2,19 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
|
"hakurei.app/internal/sys"
|
||||||
)
|
)
|
||||||
|
|
||||||
type App interface {
|
type App interface {
|
||||||
// ID returns a copy of [ID] held by App.
|
// ID returns a copy of [ID] held by App.
|
||||||
ID() ID
|
ID() state.ID
|
||||||
|
|
||||||
// Seal determines the outcome of config as a [SealedApp].
|
// Seal determines the outcome of config as a [SealedApp].
|
||||||
// The value of config might be overwritten and must not be used again.
|
// The value of config might be overwritten and must not be used again.
|
||||||
@ -47,3 +51,11 @@ func (rs *RunState) SetStart() {
|
|||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
rs.Time = &now
|
rs.Time = &now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MustNew(ctx context.Context, os sys.State) App {
|
||||||
|
a, err := New(ctx, os)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("cannot create app: %v", err)
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
package setuid
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
. "hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
"hakurei.app/internal/sys"
|
"hakurei.app/internal/sys"
|
||||||
)
|
)
|
||||||
@ -16,15 +16,15 @@ func New(ctx context.Context, os sys.State) (App, error) {
|
|||||||
a.sys = os
|
a.sys = os
|
||||||
a.ctx = ctx
|
a.ctx = ctx
|
||||||
|
|
||||||
id := new(ID)
|
id := new(state.ID)
|
||||||
err := NewAppID(id)
|
err := state.NewAppID(id)
|
||||||
a.id = newID(id)
|
a.id = newID(id)
|
||||||
|
|
||||||
return a, err
|
return a, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type app struct {
|
type app struct {
|
||||||
id *stringPair[ID]
|
id *stringPair[state.ID]
|
||||||
sys sys.State
|
sys sys.State
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ type app struct {
|
|||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *app) ID() ID { a.mu.RLock(); defer a.mu.RUnlock(); return a.id.unwrap() }
|
func (a *app) ID() state.ID { a.mu.RLock(); defer a.mu.RUnlock(); return a.id.unwrap() }
|
||||||
|
|
||||||
func (a *app) String() string {
|
func (a *app) String() string {
|
||||||
if a == nil {
|
if a == nil {
|
@ -1,4 +1,4 @@
|
|||||||
package setuid_test
|
package app_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -7,10 +7,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app/internal/setuid"
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/sys"
|
"hakurei.app/internal/sys"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
)
|
)
|
||||||
@ -19,7 +19,7 @@ type sealTestCase struct {
|
|||||||
name string
|
name string
|
||||||
os sys.State
|
os sys.State
|
||||||
config *hst.Config
|
config *hst.Config
|
||||||
id app.ID
|
id state.ID
|
||||||
wantSys *system.I
|
wantSys *system.I
|
||||||
wantContainer *container.Params
|
wantContainer *container.Params
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ func TestApp(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
a := setuid.NewWithID(tc.id, tc.os)
|
a := app.NewWithID(tc.id, tc.os)
|
||||||
var (
|
var (
|
||||||
gotSys *system.I
|
gotSys *system.I
|
||||||
gotContainer *container.Params
|
gotContainer *container.Params
|
||||||
@ -39,7 +39,7 @@ func TestApp(t *testing.T) {
|
|||||||
t.Errorf("Seal: error = %v", err)
|
t.Errorf("Seal: error = %v", err)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
gotSys, gotContainer = setuid.AppIParams(a, sa)
|
gotSys, gotContainer = app.AppIParams(a, sa)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
return
|
return
|
@ -1,10 +1,10 @@
|
|||||||
package setuid_test
|
package app_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
@ -52,7 +52,7 @@ var testCasesNixos = []sealTestCase{
|
|||||||
Data: "/var/lib/persist/module/hakurei/0/1",
|
Data: "/var/lib/persist/module/hakurei/0/1",
|
||||||
Identity: 1, Groups: []string{},
|
Identity: 1, Groups: []string{},
|
||||||
},
|
},
|
||||||
app.ID{
|
state.ID{
|
||||||
0x8e, 0x2c, 0x76, 0xb0,
|
0x8e, 0x2c, 0x76, 0xb0,
|
||||||
0x66, 0xda, 0xbe, 0x57,
|
0x66, 0xda, 0xbe, 0x57,
|
||||||
0x4c, 0xf0, 0x73, 0xbd,
|
0x4c, 0xf0, 0x73, 0xbd,
|
@ -1,12 +1,12 @@
|
|||||||
package setuid_test
|
package app_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
"hakurei.app/system/acl"
|
"hakurei.app/system/acl"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
@ -16,7 +16,7 @@ var testCasesPd = []sealTestCase{
|
|||||||
{
|
{
|
||||||
"nixos permissive defaults no enablements", new(stubNixOS),
|
"nixos permissive defaults no enablements", new(stubNixOS),
|
||||||
&hst.Config{Username: "chronos", Data: "/home/chronos"},
|
&hst.Config{Username: "chronos", Data: "/home/chronos"},
|
||||||
app.ID{
|
state.ID{
|
||||||
0x4a, 0x45, 0x0b, 0x65,
|
0x4a, 0x45, 0x0b, 0x65,
|
||||||
0x96, 0xd7, 0xbc, 0x15,
|
0x96, 0xd7, 0xbc, 0x15,
|
||||||
0xbd, 0x01, 0x78, 0x0e,
|
0xbd, 0x01, 0x78, 0x0e,
|
||||||
@ -115,7 +115,7 @@ var testCasesPd = []sealTestCase{
|
|||||||
},
|
},
|
||||||
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
Enablements: system.EWayland | system.EDBus | system.EPulse,
|
||||||
},
|
},
|
||||||
app.ID{
|
state.ID{
|
||||||
0xeb, 0xf0, 0x83, 0xd1,
|
0xeb, 0xf0, 0x83, 0xd1,
|
||||||
0xb1, 0x75, 0x91, 0x17,
|
0xb1, 0x75, 0x91, 0x17,
|
||||||
0x82, 0xd4, 0x13, 0x36,
|
0x82, 0xd4, 0x13, 0x36,
|
@ -1,4 +1,4 @@
|
|||||||
package setuid_test
|
package app_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
@ -1,4 +1,4 @@
|
|||||||
package common
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@ -19,9 +19,9 @@ import (
|
|||||||
// allocating slightly more as a margin for future expansion
|
// allocating slightly more as a margin for future expansion
|
||||||
const preallocateOpsCount = 1 << 5
|
const preallocateOpsCount = 1 << 5
|
||||||
|
|
||||||
// NewContainer initialises [sandbox.Params] via [hst.ContainerConfig].
|
// newContainer initialises [container.Params] via [hst.ContainerConfig].
|
||||||
// Note that remaining container setup must be queued by the caller.
|
// Note that remaining container setup must be queued by the caller.
|
||||||
func NewContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*container.Params, map[string]string, error) {
|
func newContainer(s *hst.ContainerConfig, os sys.State, uid, gid *int) (*container.Params, map[string]string, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil, nil, syscall.EBADE
|
return nil, nil, syscall.EBADE
|
||||||
}
|
}
|
@ -1,10 +1,9 @@
|
|||||||
package setuid
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
. "hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
)
|
)
|
||||||
|
|
@ -1,13 +1,13 @@
|
|||||||
package setuid
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/sys"
|
"hakurei.app/internal/sys"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewWithID(id ID, os sys.State) App {
|
func NewWithID(id state.ID, os sys.State) App {
|
||||||
a := new(app)
|
a := new(app)
|
||||||
a.id = newID(&id)
|
a.id = newID(&id)
|
||||||
a.sys = os
|
a.sys = os
|
@ -1,4 +1,4 @@
|
|||||||
package common
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
@ -1,4 +1,4 @@
|
|||||||
package common
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
@ -1,4 +1,4 @@
|
|||||||
package setuid
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@ -12,10 +12,9 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/state"
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
)
|
)
|
@ -1,4 +1,4 @@
|
|||||||
package setuid
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -16,11 +16,10 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
. "hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app/instance/common"
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
"hakurei.app/internal/sys"
|
"hakurei.app/internal/sys"
|
||||||
"hakurei.app/system"
|
"hakurei.app/system"
|
||||||
@ -66,7 +65,7 @@ var posixUsername = regexp.MustCompilePOSIX("^[a-z_]([A-Za-z0-9_-]{0,31}|[A-Za-z
|
|||||||
// outcome stores copies of various parts of [hst.Config]
|
// outcome stores copies of various parts of [hst.Config]
|
||||||
type outcome struct {
|
type outcome struct {
|
||||||
// copied from initialising [app]
|
// copied from initialising [app]
|
||||||
id *stringPair[ID]
|
id *stringPair[state.ID]
|
||||||
// copied from [sys.State] response
|
// copied from [sys.State] response
|
||||||
runDirPath string
|
runDirPath string
|
||||||
|
|
||||||
@ -281,7 +280,7 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
|
|||||||
{
|
{
|
||||||
var uid, gid int
|
var uid, gid int
|
||||||
var err error
|
var err error
|
||||||
seal.container, seal.env, err = common.NewContainer(config.Container, sys, &uid, &gid)
|
seal.container, seal.env, err = newContainer(config.Container, sys, &uid, &gid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hlog.WrapErrSuffix(err,
|
return hlog.WrapErrSuffix(err,
|
||||||
"cannot initialise container configuration:")
|
"cannot initialise container configuration:")
|
@ -1,4 +1,4 @@
|
|||||||
package setuid
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
@ -1,4 +1,4 @@
|
|||||||
package app
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
@ -1,22 +1,22 @@
|
|||||||
package app_test
|
package state_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "hakurei.app/cmd/hakurei/internal/app"
|
"hakurei.app/internal/app/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseAppID(t *testing.T) {
|
func TestParseAppID(t *testing.T) {
|
||||||
t.Run("bad length", func(t *testing.T) {
|
t.Run("bad length", func(t *testing.T) {
|
||||||
if err := ParseAppID(new(ID), "meow"); !errors.Is(err, ErrInvalidLength) {
|
if err := state.ParseAppID(new(state.ID), "meow"); !errors.Is(err, state.ErrInvalidLength) {
|
||||||
t.Errorf("ParseAppID: error = %v, wantErr = %v", err, ErrInvalidLength)
|
t.Errorf("ParseAppID: error = %v, wantErr = %v", err, state.ErrInvalidLength)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("bad byte", func(t *testing.T) {
|
t.Run("bad byte", func(t *testing.T) {
|
||||||
wantErr := "invalid char '\\n' at byte 15"
|
wantErr := "invalid char '\\n' at byte 15"
|
||||||
if err := ParseAppID(new(ID), "02bc7f8936b2af6\n\ne2535cd71ef0bb7"); err == nil || err.Error() != wantErr {
|
if err := state.ParseAppID(new(state.ID), "02bc7f8936b2af6\n\ne2535cd71ef0bb7"); err == nil || err.Error() != wantErr {
|
||||||
t.Errorf("ParseAppID: error = %v, wantErr = %v", err, wantErr)
|
t.Errorf("ParseAppID: error = %v, wantErr = %v", err, wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -30,30 +30,30 @@ func TestParseAppID(t *testing.T) {
|
|||||||
|
|
||||||
func FuzzParseAppID(f *testing.F) {
|
func FuzzParseAppID(f *testing.F) {
|
||||||
for i := 0; i < 16; i++ {
|
for i := 0; i < 16; i++ {
|
||||||
id := new(ID)
|
id := new(state.ID)
|
||||||
if err := NewAppID(id); err != nil {
|
if err := state.NewAppID(id); err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
f.Add(id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15])
|
f.Add(id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15])
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Fuzz(func(t *testing.T, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 byte) {
|
f.Fuzz(func(t *testing.T, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 byte) {
|
||||||
testParseAppID(t, &ID{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15})
|
testParseAppID(t, &state.ID{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func testParseAppIDWithRandom(t *testing.T) {
|
func testParseAppIDWithRandom(t *testing.T) {
|
||||||
id := new(ID)
|
id := new(state.ID)
|
||||||
if err := NewAppID(id); err != nil {
|
if err := state.NewAppID(id); err != nil {
|
||||||
t.Fatalf("cannot generate app ID: %v", err)
|
t.Fatalf("cannot generate app ID: %v", err)
|
||||||
}
|
}
|
||||||
testParseAppID(t, id)
|
testParseAppID(t, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testParseAppID(t *testing.T, id *ID) {
|
func testParseAppID(t *testing.T, id *state.ID) {
|
||||||
s := id.String()
|
s := id.String()
|
||||||
got := new(ID)
|
got := new(state.ID)
|
||||||
if err := ParseAppID(got, s); err != nil {
|
if err := state.ParseAppID(got, s); err != nil {
|
||||||
t.Fatalf("cannot parse app ID: %v", err)
|
t.Fatalf("cannot parse app ID: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -13,7 +13,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal/hlog"
|
"hakurei.app/internal/hlog"
|
||||||
)
|
)
|
||||||
@ -130,7 +129,7 @@ type multiBackend struct {
|
|||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *multiBackend) filename(id *app.ID) string {
|
func (b *multiBackend) filename(id *ID) string {
|
||||||
return path.Join(b.path, id.String())
|
return path.Join(b.path, id.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,8 +189,8 @@ func (b *multiBackend) load(decode bool) (Entries, error) {
|
|||||||
return nil, fmt.Errorf("unexpected directory %q in store", e.Name())
|
return nil, fmt.Errorf("unexpected directory %q in store", e.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
id := new(app.ID)
|
id := new(ID)
|
||||||
if err := app.ParseAppID(id, e.Name()); err != nil {
|
if err := ParseAppID(id, e.Name()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +335,7 @@ func (b *multiBackend) encodeState(w io.WriteSeeker, state *State, configWriter
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *multiBackend) Destroy(id app.ID) error {
|
func (b *multiBackend) Destroy(id ID) error {
|
||||||
b.lock.Lock()
|
b.lock.Lock()
|
||||||
defer b.lock.Unlock()
|
defer b.lock.Unlock()
|
||||||
|
|
@ -3,7 +3,7 @@ package state_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/state"
|
"hakurei.app/internal/app/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMulti(t *testing.T) { testStore(t, state.NewMulti(t.TempDir())) }
|
func TestMulti(t *testing.T) { testStore(t, state.NewMulti(t.TempDir())) }
|
@ -1,3 +1,4 @@
|
|||||||
|
// Package state provides cross-process state tracking for hakurei container instances.
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -5,13 +6,12 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNoConfig = errors.New("state does not contain config")
|
var ErrNoConfig = errors.New("state does not contain config")
|
||||||
|
|
||||||
type Entries map[app.ID]*State
|
type Entries map[ID]*State
|
||||||
|
|
||||||
type Store interface {
|
type Store interface {
|
||||||
// Do calls f exactly once and ensures store exclusivity until f returns.
|
// Do calls f exactly once and ensures store exclusivity until f returns.
|
||||||
@ -30,7 +30,7 @@ type Store interface {
|
|||||||
// Cursor provides access to the store
|
// Cursor provides access to the store
|
||||||
type Cursor interface {
|
type Cursor interface {
|
||||||
Save(state *State, configWriter io.WriterTo) error
|
Save(state *State, configWriter io.WriterTo) error
|
||||||
Destroy(id app.ID) error
|
Destroy(id ID) error
|
||||||
Load() (Entries, error)
|
Load() (Entries, error)
|
||||||
Len() (int, error)
|
Len() (int, error)
|
||||||
}
|
}
|
||||||
@ -38,7 +38,7 @@ type Cursor interface {
|
|||||||
// State is an instance state
|
// State is an instance state
|
||||||
type State struct {
|
type State struct {
|
||||||
// hakurei instance id
|
// hakurei instance id
|
||||||
ID app.ID `json:"instance"`
|
ID ID `json:"instance"`
|
||||||
// child process PID value
|
// child process PID value
|
||||||
PID int `json:"pid"`
|
PID int `json:"pid"`
|
||||||
// sealed app configuration
|
// sealed app configuration
|
@ -10,9 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/cmd/hakurei/internal/app"
|
|
||||||
"hakurei.app/cmd/hakurei/internal/state"
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/app/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testStore(t *testing.T, s state.Store) {
|
func testStore(t *testing.T, s state.Store) {
|
||||||
@ -134,7 +133,7 @@ func testStore(t *testing.T, s state.Store) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func makeState(t *testing.T, s *state.State, ct io.Writer) {
|
func makeState(t *testing.T, s *state.State, ct io.Writer) {
|
||||||
if err := app.NewAppID(&s.ID); err != nil {
|
if err := state.NewAppID(&s.ID); err != nil {
|
||||||
t.Fatalf("cannot create dummy state: %v", err)
|
t.Fatalf("cannot create dummy state: %v", err)
|
||||||
}
|
}
|
||||||
if err := gob.NewEncoder(ct).Encode(hst.Template()); err != nil {
|
if err := gob.NewEncoder(ct).Encode(hst.Template()); err != nil {
|
@ -1,13 +1,13 @@
|
|||||||
package setuid
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
. "hakurei.app/cmd/hakurei/internal/app"
|
"hakurei.app/internal/app/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }
|
func newInt(v int) *stringPair[int] { return &stringPair[int]{v, strconv.Itoa(v)} }
|
||||||
func newID(id *ID) *stringPair[ID] { return &stringPair[ID]{*id, id.String()} }
|
func newID(id *state.ID) *stringPair[state.ID] { return &stringPair[state.ID]{*id, id.String()} }
|
||||||
|
|
||||||
// stringPair stores a value and its string representation.
|
// stringPair stores a value and its string representation.
|
||||||
type stringPair[T comparable] struct {
|
type stringPair[T comparable] struct {
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
buildGoModule rec {
|
buildGoModule rec {
|
||||||
pname = "hakurei";
|
pname = "hakurei";
|
||||||
version = "0.1.0";
|
version = "0.1.1";
|
||||||
|
|
||||||
srcFiltered = builtins.path {
|
srcFiltered = builtins.path {
|
||||||
name = "${pname}-src";
|
name = "${pname}-src";
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package sandbox provides utilities for checking sandbox outcome.
|
Package sandbox provides utilities for checking sandbox outcome.
|
||||||
|
|
||||||
@ -15,7 +17,6 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -40,13 +41,10 @@ type T struct {
|
|||||||
MountsPath string
|
MountsPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *T) MustCheckFile(wantFilePath, markerPath string) {
|
func (t *T) MustCheckFile(wantFilePath string) {
|
||||||
var want *TestCase
|
var want *TestCase
|
||||||
mustDecode(wantFilePath, &want)
|
mustDecode(wantFilePath, &want)
|
||||||
t.MustCheck(want)
|
t.MustCheck(want)
|
||||||
if _, err := os.Create(markerPath); err != nil {
|
|
||||||
fatalf("cannot create success marker: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *T) MustCheck(want *TestCase) {
|
func (t *T) MustCheck(want *TestCase) {
|
||||||
@ -165,31 +163,10 @@ func CheckFilter(pid int, want string) error {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
h := sha512.New()
|
h := sha512.New()
|
||||||
{
|
|
||||||
getFilter:
|
|
||||||
buf, err := getFilter[[8]byte](pid, 0)
|
|
||||||
/* this is not how ESRCH should be handled: the manpage advises the
|
|
||||||
use of waitpid, however that is not applicable for attaching to an
|
|
||||||
arbitrary process, and spawning target process here is not easily
|
|
||||||
possible under the current testing framework;
|
|
||||||
|
|
||||||
despite checking for /proc/pid/status indicating state t (tracing stop),
|
|
||||||
it does not appear to be directly related to the internal state used to
|
|
||||||
determine whether a process is ready to accept ptrace operations, it also
|
|
||||||
introduces a TOCTOU that is irrelevant in the testing vm; this behaviour
|
|
||||||
is kept anyway as it reduces the average iterations required here;
|
|
||||||
|
|
||||||
since this code is only ever compiled into the test program, whatever
|
|
||||||
implications this ugliness might have should not hurt anyone */
|
|
||||||
if errors.Is(err, syscall.ESRCH) {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
goto getFilter
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if buf, err := getFilter[[8]byte](pid, 0); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
for _, b := range buf {
|
for _, b := range buf {
|
||||||
h.Write(b[:])
|
h.Write(b[:])
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
lib: testProgram:
|
system: lib: testProgram:
|
||||||
let
|
let
|
||||||
fs = mode: dir: data: {
|
fs = mode: dir: data: {
|
||||||
mode = lib.fromHexString mode;
|
mode = lib.fromHexString mode;
|
||||||
@ -31,6 +31,7 @@ let
|
|||||||
fs
|
fs
|
||||||
ent
|
ent
|
||||||
ignore
|
ignore
|
||||||
|
system
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
@ -43,13 +44,17 @@ let
|
|||||||
device
|
device
|
||||||
mapRealUid
|
mapRealUid
|
||||||
useCommonPaths
|
useCommonPaths
|
||||||
|
userns
|
||||||
;
|
;
|
||||||
share = testProgram;
|
share = testProgram;
|
||||||
packages = [ ];
|
packages = [ ];
|
||||||
path = "${testProgram}/bin/hakurei-test";
|
path = "${testProgram}/bin/hakurei-test";
|
||||||
args = [
|
args = [
|
||||||
"test"
|
"test"
|
||||||
|
"-t"
|
||||||
(toString (builtins.toFile "hakurei-${tc.name}-want.json" (builtins.toJSON tc.want)))
|
(toString (builtins.toFile "hakurei-${tc.name}-want.json" (builtins.toJSON tc.want)))
|
||||||
|
"-s"
|
||||||
|
tc.expectedFilter.${system}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -60,4 +65,5 @@ in
|
|||||||
${testCaseName "tty"} = callTestCase ./tty.nix 2;
|
${testCaseName "tty"} = callTestCase ./tty.nix 2;
|
||||||
${testCaseName "mapuid"} = callTestCase ./mapuid.nix 3;
|
${testCaseName "mapuid"} = callTestCase ./mapuid.nix 3;
|
||||||
${testCaseName "device"} = callTestCase ./device.nix 4;
|
${testCaseName "device"} = callTestCase ./device.nix 4;
|
||||||
|
${testCaseName "pdlike"} = callTestCase ./pdlike.nix 5;
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,35 @@
|
|||||||
fs,
|
fs,
|
||||||
ent,
|
ent,
|
||||||
ignore,
|
ignore,
|
||||||
|
system,
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
extraPaths = {
|
||||||
|
x86_64-linux = {
|
||||||
|
fd = "fd0";
|
||||||
|
sr = {
|
||||||
|
sr0 = fs "80001ff" null null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
fd = "mtdblock0";
|
||||||
|
sr = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "device";
|
name = "device";
|
||||||
tty = false;
|
tty = false;
|
||||||
device = true;
|
device = true;
|
||||||
mapRealUid = false;
|
mapRealUid = false;
|
||||||
useCommonPaths = true;
|
useCommonPaths = true;
|
||||||
|
userns = false;
|
||||||
|
|
||||||
|
# 0, PresetStrict
|
||||||
|
expectedFilter = {
|
||||||
|
x86_64-linux = "e880298df2bd6751d0040fc21bc0ed4c00f95dc0d7ba506c244d8b8cf6866dba8ef4a33296f287b66cccc1d78e97026597f84cc7dec1573e148960fbd35cd735";
|
||||||
|
aarch64-linux = "79318538a3dc851314b6bd96f10d5861acb2aa7e13cb8de0619d0f6a76709d67f01ef3fd67e195862b02f9711e5b769bc4d1eb4fc0dfc41a723c89c968a93297";
|
||||||
|
};
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -113,19 +135,21 @@
|
|||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
sys = fs "800001c0" {
|
sys = fs "800001c0" {
|
||||||
block = fs "800001ed" {
|
block = fs "800001ed" (
|
||||||
fd0 = fs "80001ff" null null;
|
{
|
||||||
loop0 = fs "80001ff" null null;
|
${extraPaths.${system}.fd} = fs "80001ff" null null;
|
||||||
loop1 = fs "80001ff" null null;
|
loop0 = fs "80001ff" null null;
|
||||||
loop2 = fs "80001ff" null null;
|
loop1 = fs "80001ff" null null;
|
||||||
loop3 = fs "80001ff" null null;
|
loop2 = fs "80001ff" null null;
|
||||||
loop4 = fs "80001ff" null null;
|
loop3 = fs "80001ff" null null;
|
||||||
loop5 = fs "80001ff" null null;
|
loop4 = fs "80001ff" null null;
|
||||||
loop6 = fs "80001ff" null null;
|
loop5 = fs "80001ff" null null;
|
||||||
loop7 = fs "80001ff" null null;
|
loop6 = fs "80001ff" null null;
|
||||||
sr0 = fs "80001ff" null null;
|
loop7 = fs "80001ff" null null;
|
||||||
vda = fs "80001ff" null null;
|
vda = fs "80001ff" null null;
|
||||||
} null;
|
}
|
||||||
|
// extraPaths.${system}.sr
|
||||||
|
) null;
|
||||||
bus = fs "800001ed" null null;
|
bus = fs "800001ed" null null;
|
||||||
class = fs "800001ed" null null;
|
class = fs "800001ed" null null;
|
||||||
dev = fs "800001ed" {
|
dev = fs "800001ed" {
|
||||||
|
@ -2,13 +2,44 @@
|
|||||||
fs,
|
fs,
|
||||||
ent,
|
ent,
|
||||||
ignore,
|
ignore,
|
||||||
|
system,
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
extraPaths = {
|
||||||
|
x86_64-linux = {
|
||||||
|
fd = "fd0";
|
||||||
|
"/dev/dri" = {
|
||||||
|
by-path = fs "800001ed" {
|
||||||
|
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
||||||
|
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
card0 = fs "42001b0" null null;
|
||||||
|
renderD128 = fs "42001b6" null null;
|
||||||
|
};
|
||||||
|
sr = {
|
||||||
|
sr0 = fs "80001ff" null null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
fd = "mtdblock0";
|
||||||
|
"/dev/dri" = null;
|
||||||
|
sr = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "mapuid";
|
name = "mapuid";
|
||||||
tty = false;
|
tty = false;
|
||||||
device = false;
|
device = false;
|
||||||
mapRealUid = true;
|
mapRealUid = true;
|
||||||
useCommonPaths = true;
|
useCommonPaths = true;
|
||||||
|
userns = false;
|
||||||
|
|
||||||
|
# 0, PresetStrict
|
||||||
|
expectedFilter = {
|
||||||
|
x86_64-linux = "e880298df2bd6751d0040fc21bc0ed4c00f95dc0d7ba506c244d8b8cf6866dba8ef4a33296f287b66cccc1d78e97026597f84cc7dec1573e148960fbd35cd735";
|
||||||
|
aarch64-linux = "79318538a3dc851314b6bd96f10d5861acb2aa7e13cb8de0619d0f6a76709d67f01ef3fd67e195862b02f9711e5b769bc4d1eb4fc0dfc41a723c89c968a93297";
|
||||||
|
};
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -29,14 +60,7 @@
|
|||||||
bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
|
bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
|
||||||
dev = fs "800001ed" {
|
dev = fs "800001ed" {
|
||||||
core = fs "80001ff" null null;
|
core = fs "80001ff" null null;
|
||||||
dri = fs "800001ed" {
|
dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
|
||||||
by-path = fs "800001ed" {
|
|
||||||
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
|
||||||
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
|
||||||
} null;
|
|
||||||
card0 = fs "42001b0" null null;
|
|
||||||
renderD128 = fs "42001b6" null null;
|
|
||||||
} null;
|
|
||||||
fd = fs "80001ff" null null;
|
fd = fs "80001ff" null null;
|
||||||
full = fs "42001b6" null null;
|
full = fs "42001b6" null null;
|
||||||
mqueue = fs "801001ff" { } null;
|
mqueue = fs "801001ff" { } null;
|
||||||
@ -137,19 +161,21 @@
|
|||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
sys = fs "800001c0" {
|
sys = fs "800001c0" {
|
||||||
block = fs "800001ed" {
|
block = fs "800001ed" (
|
||||||
fd0 = fs "80001ff" null null;
|
{
|
||||||
loop0 = fs "80001ff" null null;
|
${extraPaths.${system}.fd} = fs "80001ff" null null;
|
||||||
loop1 = fs "80001ff" null null;
|
loop0 = fs "80001ff" null null;
|
||||||
loop2 = fs "80001ff" null null;
|
loop1 = fs "80001ff" null null;
|
||||||
loop3 = fs "80001ff" null null;
|
loop2 = fs "80001ff" null null;
|
||||||
loop4 = fs "80001ff" null null;
|
loop3 = fs "80001ff" null null;
|
||||||
loop5 = fs "80001ff" null null;
|
loop4 = fs "80001ff" null null;
|
||||||
loop6 = fs "80001ff" null null;
|
loop5 = fs "80001ff" null null;
|
||||||
loop7 = fs "80001ff" null null;
|
loop6 = fs "80001ff" null null;
|
||||||
sr0 = fs "80001ff" null null;
|
loop7 = fs "80001ff" null null;
|
||||||
vda = fs "80001ff" null null;
|
vda = fs "80001ff" null null;
|
||||||
} null;
|
}
|
||||||
|
// extraPaths.${system}.sr
|
||||||
|
) null;
|
||||||
bus = fs "800001ed" null null;
|
bus = fs "800001ed" null null;
|
||||||
class = fs "800001ed" null null;
|
class = fs "800001ed" null null;
|
||||||
dev = fs "800001ed" {
|
dev = fs "800001ed" {
|
||||||
|
274
test/sandbox/case/pdlike.nix
Normal file
274
test/sandbox/case/pdlike.nix
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
{
|
||||||
|
fs,
|
||||||
|
ent,
|
||||||
|
ignore,
|
||||||
|
system,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
extraPaths = {
|
||||||
|
x86_64-linux = {
|
||||||
|
fd = "fd0";
|
||||||
|
"/dev/dri" = {
|
||||||
|
by-path = fs "800001ed" {
|
||||||
|
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
||||||
|
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
card0 = fs "42001b0" null null;
|
||||||
|
renderD128 = fs "42001b6" null null;
|
||||||
|
};
|
||||||
|
sr = {
|
||||||
|
sr0 = fs "80001ff" null null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
fd = "mtdblock0";
|
||||||
|
"/dev/dri" = null;
|
||||||
|
sr = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
name = "pdlike";
|
||||||
|
tty = true;
|
||||||
|
device = false;
|
||||||
|
mapRealUid = false;
|
||||||
|
useCommonPaths = false;
|
||||||
|
userns = true;
|
||||||
|
|
||||||
|
# 0, PresetExt | PresetDenyDevel
|
||||||
|
expectedFilter = {
|
||||||
|
x86_64-linux = "c698b081ff957afe17a6d94374537d37f2a63f6f9dd75da7546542407a9e32476ebda3312ba7785d7f618542bcfaf27ca27dcc2dddba852069d28bcfe8cad39a";
|
||||||
|
aarch64-linux = "433ce9b911282d6dcc8029319fb79b816b60d5a795ec8fc94344dd027614d68f023166a91bb881faaeeedd26e3d89474e141e5a69a97e93b8984ca8f14999980";
|
||||||
|
};
|
||||||
|
|
||||||
|
want = {
|
||||||
|
env = [
|
||||||
|
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/65534/bus"
|
||||||
|
"HOME=/var/lib/hakurei/u0/a5"
|
||||||
|
"PULSE_SERVER=unix:/run/user/65534/pulse/native"
|
||||||
|
"SHELL=/run/current-system/sw/bin/bash"
|
||||||
|
"TERM=linux"
|
||||||
|
"USER=u0_a5"
|
||||||
|
"WAYLAND_DISPLAY=wayland-0"
|
||||||
|
"XDG_RUNTIME_DIR=/run/user/65534"
|
||||||
|
"XDG_SESSION_CLASS=user"
|
||||||
|
"XDG_SESSION_TYPE=tty"
|
||||||
|
];
|
||||||
|
|
||||||
|
fs = fs "dead" {
|
||||||
|
".hakurei" = fs "800001ed" { } null;
|
||||||
|
bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
|
||||||
|
dev = fs "800001ed" {
|
||||||
|
console = fs "4200190" null null;
|
||||||
|
core = fs "80001ff" null null;
|
||||||
|
dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
|
||||||
|
fd = fs "80001ff" null null;
|
||||||
|
full = fs "42001b6" null null;
|
||||||
|
mqueue = fs "801001ff" { } null;
|
||||||
|
null = fs "42001b6" null "";
|
||||||
|
ptmx = fs "80001ff" null null;
|
||||||
|
pts = fs "800001ed" { ptmx = fs "42001b6" null null; } null;
|
||||||
|
random = fs "42001b6" null null;
|
||||||
|
shm = fs "800001ed" { } null;
|
||||||
|
stderr = fs "80001ff" null null;
|
||||||
|
stdin = fs "80001ff" null null;
|
||||||
|
stdout = fs "80001ff" null null;
|
||||||
|
tty = fs "42001b6" null null;
|
||||||
|
urandom = fs "42001b6" null null;
|
||||||
|
zero = fs "42001b6" null null;
|
||||||
|
} null;
|
||||||
|
etc = fs "800001ed" {
|
||||||
|
".clean" = fs "80001ff" null null;
|
||||||
|
".host" = fs "800001c0" null null;
|
||||||
|
".updated" = fs "80001ff" null null;
|
||||||
|
"NIXOS" = fs "80001ff" null null;
|
||||||
|
"X11" = fs "80001ff" null null;
|
||||||
|
"alsa" = fs "80001ff" null null;
|
||||||
|
"bash_logout" = fs "80001ff" null null;
|
||||||
|
"bashrc" = fs "80001ff" null null;
|
||||||
|
"binfmt.d" = fs "80001ff" null null;
|
||||||
|
"dbus-1" = fs "80001ff" null null;
|
||||||
|
"default" = fs "80001ff" null null;
|
||||||
|
"dhcpcd.exit-hook" = fs "80001ff" null null;
|
||||||
|
"fonts" = fs "80001ff" null null;
|
||||||
|
"fstab" = fs "80001ff" null null;
|
||||||
|
"hsurc" = fs "80001ff" null null;
|
||||||
|
"fuse.conf" = fs "80001ff" null null;
|
||||||
|
"group" = fs "180" null "hakurei:x:65534:\n";
|
||||||
|
"host.conf" = fs "80001ff" null null;
|
||||||
|
"hostname" = fs "80001ff" null null;
|
||||||
|
"hosts" = fs "80001ff" null null;
|
||||||
|
"inputrc" = fs "80001ff" null null;
|
||||||
|
"issue" = fs "80001ff" null null;
|
||||||
|
"kbd" = fs "80001ff" null null;
|
||||||
|
"locale.conf" = fs "80001ff" null null;
|
||||||
|
"login.defs" = fs "80001ff" null null;
|
||||||
|
"lsb-release" = fs "80001ff" null null;
|
||||||
|
"lvm" = fs "80001ff" null null;
|
||||||
|
"machine-id" = fs "80001ff" null null;
|
||||||
|
"man_db.conf" = fs "80001ff" null null;
|
||||||
|
"modprobe.d" = fs "80001ff" null null;
|
||||||
|
"modules-load.d" = fs "80001ff" null null;
|
||||||
|
"mtab" = fs "80001ff" null null;
|
||||||
|
"nanorc" = fs "80001ff" null null;
|
||||||
|
"netgroup" = fs "80001ff" null null;
|
||||||
|
"nix" = fs "80001ff" null null;
|
||||||
|
"nixos" = fs "80001ff" null null;
|
||||||
|
"nscd.conf" = fs "80001ff" null null;
|
||||||
|
"nsswitch.conf" = fs "80001ff" null null;
|
||||||
|
"os-release" = fs "80001ff" null null;
|
||||||
|
"pam" = fs "80001ff" null null;
|
||||||
|
"pam.d" = fs "80001ff" null null;
|
||||||
|
"passwd" = fs "180" null "u0_a5:x:65534:65534:Hakurei:/var/lib/hakurei/u0/a5:/run/current-system/sw/bin/bash\n";
|
||||||
|
"pipewire" = fs "80001ff" null null;
|
||||||
|
"pki" = fs "80001ff" null null;
|
||||||
|
"polkit-1" = fs "80001ff" null null;
|
||||||
|
"profile" = fs "80001ff" null null;
|
||||||
|
"protocols" = fs "80001ff" null null;
|
||||||
|
"resolv.conf" = fs "80001ff" null null;
|
||||||
|
"resolvconf.conf" = fs "80001ff" null null;
|
||||||
|
"rpc" = fs "80001ff" null null;
|
||||||
|
"services" = fs "80001ff" null null;
|
||||||
|
"set-environment" = fs "80001ff" null null;
|
||||||
|
"shadow" = fs "80001ff" null null;
|
||||||
|
"shells" = fs "80001ff" null null;
|
||||||
|
"ssh" = fs "80001ff" null null;
|
||||||
|
"ssl" = fs "80001ff" null null;
|
||||||
|
"static" = fs "80001ff" null null;
|
||||||
|
"subgid" = fs "80001ff" null null;
|
||||||
|
"subuid" = fs "80001ff" null null;
|
||||||
|
"sudoers" = fs "80001ff" null null;
|
||||||
|
"sway" = fs "80001ff" null null;
|
||||||
|
"sysctl.d" = fs "80001ff" null null;
|
||||||
|
"systemd" = fs "80001ff" null null;
|
||||||
|
"terminfo" = fs "80001ff" null null;
|
||||||
|
"tmpfiles.d" = fs "80001ff" null null;
|
||||||
|
"udev" = fs "80001ff" null null;
|
||||||
|
"vconsole.conf" = fs "80001ff" null null;
|
||||||
|
"xdg" = fs "80001ff" null null;
|
||||||
|
"zoneinfo" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
nix = fs "800001c0" { store = fs "801001fd" null null; } null;
|
||||||
|
proc = fs "8000016d" null null;
|
||||||
|
run = fs "800001ed" {
|
||||||
|
current-system = fs "80001ff" null null;
|
||||||
|
opengl-driver = fs "80001ff" null null;
|
||||||
|
user = fs "800001ed" {
|
||||||
|
"65534" = fs "800001f8" {
|
||||||
|
bus = fs "10001fd" null null;
|
||||||
|
pulse = fs "800001c0" { native = fs "10001b6" null null; } null;
|
||||||
|
wayland-0 = fs "1000038" null null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
sys = fs "800001c0" {
|
||||||
|
block = fs "800001ed" (
|
||||||
|
{
|
||||||
|
${extraPaths.${system}.fd} = fs "80001ff" null null;
|
||||||
|
loop0 = fs "80001ff" null null;
|
||||||
|
loop1 = fs "80001ff" null null;
|
||||||
|
loop2 = fs "80001ff" null null;
|
||||||
|
loop3 = fs "80001ff" null null;
|
||||||
|
loop4 = fs "80001ff" null null;
|
||||||
|
loop5 = fs "80001ff" null null;
|
||||||
|
loop6 = fs "80001ff" null null;
|
||||||
|
loop7 = fs "80001ff" null null;
|
||||||
|
vda = fs "80001ff" null null;
|
||||||
|
}
|
||||||
|
// extraPaths.${system}.sr
|
||||||
|
) null;
|
||||||
|
bus = fs "800001ed" null null;
|
||||||
|
class = fs "800001ed" null null;
|
||||||
|
dev = fs "800001ed" {
|
||||||
|
block = fs "800001ed" null null;
|
||||||
|
char = fs "800001ed" null null;
|
||||||
|
} null;
|
||||||
|
devices = fs "800001ed" null null;
|
||||||
|
} null;
|
||||||
|
tmp = fs "800001f8" { } null;
|
||||||
|
usr = fs "800001c0" { bin = fs "800001ed" { env = fs "80001ff" null null; } null; } null;
|
||||||
|
var = fs "800001c0" {
|
||||||
|
lib = fs "800001c0" {
|
||||||
|
hakurei = fs "800001c0" {
|
||||||
|
u0 = fs "800001c0" {
|
||||||
|
a5 = fs "800001c0" {
|
||||||
|
".cache" = fs "800001ed" { ".keep" = fs "80001ff" 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" {
|
||||||
|
share = fs "800001ed" {
|
||||||
|
dbus-1 = fs "800001ed" {
|
||||||
|
services = fs "800001ed" {
|
||||||
|
"ca.desrt.dconf.service" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
state = fs "800001ed" {
|
||||||
|
".keep" = fs "80001ff" null "";
|
||||||
|
home-manager = fs "800001ed" { gcroots = fs "800001ed" { current-home = fs "80001ff" null null; } null; } null;
|
||||||
|
nix = fs "800001ed" {
|
||||||
|
profiles = fs "800001ed" {
|
||||||
|
home-manager = fs "80001ff" null null;
|
||||||
|
home-manager-1-link = fs "80001ff" null null;
|
||||||
|
profile = fs "80001ff" null null;
|
||||||
|
profile-1-link = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
".nix-defexpr" = fs "800001ed" {
|
||||||
|
channels = fs "80001ff" null null;
|
||||||
|
channels_root = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
".nix-profile" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
run = fs "800001ed" { nscd = fs "800001ed" { } null; } null;
|
||||||
|
} null;
|
||||||
|
} null;
|
||||||
|
|
||||||
|
mount = [
|
||||||
|
(ent "/sysroot" "/" "rw,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000005,gid=1000005")
|
||||||
|
(ent "/" "/proc" "rw,nosuid,nodev,noexec,relatime" "proc" "proc" "rw")
|
||||||
|
(ent "/" "/.hakurei" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=4k,mode=755,uid=1000005,gid=1000005")
|
||||||
|
(ent "/" "/dev" "rw,nosuid,nodev,relatime" "tmpfs" "devtmpfs" "rw,mode=755,uid=1000005,gid=1000005")
|
||||||
|
(ent "/null" "/dev/null" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/zero" "/dev/zero" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/full" "/dev/full" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/random" "/dev/random" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/urandom" "/dev/urandom" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/tty" "/dev/tty" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(ent "/" "/dev/pts" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,mode=620,ptmxmode=666")
|
||||||
|
(ent ignore "/dev/console" "rw,nosuid,noexec,relatime" "devpts" "devpts" "rw,gid=3,mode=620,ptmxmode=666")
|
||||||
|
(ent "/" "/dev/mqueue" "rw,nosuid,nodev,noexec,relatime" "mqueue" "mqueue" "rw")
|
||||||
|
(ent "/bin" "/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
|
(ent "/usr/bin" "/usr/bin" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
|
(ent "/" "/nix/store" "ro,nosuid,nodev,relatime" "overlay" "overlay" "rw,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work,uuid=on")
|
||||||
|
(ent "/block" "/sys/block" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
|
(ent "/bus" "/sys/bus" "ro,nosuid,nodev,noexec,relatime" "sysfs" "sysfs" "rw")
|
||||||
|
(ent "/class" "/sys/class" "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 "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
|
(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=1000005,gid=1000005")
|
||||||
|
(ent "/tmp/hakurei.1000/runtime/5" "/run/user/65534" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
|
(ent "/tmp/hakurei.1000/tmpdir/5" "/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
|
(ent "/var/lib/hakurei/u0/a5" "/var/lib/hakurei/u0/a5" "rw,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
|
(ent ignore "/etc/passwd" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000005,gid=1000005")
|
||||||
|
(ent ignore "/etc/group" "ro,nosuid,nodev,relatime" "tmpfs" "rootfs" "rw,uid=1000005,gid=1000005")
|
||||||
|
(ent ignore "/run/user/65534/wayland-0" "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/bus" "ro,nosuid,nodev,relatime" "ext4" "/dev/disk/by-label/nixos" "rw")
|
||||||
|
(ent "/" "/var/run/nscd" "rw,nosuid,nodev,relatime" "tmpfs" "tmpfs" "rw,size=8k,mode=755,uid=1000005,gid=1000005")
|
||||||
|
];
|
||||||
|
|
||||||
|
seccomp = true;
|
||||||
|
};
|
||||||
|
}
|
@ -2,13 +2,44 @@
|
|||||||
fs,
|
fs,
|
||||||
ent,
|
ent,
|
||||||
ignore,
|
ignore,
|
||||||
|
system,
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
extraPaths = {
|
||||||
|
x86_64-linux = {
|
||||||
|
fd = "fd0";
|
||||||
|
"/dev/dri" = {
|
||||||
|
by-path = fs "800001ed" {
|
||||||
|
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
||||||
|
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
card0 = fs "42001b0" null null;
|
||||||
|
renderD128 = fs "42001b6" null null;
|
||||||
|
};
|
||||||
|
sr = {
|
||||||
|
sr0 = fs "80001ff" null null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
fd = "mtdblock0";
|
||||||
|
"/dev/dri" = null;
|
||||||
|
sr = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "preset";
|
name = "preset";
|
||||||
tty = false;
|
tty = false;
|
||||||
device = false;
|
device = false;
|
||||||
mapRealUid = false;
|
mapRealUid = false;
|
||||||
useCommonPaths = false;
|
useCommonPaths = false;
|
||||||
|
userns = false;
|
||||||
|
|
||||||
|
# 0, PresetStrict
|
||||||
|
expectedFilter = {
|
||||||
|
x86_64-linux = "e880298df2bd6751d0040fc21bc0ed4c00f95dc0d7ba506c244d8b8cf6866dba8ef4a33296f287b66cccc1d78e97026597f84cc7dec1573e148960fbd35cd735";
|
||||||
|
aarch64-linux = "79318538a3dc851314b6bd96f10d5861acb2aa7e13cb8de0619d0f6a76709d67f01ef3fd67e195862b02f9711e5b769bc4d1eb4fc0dfc41a723c89c968a93297";
|
||||||
|
};
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -29,14 +60,7 @@
|
|||||||
bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
|
bin = fs "800001ed" { sh = fs "80001ff" null null; } null;
|
||||||
dev = fs "800001ed" {
|
dev = fs "800001ed" {
|
||||||
core = fs "80001ff" null null;
|
core = fs "80001ff" null null;
|
||||||
dri = fs "800001ed" {
|
dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
|
||||||
by-path = fs "800001ed" {
|
|
||||||
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
|
||||||
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
|
||||||
} null;
|
|
||||||
card0 = fs "42001b0" null null;
|
|
||||||
renderD128 = fs "42001b6" null null;
|
|
||||||
} null;
|
|
||||||
fd = fs "80001ff" null null;
|
fd = fs "80001ff" null null;
|
||||||
full = fs "42001b6" null null;
|
full = fs "42001b6" null null;
|
||||||
mqueue = fs "801001ff" { } null;
|
mqueue = fs "801001ff" { } null;
|
||||||
@ -137,19 +161,21 @@
|
|||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
sys = fs "800001c0" {
|
sys = fs "800001c0" {
|
||||||
block = fs "800001ed" {
|
block = fs "800001ed" (
|
||||||
fd0 = fs "80001ff" null null;
|
{
|
||||||
loop0 = fs "80001ff" null null;
|
${extraPaths.${system}.fd} = fs "80001ff" null null;
|
||||||
loop1 = fs "80001ff" null null;
|
loop0 = fs "80001ff" null null;
|
||||||
loop2 = fs "80001ff" null null;
|
loop1 = fs "80001ff" null null;
|
||||||
loop3 = fs "80001ff" null null;
|
loop2 = fs "80001ff" null null;
|
||||||
loop4 = fs "80001ff" null null;
|
loop3 = fs "80001ff" null null;
|
||||||
loop5 = fs "80001ff" null null;
|
loop4 = fs "80001ff" null null;
|
||||||
loop6 = fs "80001ff" null null;
|
loop5 = fs "80001ff" null null;
|
||||||
loop7 = fs "80001ff" null null;
|
loop6 = fs "80001ff" null null;
|
||||||
sr0 = fs "80001ff" null null;
|
loop7 = fs "80001ff" null null;
|
||||||
vda = fs "80001ff" null null;
|
vda = fs "80001ff" null null;
|
||||||
} null;
|
}
|
||||||
|
// extraPaths.${system}.sr
|
||||||
|
) null;
|
||||||
bus = fs "800001ed" null null;
|
bus = fs "800001ed" null null;
|
||||||
class = fs "800001ed" null null;
|
class = fs "800001ed" null null;
|
||||||
dev = fs "800001ed" {
|
dev = fs "800001ed" {
|
||||||
|
@ -2,13 +2,44 @@
|
|||||||
fs,
|
fs,
|
||||||
ent,
|
ent,
|
||||||
ignore,
|
ignore,
|
||||||
|
system,
|
||||||
}:
|
}:
|
||||||
|
let
|
||||||
|
extraPaths = {
|
||||||
|
x86_64-linux = {
|
||||||
|
fd = "fd0";
|
||||||
|
"/dev/dri" = {
|
||||||
|
by-path = fs "800001ed" {
|
||||||
|
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
||||||
|
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
||||||
|
} null;
|
||||||
|
card0 = fs "42001b0" null null;
|
||||||
|
renderD128 = fs "42001b6" null null;
|
||||||
|
};
|
||||||
|
sr = {
|
||||||
|
sr0 = fs "80001ff" null null;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
aarch64-linux = {
|
||||||
|
fd = "mtdblock0";
|
||||||
|
"/dev/dri" = null;
|
||||||
|
sr = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
{
|
{
|
||||||
name = "tty";
|
name = "tty";
|
||||||
tty = true;
|
tty = true;
|
||||||
device = false;
|
device = false;
|
||||||
mapRealUid = false;
|
mapRealUid = false;
|
||||||
useCommonPaths = true;
|
useCommonPaths = true;
|
||||||
|
userns = false;
|
||||||
|
|
||||||
|
# 0, PresetExt | PresetDenyNS | PresetDenyDevel
|
||||||
|
expectedFilter = {
|
||||||
|
x86_64-linux = "0b76007476c1c9e25dbf674c29fdf609a1656a70063e49327654e1b5360ad3da06e1a3e32bf80e961c5516ad83d4b9e7e9bde876a93797e27627d2555c25858b";
|
||||||
|
aarch64-linux = "cf1f4dc87436ba8ec95d268b663a6397bb0b4a5ac64d8557e6cc529d8b0f6f65dad3a92b62ed29d85eee9c6dde1267757a4d0f86032e8a45ca1bceadfa34cf5e";
|
||||||
|
};
|
||||||
|
|
||||||
want = {
|
want = {
|
||||||
env = [
|
env = [
|
||||||
@ -30,14 +61,7 @@
|
|||||||
dev = fs "800001ed" {
|
dev = fs "800001ed" {
|
||||||
console = fs "4200190" null null;
|
console = fs "4200190" null null;
|
||||||
core = fs "80001ff" null null;
|
core = fs "80001ff" null null;
|
||||||
dri = fs "800001ed" {
|
dri = fs "800001ed" extraPaths.${system}."/dev/dri" null;
|
||||||
by-path = fs "800001ed" {
|
|
||||||
"pci-0000:00:09.0-card" = fs "80001ff" null null;
|
|
||||||
"pci-0000:00:09.0-render" = fs "80001ff" null null;
|
|
||||||
} null;
|
|
||||||
card0 = fs "42001b0" null null;
|
|
||||||
renderD128 = fs "42001b6" null null;
|
|
||||||
} null;
|
|
||||||
fd = fs "80001ff" null null;
|
fd = fs "80001ff" null null;
|
||||||
full = fs "42001b6" null null;
|
full = fs "42001b6" null null;
|
||||||
mqueue = fs "801001ff" { } null;
|
mqueue = fs "801001ff" { } null;
|
||||||
@ -138,19 +162,21 @@
|
|||||||
} null;
|
} null;
|
||||||
} null;
|
} null;
|
||||||
sys = fs "800001c0" {
|
sys = fs "800001c0" {
|
||||||
block = fs "800001ed" {
|
block = fs "800001ed" (
|
||||||
fd0 = fs "80001ff" null null;
|
{
|
||||||
loop0 = fs "80001ff" null null;
|
${extraPaths.${system}.fd} = fs "80001ff" null null;
|
||||||
loop1 = fs "80001ff" null null;
|
loop0 = fs "80001ff" null null;
|
||||||
loop2 = fs "80001ff" null null;
|
loop1 = fs "80001ff" null null;
|
||||||
loop3 = fs "80001ff" null null;
|
loop2 = fs "80001ff" null null;
|
||||||
loop4 = fs "80001ff" null null;
|
loop3 = fs "80001ff" null null;
|
||||||
loop5 = fs "80001ff" null null;
|
loop4 = fs "80001ff" null null;
|
||||||
loop6 = fs "80001ff" null null;
|
loop5 = fs "80001ff" null null;
|
||||||
loop7 = fs "80001ff" null null;
|
loop6 = fs "80001ff" null null;
|
||||||
sr0 = fs "80001ff" null null;
|
loop7 = fs "80001ff" null null;
|
||||||
vda = fs "80001ff" null null;
|
vda = fs "80001ff" null null;
|
||||||
} null;
|
}
|
||||||
|
// extraPaths.${system}.sr
|
||||||
|
) null;
|
||||||
bus = fs "800001ed" null null;
|
bus = fs "800001ed" null null;
|
||||||
class = fs "800001ed" null null;
|
class = fs "800001ed" null null;
|
||||||
dev = fs "800001ed" {
|
dev = fs "800001ed" {
|
||||||
|
@ -75,6 +75,6 @@ in
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
apps = import ./case lib testProgram;
|
apps = import ./case pkgs.system lib testProgram;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package sandbox_test
|
package sandbox_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package sandbox_test
|
package sandbox_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,49 +37,19 @@ func ptrace(op uintptr, pid, addr int, data unsafe.Pointer) (r uintptr, errno sy
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ptraceAttach(pid int) error {
|
func ptraceAttach(pid int) error {
|
||||||
const (
|
|
||||||
statePrefix = "State:"
|
|
||||||
stateSuffix = "t (tracing stop)"
|
|
||||||
)
|
|
||||||
|
|
||||||
var r io.ReadSeekCloser
|
|
||||||
if f, err := os.Open(fmt.Sprintf("/proc/%d/status", pid)); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
r = f
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, errno := ptrace(PTRACE_ATTACH, pid, 0, nil); errno != 0 {
|
if _, errno := ptrace(PTRACE_ATTACH, pid, 0, nil); errno != 0 {
|
||||||
return &ptraceError{"PTRACE_ATTACH", errno}
|
return &ptraceError{"PTRACE_ATTACH", errno}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ugly! but there does not appear to be another way
|
var status syscall.WaitStatus
|
||||||
for {
|
for {
|
||||||
time.Sleep(10 * time.Millisecond)
|
if _, err := syscall.Wait4(pid, &status, syscall.WALL, nil); err != nil {
|
||||||
|
if errors.Is(err, syscall.EINTR) {
|
||||||
if _, err := r.Seek(0, io.SeekStart); err != nil {
|
continue
|
||||||
return err
|
|
||||||
}
|
|
||||||
s := bufio.NewScanner(r)
|
|
||||||
|
|
||||||
var found bool
|
|
||||||
for s.Scan() {
|
|
||||||
found = strings.HasPrefix(s.Text(), statePrefix)
|
|
||||||
if found {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
fatalf("cannot waitpid: %v", err)
|
||||||
}
|
}
|
||||||
if err := s.Err(); err != nil {
|
break
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return syscall.EBADE
|
|
||||||
}
|
|
||||||
|
|
||||||
if strings.HasSuffix(s.Text(), stateSuffix) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package sandbox
|
package sandbox
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -18,7 +20,6 @@ func trySyscalls() error {
|
|||||||
trap, a1, a2, a3, a4, a5, a6 uintptr
|
trap, a1, a2, a3, a4, a5, a6 uintptr
|
||||||
}{
|
}{
|
||||||
{"syslog", syscall.EPERM, syscall.SYS_SYSLOG, 0, NULL, NULL, NULL, NULL, NULL},
|
{"syslog", syscall.EPERM, syscall.SYS_SYSLOG, 0, NULL, NULL, NULL, NULL, NULL},
|
||||||
{"uselib", syscall.EPERM, syscall.SYS_USELIB, 0, NULL, NULL, NULL, NULL, NULL},
|
|
||||||
{"acct", syscall.EPERM, syscall.SYS_ACCT, 0, NULL, NULL, NULL, NULL, NULL},
|
{"acct", syscall.EPERM, syscall.SYS_ACCT, 0, NULL, NULL, NULL, NULL, NULL},
|
||||||
{"quotactl", syscall.EPERM, syscall.SYS_QUOTACTL, C.Q_GETQUOTA, NULL, uintptr(os.Getuid()), NULL, NULL, NULL},
|
{"quotactl", syscall.EPERM, syscall.SYS_QUOTACTL, C.Q_GETQUOTA, NULL, uintptr(os.Getuid()), NULL, NULL, NULL},
|
||||||
{"add_key", syscall.EPERM, syscall.SYS_ADD_KEY, NULL, NULL, NULL, NULL, NULL, NULL},
|
{"add_key", syscall.EPERM, syscall.SYS_ADD_KEY, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||||
|
@ -25,6 +25,12 @@ def swaymsg(command: str = "", succeed=True, type="command"):
|
|||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
|
|
||||||
|
def check_filter(check_offset, name, pname):
|
||||||
|
pid = int(machine.wait_until_succeeds(f"pgrep -U {1000000+check_offset} -x {pname}", timeout=15))
|
||||||
|
hash = machine.succeed(f"sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 WAYLAND_DISPLAY=wayland-1 check-sandbox-{name} hash 2>/dev/null")
|
||||||
|
print(machine.succeed(f"hakurei-test -s {hash} filter {pid}"))
|
||||||
|
|
||||||
|
|
||||||
start_all()
|
start_all()
|
||||||
machine.wait_for_unit("multi-user.target")
|
machine.wait_for_unit("multi-user.target")
|
||||||
|
|
||||||
@ -35,11 +41,9 @@ print(machine.succeed("sudo -u alice -i hakurei version"))
|
|||||||
machine.wait_for_file("/run/user/1000/wayland-1")
|
machine.wait_for_file("/run/user/1000/wayland-1")
|
||||||
machine.wait_for_file("/tmp/sway-ipc.sock")
|
machine.wait_for_file("/tmp/sway-ipc.sock")
|
||||||
|
|
||||||
# Check seccomp outcome:
|
# Check pd seccomp outcome:
|
||||||
swaymsg("exec hakurei run cat")
|
swaymsg("exec hakurei run cat")
|
||||||
pid = int(machine.wait_until_succeeds("pgrep -U 1000000 -x cat", timeout=5))
|
check_filter(0, "pdlike", "cat")
|
||||||
print(machine.succeed(f"hakurei-test filter {pid} c698b081ff957afe17a6d94374537d37f2a63f6f9dd75da7546542407a9e32476ebda3312ba7785d7f618542bcfaf27ca27dcc2dddba852069d28bcfe8cad39a &>/dev/stdout", timeout=5))
|
|
||||||
machine.succeed(f"kill -TERM {pid}")
|
|
||||||
|
|
||||||
# Verify capabilities/securebits in user namespace:
|
# Verify capabilities/securebits in user namespace:
|
||||||
print(machine.succeed("sudo -u alice -i hakurei run capsh --print"))
|
print(machine.succeed("sudo -u alice -i hakurei run capsh --print"))
|
||||||
@ -57,12 +61,14 @@ def check_sandbox(name):
|
|||||||
check_offset += 1
|
check_offset += 1
|
||||||
swaymsg(f"exec script /dev/null -E always -qec check-sandbox-{name}")
|
swaymsg(f"exec script /dev/null -E always -qec check-sandbox-{name}")
|
||||||
machine.wait_for_file(f"/tmp/hakurei.1000/tmpdir/{check_offset}/sandbox-ok", timeout=15)
|
machine.wait_for_file(f"/tmp/hakurei.1000/tmpdir/{check_offset}/sandbox-ok", timeout=15)
|
||||||
|
check_filter(check_offset, name, "hakurei-test")
|
||||||
|
|
||||||
|
|
||||||
check_sandbox("preset")
|
check_sandbox("preset")
|
||||||
check_sandbox("tty")
|
check_sandbox("tty")
|
||||||
check_sandbox("mapuid")
|
check_sandbox("mapuid")
|
||||||
check_sandbox("device")
|
check_sandbox("device")
|
||||||
|
check_sandbox("pdlike")
|
||||||
|
|
||||||
# Exit Sway and verify process exit status 0:
|
# Exit Sway and verify process exit status 0:
|
||||||
swaymsg("exit", succeed=False)
|
swaymsg("exit", succeed=False)
|
||||||
|
@ -1,39 +1,71 @@
|
|||||||
|
//go:build testtool
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/test/sandbox"
|
"hakurei.app/test/sandbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
flagTestCase string
|
||||||
|
flagBpfHash string
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flag.StringVar(&flagTestCase, "t", "", "Nix store path to test case file")
|
||||||
|
flag.StringVar(&flagBpfHash, "s", "", "String representation of expected bpf sha512 hash")
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
log.SetPrefix("test: ")
|
log.SetPrefix("test: ")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
if len(os.Args) < 2 {
|
args := flag.Args()
|
||||||
log.Fatal("invalid argument")
|
if len(args) < 1 {
|
||||||
|
s := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(s, syscall.SIGINT)
|
||||||
|
go func() { <-s; log.Println("exiting on signal (likely from verifier)"); os.Exit(0) }()
|
||||||
|
|
||||||
|
(&sandbox.T{FS: os.DirFS("/")}).MustCheckFile(flagTestCase)
|
||||||
|
if _, err := os.Create("/tmp/sandbox-ok"); err != nil {
|
||||||
|
log.Fatalf("cannot create success marker: %v", err)
|
||||||
|
}
|
||||||
|
log.Println("blocking for seccomp check")
|
||||||
|
select {}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch os.Args[1] {
|
switch args[0] {
|
||||||
case "filter":
|
case "filter":
|
||||||
if len(os.Args) != 4 {
|
if len(args) != 2 {
|
||||||
log.Fatal("invalid argument")
|
log.Fatal("invalid argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
if pid, err := strconv.Atoi(strings.TrimSpace(os.Args[2])); err != nil {
|
if pid, err := strconv.Atoi(strings.TrimSpace(args[1])); err != nil {
|
||||||
log.Fatalf("%s", err)
|
log.Fatalf("%s", err)
|
||||||
} else if pid < 1 {
|
} else if pid < 1 {
|
||||||
log.Fatalf("%d out of range", pid)
|
log.Fatalf("%d out of range", pid)
|
||||||
} else {
|
} else {
|
||||||
sandbox.MustCheckFilter(pid, os.Args[3])
|
sandbox.MustCheckFilter(pid, flagBpfHash)
|
||||||
return
|
if err = syscall.Kill(pid, syscall.SIGINT); err != nil {
|
||||||
|
log.Fatalf("cannot signal check process: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "hash": // this eases the pain of passing the hash to python
|
||||||
|
fmt.Print(flagBpfHash)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
(&sandbox.T{FS: os.DirFS("/")}).MustCheckFile(os.Args[1], "/tmp/sandbox-ok")
|
log.Fatal("invalid argument")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ buildGoModule rec {
|
|||||||
};
|
};
|
||||||
vendorHash = null;
|
vendorHash = null;
|
||||||
|
|
||||||
|
tags = [ "testtool" ];
|
||||||
|
|
||||||
buildInputs = [ util-linux ];
|
buildInputs = [ util-linux ];
|
||||||
nativeBuildInputs = [ pkg-config ];
|
nativeBuildInputs = [ pkg-config ];
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user