container: remove global msg
All checks were successful
Test / Create distribution (push) Successful in 1m10s
Test / Sandbox (push) Successful in 2m40s
Test / Hakurei (push) Successful in 3m58s
Test / Hpkg (push) Successful in 4m44s
Test / Sandbox (race detector) (push) Successful in 5m1s
Test / Hakurei (race detector) (push) Successful in 6m2s
Test / Flake checks (push) Successful in 1m47s
All checks were successful
Test / Create distribution (push) Successful in 1m10s
Test / Sandbox (push) Successful in 2m40s
Test / Hakurei (push) Successful in 3m58s
Test / Hpkg (push) Successful in 4m44s
Test / Sandbox (race detector) (push) Successful in 5m1s
Test / Hakurei (race detector) (push) Successful in 6m2s
Test / Flake checks (push) Successful in 1m47s
This frees all container instances of side effects. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -34,7 +34,7 @@ func (r *AutoRootOp) early(state *setupState, k syscallDispatcher) error {
|
||||
r.resolved = make([]*BindMountOp, 0, len(d))
|
||||
for _, ent := range d {
|
||||
name := ent.Name()
|
||||
if IsAutoRootBindable(name) {
|
||||
if IsAutoRootBindable(state, name) {
|
||||
// careful: the Valid method is skipped, make sure this is always valid
|
||||
op := &BindMountOp{
|
||||
Source: r.Host.Append(name),
|
||||
@@ -78,7 +78,7 @@ func (r *AutoRootOp) String() string {
|
||||
}
|
||||
|
||||
// IsAutoRootBindable returns whether a dir entry name is selected for AutoRoot.
|
||||
func IsAutoRootBindable(name string) bool {
|
||||
func IsAutoRootBindable(msg Msg, name string) bool {
|
||||
switch name {
|
||||
case "proc", "dev", "tmp", "mnt", "etc":
|
||||
|
||||
|
||||
@@ -180,19 +180,26 @@ func TestIsAutoRootBindable(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
want bool
|
||||
log bool
|
||||
}{
|
||||
{"proc", false},
|
||||
{"dev", false},
|
||||
{"tmp", false},
|
||||
{"mnt", false},
|
||||
{"etc", false},
|
||||
{"", false},
|
||||
{"proc", false, false},
|
||||
{"dev", false, false},
|
||||
{"tmp", false, false},
|
||||
{"mnt", false, false},
|
||||
{"etc", false, false},
|
||||
{"", false, true},
|
||||
|
||||
{"var", true},
|
||||
{"var", true, false},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got := IsAutoRootBindable(tc.name); got != tc.want {
|
||||
var msg Msg
|
||||
if tc.log {
|
||||
msg = &kstub{nil, stub.New(t, func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { panic("unreachable") }, stub.Expect{Calls: []stub.Call{
|
||||
call("verbose", stub.ExpectArgs{[]any{"got unexpected root entry"}}, nil, nil),
|
||||
}})}
|
||||
}
|
||||
if got := IsAutoRootBindable(msg, tc.name); got != tc.want {
|
||||
t.Errorf("IsAutoRootBindable: %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -49,6 +49,7 @@ type (
|
||||
|
||||
cmd *exec.Cmd
|
||||
ctx context.Context
|
||||
msg Msg
|
||||
Params
|
||||
}
|
||||
|
||||
@@ -162,10 +163,10 @@ func (p *Container) Start() error {
|
||||
|
||||
// map to overflow id to work around ownership checks
|
||||
if p.Uid < 1 {
|
||||
p.Uid = OverflowUid()
|
||||
p.Uid = OverflowUid(p.msg)
|
||||
}
|
||||
if p.Gid < 1 {
|
||||
p.Gid = OverflowGid()
|
||||
p.Gid = OverflowGid(p.msg)
|
||||
}
|
||||
|
||||
if !p.RetainSession {
|
||||
@@ -263,19 +264,19 @@ func (p *Container) Start() error {
|
||||
}
|
||||
return &StartError{false, "kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET", ENOSYS, true, false}
|
||||
} else {
|
||||
msg.Verbosef("landlock abi version %d", abi)
|
||||
p.msg.Verbosef("landlock abi version %d", abi)
|
||||
}
|
||||
|
||||
if rulesetFd, err := rulesetAttr.Create(0); err != nil {
|
||||
return &StartError{true, "create landlock ruleset", err, false, false}
|
||||
} else {
|
||||
msg.Verbosef("enforcing landlock ruleset %s", rulesetAttr)
|
||||
p.msg.Verbosef("enforcing landlock ruleset %s", rulesetAttr)
|
||||
if err = LandlockRestrictSelf(rulesetFd, 0); err != nil {
|
||||
_ = Close(rulesetFd)
|
||||
return &StartError{true, "enforce landlock ruleset", err, false, false}
|
||||
}
|
||||
if err = Close(rulesetFd); err != nil {
|
||||
msg.Verbosef("cannot close landlock ruleset: %v", err)
|
||||
p.msg.Verbosef("cannot close landlock ruleset: %v", err)
|
||||
// not fatal
|
||||
}
|
||||
}
|
||||
@@ -283,7 +284,7 @@ func (p *Container) Start() error {
|
||||
landlockOut:
|
||||
}
|
||||
|
||||
msg.Verbose("starting container init")
|
||||
p.msg.Verbose("starting container init")
|
||||
if err := p.cmd.Start(); err != nil {
|
||||
return &StartError{false, "start container init", err, false, true}
|
||||
}
|
||||
@@ -325,7 +326,7 @@ func (p *Container) Serve() error {
|
||||
Getuid(),
|
||||
Getgid(),
|
||||
len(p.ExtraFiles),
|
||||
msg.IsVerbose(),
|
||||
p.msg.IsVerbose(),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -392,17 +393,21 @@ func (p *Container) ProcessState() *os.ProcessState {
|
||||
}
|
||||
|
||||
// New returns the address to a new instance of [Container] that requires further initialisation before use.
|
||||
func New(ctx context.Context) *Container {
|
||||
p := &Container{ctx: ctx, Params: Params{Ops: new(Ops)}}
|
||||
func New(ctx context.Context, msg Msg) *Container {
|
||||
if msg == nil {
|
||||
msg = NewMsg(nil)
|
||||
}
|
||||
|
||||
p := &Container{ctx: ctx, msg: msg, Params: Params{Ops: new(Ops)}}
|
||||
c, cancel := context.WithCancel(ctx)
|
||||
p.cancel = cancel
|
||||
p.cmd = exec.CommandContext(c, MustExecutable())
|
||||
p.cmd = exec.CommandContext(c, MustExecutable(msg))
|
||||
return p
|
||||
}
|
||||
|
||||
// NewCommand calls [New] and initialises the [Params.Path] and [Params.Args] fields.
|
||||
func NewCommand(ctx context.Context, pathname *Absolute, name string, args ...string) *Container {
|
||||
z := New(ctx)
|
||||
func NewCommand(ctx context.Context, msg Msg, pathname *Absolute, name string, args ...string) *Container {
|
||||
z := New(ctx, msg)
|
||||
z.Path = pathname
|
||||
z.Args = append([]string{name}, args...)
|
||||
return z
|
||||
|
||||
@@ -23,8 +23,6 @@ import (
|
||||
"hakurei.app/container/seccomp"
|
||||
"hakurei.app/container/vfs"
|
||||
"hakurei.app/hst"
|
||||
"hakurei.app/internal"
|
||||
"hakurei.app/internal/hlog"
|
||||
"hakurei.app/ldd"
|
||||
)
|
||||
|
||||
@@ -351,8 +349,6 @@ var containerTestCases = []struct {
|
||||
}
|
||||
|
||||
func TestContainer(t *testing.T) {
|
||||
replaceOutput(t)
|
||||
|
||||
t.Run("cancel", testContainerCancel(nil, func(t *testing.T, c *container.Container) {
|
||||
wantErr := context.Canceled
|
||||
wantExitCode := 0
|
||||
@@ -547,7 +543,8 @@ func testContainerCancel(
|
||||
}
|
||||
|
||||
func TestContainerString(t *testing.T) {
|
||||
c := container.NewCommand(t.Context(), container.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env")
|
||||
msg := container.NewMsg(nil)
|
||||
c := container.NewCommand(t.Context(), msg, container.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env")
|
||||
c.SeccompFlags |= seccomp.AllowMultiarch
|
||||
c.SeccompRules = seccomp.Preset(
|
||||
seccomp.PresetExt|seccomp.PresetDenyNS|seccomp.PresetDenyTTY,
|
||||
@@ -689,7 +686,7 @@ var (
|
||||
var helperCommands []func(c command.Command)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
container.TryArgv0(hlog.Output{}, hlog.Prepare, internal.InstallOutput)
|
||||
container.TryArgv0(nil)
|
||||
|
||||
if os.Getenv(envDoCheck) == "1" {
|
||||
c := command.New(os.Stderr, log.Printf, "helper", func(args []string) error {
|
||||
@@ -712,12 +709,13 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*container.Absolute, args ...string) (c *container.Container) {
|
||||
c = container.NewCommand(ctx, absHelperInnerPath, "helper", args...)
|
||||
msg := container.NewMsg(nil)
|
||||
c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...)
|
||||
c.Env = append(c.Env, envDoCheck+"=1")
|
||||
c.Bind(container.MustAbs(os.Args[0]), absHelperInnerPath, 0)
|
||||
|
||||
// in case test has cgo enabled
|
||||
if entries, err := ldd.Exec(ctx, os.Args[0]); err != nil {
|
||||
if entries, err := ldd.Exec(ctx, msg, os.Args[0]); err != nil {
|
||||
log.Fatalf("ldd: %v", err)
|
||||
} else {
|
||||
*libPaths = ldd.Path(entries)
|
||||
|
||||
@@ -3,7 +3,6 @@ package container
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
@@ -38,7 +37,7 @@ type syscallDispatcher interface {
|
||||
setNoNewPrivs() error
|
||||
|
||||
// lastcap provides [LastCap].
|
||||
lastcap() uintptr
|
||||
lastcap(msg Msg) uintptr
|
||||
// capset provides capset.
|
||||
capset(hdrp *capHeader, datap *[2]capData) error
|
||||
// capBoundingSetDrop provides capBoundingSetDrop.
|
||||
@@ -53,9 +52,9 @@ type syscallDispatcher interface {
|
||||
receive(key string, e any, fdp *uintptr) (closeFunc func() error, err error)
|
||||
|
||||
// bindMount provides procPaths.bindMount.
|
||||
bindMount(source, target string, flags uintptr) error
|
||||
bindMount(msg Msg, source, target string, flags uintptr) error
|
||||
// remount provides procPaths.remount.
|
||||
remount(target string, flags uintptr) error
|
||||
remount(msg Msg, target string, flags uintptr) error
|
||||
// mountTmpfs provides mountTmpfs.
|
||||
mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error
|
||||
// ensureFile provides ensureFile.
|
||||
@@ -122,22 +121,12 @@ type syscallDispatcher interface {
|
||||
// wait4 provides syscall.Wait4
|
||||
wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error)
|
||||
|
||||
// printf provides [log.Printf].
|
||||
printf(format string, v ...any)
|
||||
// fatal provides [log.Fatal]
|
||||
fatal(v ...any)
|
||||
// fatalf provides [log.Fatalf]
|
||||
fatalf(format string, v ...any)
|
||||
// verbose provides [Msg.Verbose].
|
||||
verbose(v ...any)
|
||||
// verbosef provides [Msg.Verbosef].
|
||||
verbosef(format string, v ...any)
|
||||
// suspend provides [Msg.Suspend].
|
||||
suspend()
|
||||
// resume provides [Msg.Resume].
|
||||
resume() bool
|
||||
// beforeExit provides [Msg.BeforeExit].
|
||||
beforeExit()
|
||||
// printf provides the Printf method of [log.Logger].
|
||||
printf(msg Msg, format string, v ...any)
|
||||
// fatal provides the Fatal method of [log.Logger]
|
||||
fatal(msg Msg, v ...any)
|
||||
// fatalf provides the Fatalf method of [log.Logger]
|
||||
fatalf(msg Msg, format string, v ...any)
|
||||
}
|
||||
|
||||
// direct implements syscallDispatcher on the current kernel.
|
||||
@@ -151,7 +140,7 @@ func (direct) setPtracer(pid uintptr) error { return SetPtracer(pid) }
|
||||
func (direct) setDumpable(dumpable uintptr) error { return SetDumpable(dumpable) }
|
||||
func (direct) setNoNewPrivs() error { return SetNoNewPrivs() }
|
||||
|
||||
func (direct) lastcap() uintptr { return LastCap() }
|
||||
func (direct) lastcap(msg Msg) uintptr { return LastCap(msg) }
|
||||
func (direct) capset(hdrp *capHeader, datap *[2]capData) error { return capset(hdrp, datap) }
|
||||
func (direct) capBoundingSetDrop(cap uintptr) error { return capBoundingSetDrop(cap) }
|
||||
func (direct) capAmbientClearAll() error { return capAmbientClearAll() }
|
||||
@@ -161,11 +150,11 @@ func (direct) receive(key string, e any, fdp *uintptr) (func() error, error) {
|
||||
return Receive(key, e, fdp)
|
||||
}
|
||||
|
||||
func (direct) bindMount(source, target string, flags uintptr) error {
|
||||
return hostProc.bindMount(source, target, flags)
|
||||
func (direct) bindMount(msg Msg, source, target string, flags uintptr) error {
|
||||
return hostProc.bindMount(msg, source, target, flags)
|
||||
}
|
||||
func (direct) remount(target string, flags uintptr) error {
|
||||
return hostProc.remount(target, flags)
|
||||
func (direct) remount(msg Msg, target string, flags uintptr) error {
|
||||
return hostProc.remount(msg, target, flags)
|
||||
}
|
||||
func (k direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||
return mountTmpfs(k, fsname, target, flags, size, perm)
|
||||
@@ -232,11 +221,6 @@ func (direct) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *s
|
||||
return syscall.Wait4(pid, wstatus, options, rusage)
|
||||
}
|
||||
|
||||
func (direct) printf(format string, v ...any) { log.Printf(format, v...) }
|
||||
func (direct) fatal(v ...any) { log.Fatal(v...) }
|
||||
func (direct) fatalf(format string, v ...any) { log.Fatalf(format, v...) }
|
||||
func (direct) verbose(v ...any) { msg.Verbose(v...) }
|
||||
func (direct) verbosef(format string, v ...any) { msg.Verbosef(format, v...) }
|
||||
func (direct) suspend() { msg.Suspend() }
|
||||
func (direct) resume() bool { return msg.Resume() }
|
||||
func (direct) beforeExit() { msg.BeforeExit() }
|
||||
func (direct) printf(msg Msg, format string, v ...any) { msg.GetLogger().Printf(format, v...) }
|
||||
func (direct) fatal(msg Msg, v ...any) { msg.GetLogger().Fatal(v...) }
|
||||
func (direct) fatalf(msg Msg, format string, v ...any) { msg.GetLogger().Fatalf(format, v...) }
|
||||
|
||||
@@ -2,8 +2,10 @@ package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
@@ -136,7 +138,7 @@ func call(name string, args stub.ExpectArgs, ret any, err error) stub.Call {
|
||||
|
||||
type simpleTestCase struct {
|
||||
name string
|
||||
f func(k syscallDispatcher) error
|
||||
f func(k *kstub) error
|
||||
want stub.Expect
|
||||
wantErr error
|
||||
}
|
||||
@@ -185,11 +187,11 @@ func checkOpBehaviour(t *testing.T, testCases []opBehaviourTestCase) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Helper()
|
||||
|
||||
state := &setupState{Params: tc.params}
|
||||
k := &kstub{nil, stub.New(t,
|
||||
func(s *stub.Stub[syscallDispatcher]) syscallDispatcher { return &kstub{nil, s} },
|
||||
stub.Expect{Calls: slices.Concat(tc.early, []stub.Call{{Name: stub.CallSeparator}}, tc.apply)},
|
||||
)}
|
||||
state := &setupState{Params: tc.params, Msg: k}
|
||||
defer stub.HandleExit(t)
|
||||
errEarly := tc.op.early(state, k)
|
||||
k.Expects(stub.CallSeparator)
|
||||
@@ -327,7 +329,11 @@ func (k *kstub) setDumpable(dumpable uintptr) error {
|
||||
}
|
||||
|
||||
func (k *kstub) setNoNewPrivs() error { k.Helper(); return k.Expects("setNoNewPrivs").Err }
|
||||
func (k *kstub) lastcap() uintptr { k.Helper(); return k.Expects("lastcap").Ret.(uintptr) }
|
||||
func (k *kstub) lastcap(msg Msg) uintptr {
|
||||
k.Helper()
|
||||
k.checkMsg(msg)
|
||||
return k.Expects("lastcap").Ret.(uintptr)
|
||||
}
|
||||
|
||||
func (k *kstub) capset(hdrp *capHeader, datap *[2]capData) error {
|
||||
k.Helper()
|
||||
@@ -403,16 +409,18 @@ func (k *kstub) receive(key string, e any, fdp *uintptr) (closeFunc func() error
|
||||
return
|
||||
}
|
||||
|
||||
func (k *kstub) bindMount(source, target string, flags uintptr) error {
|
||||
func (k *kstub) bindMount(msg Msg, source, target string, flags uintptr) error {
|
||||
k.Helper()
|
||||
k.checkMsg(msg)
|
||||
return k.Expects("bindMount").Error(
|
||||
stub.CheckArg(k.Stub, "source", source, 0),
|
||||
stub.CheckArg(k.Stub, "target", target, 1),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 2))
|
||||
}
|
||||
|
||||
func (k *kstub) remount(target string, flags uintptr) error {
|
||||
func (k *kstub) remount(msg Msg, target string, flags uintptr) error {
|
||||
k.Helper()
|
||||
k.checkMsg(msg)
|
||||
return k.Expects("remount").Error(
|
||||
stub.CheckArg(k.Stub, "target", target, 0),
|
||||
stub.CheckArg(k.Stub, "flags", flags, 1))
|
||||
@@ -694,7 +702,7 @@ func (k *kstub) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage
|
||||
return
|
||||
}
|
||||
|
||||
func (k *kstub) printf(format string, v ...any) {
|
||||
func (k *kstub) printf(_ Msg, format string, v ...any) {
|
||||
k.Helper()
|
||||
if k.Expects("printf").Error(
|
||||
stub.CheckArg(k.Stub, "format", format, 0),
|
||||
@@ -703,7 +711,7 @@ func (k *kstub) printf(format string, v ...any) {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) fatal(v ...any) {
|
||||
func (k *kstub) fatal(_ Msg, v ...any) {
|
||||
k.Helper()
|
||||
if k.Expects("fatal").Error(
|
||||
stub.CheckArgReflect(k.Stub, "v", v, 0)) != nil {
|
||||
@@ -712,7 +720,7 @@ func (k *kstub) fatal(v ...any) {
|
||||
panic(stub.PanicExit)
|
||||
}
|
||||
|
||||
func (k *kstub) fatalf(format string, v ...any) {
|
||||
func (k *kstub) fatalf(_ Msg, format string, v ...any) {
|
||||
k.Helper()
|
||||
if k.Expects("fatalf").Error(
|
||||
stub.CheckArg(k.Stub, "format", format, 0),
|
||||
@@ -722,7 +730,35 @@ func (k *kstub) fatalf(format string, v ...any) {
|
||||
panic(stub.PanicExit)
|
||||
}
|
||||
|
||||
func (k *kstub) verbose(v ...any) {
|
||||
func (k *kstub) checkMsg(msg Msg) {
|
||||
k.Helper()
|
||||
var target *kstub
|
||||
|
||||
if state, ok := msg.(*setupState); ok {
|
||||
target = state.Msg.(*kstub)
|
||||
} else {
|
||||
target = msg.(*kstub)
|
||||
}
|
||||
|
||||
if k != target {
|
||||
panic(fmt.Sprintf("unexpected Msg: %#v", msg))
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) GetLogger() *log.Logger { panic("unreachable") }
|
||||
func (k *kstub) IsVerbose() bool { panic("unreachable") }
|
||||
|
||||
func (k *kstub) SwapVerbose(verbose bool) bool {
|
||||
k.Helper()
|
||||
expect := k.Expects("swapVerbose")
|
||||
if expect.Error(
|
||||
stub.CheckArg(k.Stub, "verbose", verbose, 0)) != nil {
|
||||
k.FailNow()
|
||||
}
|
||||
return expect.Ret.(bool)
|
||||
}
|
||||
|
||||
func (k *kstub) Verbose(v ...any) {
|
||||
k.Helper()
|
||||
if k.Expects("verbose").Error(
|
||||
stub.CheckArgReflect(k.Stub, "v", v, 0)) != nil {
|
||||
@@ -730,7 +766,7 @@ func (k *kstub) verbose(v ...any) {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) verbosef(format string, v ...any) {
|
||||
func (k *kstub) Verbosef(format string, v ...any) {
|
||||
k.Helper()
|
||||
if k.Expects("verbosef").Error(
|
||||
stub.CheckArg(k.Stub, "format", format, 0),
|
||||
@@ -739,6 +775,6 @@ func (k *kstub) verbosef(format string, v ...any) {
|
||||
}
|
||||
}
|
||||
|
||||
func (k *kstub) suspend() { k.Helper(); k.Expects("suspend") }
|
||||
func (k *kstub) resume() bool { k.Helper(); return k.Expects("resume").Ret.(bool) }
|
||||
func (k *kstub) beforeExit() { k.Helper(); k.Expects("beforeExit") }
|
||||
func (k *kstub) Suspend() bool { k.Helper(); return k.Expects("suspend").Ret.(bool) }
|
||||
func (k *kstub) Resume() bool { k.Helper(); return k.Expects("resume").Ret.(bool) }
|
||||
func (k *kstub) BeforeExit() { k.Helper(); k.Expects("beforeExit") }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
@@ -11,16 +10,16 @@ var (
|
||||
executableOnce sync.Once
|
||||
)
|
||||
|
||||
func copyExecutable() {
|
||||
func copyExecutable(msg Msg) {
|
||||
if name, err := os.Executable(); err != nil {
|
||||
msg.BeforeExit()
|
||||
log.Fatalf("cannot read executable path: %v", err)
|
||||
msg.GetLogger().Fatalf("cannot read executable path: %v", err)
|
||||
} else {
|
||||
executable = name
|
||||
}
|
||||
}
|
||||
|
||||
func MustExecutable() string {
|
||||
executableOnce.Do(copyExecutable)
|
||||
func MustExecutable(msg Msg) string {
|
||||
executableOnce.Do(func() { copyExecutable(msg) })
|
||||
return executable
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
func TestExecutable(t *testing.T) {
|
||||
for i := 0; i < 16; i++ {
|
||||
if got := container.MustExecutable(); got != os.Args[0] {
|
||||
if got := container.MustExecutable(container.NewMsg(nil)); got != os.Args[0] {
|
||||
t.Errorf("MustExecutable: %q, want %q",
|
||||
got, os.Args[0])
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package container
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@@ -59,6 +60,7 @@ type (
|
||||
setupState struct {
|
||||
nonrepeatable uintptr
|
||||
*Params
|
||||
Msg
|
||||
}
|
||||
)
|
||||
|
||||
@@ -91,20 +93,23 @@ type initParams struct {
|
||||
Verbose bool
|
||||
}
|
||||
|
||||
func Init(prepareLogger func(prefix string), setVerbose func(verbose bool)) {
|
||||
initEntrypoint(direct{}, prepareLogger, setVerbose)
|
||||
// Init is called by [TryArgv0] if the current process is the container init.
|
||||
func Init(msg Msg) {
|
||||
if msg == nil {
|
||||
panic("attempting to call initEntrypoint with nil msg")
|
||||
}
|
||||
initEntrypoint(direct{}, msg)
|
||||
}
|
||||
|
||||
func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setVerbose func(verbose bool)) {
|
||||
func initEntrypoint(k syscallDispatcher, msg Msg) {
|
||||
k.lockOSThread()
|
||||
prepareLogger("init")
|
||||
|
||||
if k.getpid() != 1 {
|
||||
k.fatal("this process must run as pid 1")
|
||||
k.fatal(msg, "this process must run as pid 1")
|
||||
}
|
||||
|
||||
if err := k.setPtracer(0); err != nil {
|
||||
k.verbosef("cannot enable ptrace protection via Yama LSM: %v", err)
|
||||
msg.Verbosef("cannot enable ptrace protection via Yama LSM: %v", err)
|
||||
// not fatal: this program has no additional privileges at initial program start
|
||||
}
|
||||
|
||||
@@ -116,65 +121,65 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
)
|
||||
if f, err := k.receive(setupEnv, ¶ms, &setupFd); err != nil {
|
||||
if errors.Is(err, EBADF) {
|
||||
k.fatal("invalid setup descriptor")
|
||||
k.fatal(msg, "invalid setup descriptor")
|
||||
}
|
||||
if errors.Is(err, ErrReceiveEnv) {
|
||||
k.fatal("HAKUREI_SETUP not set")
|
||||
k.fatal(msg, "HAKUREI_SETUP not set")
|
||||
}
|
||||
|
||||
k.fatalf("cannot decode init setup payload: %v", err)
|
||||
k.fatalf(msg, "cannot decode init setup payload: %v", err)
|
||||
} else {
|
||||
if params.Ops == nil {
|
||||
k.fatal("invalid setup parameters")
|
||||
k.fatal(msg, "invalid setup parameters")
|
||||
}
|
||||
if params.ParentPerm == 0 {
|
||||
params.ParentPerm = 0755
|
||||
}
|
||||
|
||||
setVerbose(params.Verbose)
|
||||
k.verbose("received setup parameters")
|
||||
msg.SwapVerbose(params.Verbose)
|
||||
msg.Verbose("received setup parameters")
|
||||
closeSetup = f
|
||||
offsetSetup = int(setupFd + 1)
|
||||
}
|
||||
|
||||
// write uid/gid map here so parent does not need to set dumpable
|
||||
if err := k.setDumpable(SUID_DUMP_USER); err != nil {
|
||||
k.fatalf("cannot set SUID_DUMP_USER: %v", err)
|
||||
k.fatalf(msg, "cannot set SUID_DUMP_USER: %v", err)
|
||||
}
|
||||
if err := k.writeFile(FHSProc+"self/uid_map",
|
||||
append([]byte{}, strconv.Itoa(params.Uid)+" "+strconv.Itoa(params.HostUid)+" 1\n"...),
|
||||
0); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
k.fatalf(msg, "%v", err)
|
||||
}
|
||||
if err := k.writeFile(FHSProc+"self/setgroups",
|
||||
[]byte("deny\n"),
|
||||
0); err != nil && !os.IsNotExist(err) {
|
||||
k.fatalf("%v", err)
|
||||
k.fatalf(msg, "%v", err)
|
||||
}
|
||||
if err := k.writeFile(FHSProc+"self/gid_map",
|
||||
append([]byte{}, strconv.Itoa(params.Gid)+" "+strconv.Itoa(params.HostGid)+" 1\n"...),
|
||||
0); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
k.fatalf(msg, "%v", err)
|
||||
}
|
||||
if err := k.setDumpable(SUID_DUMP_DISABLE); err != nil {
|
||||
k.fatalf("cannot set SUID_DUMP_DISABLE: %v", err)
|
||||
k.fatalf(msg, "cannot set SUID_DUMP_DISABLE: %v", err)
|
||||
}
|
||||
|
||||
oldmask := k.umask(0)
|
||||
if params.Hostname != "" {
|
||||
if err := k.sethostname([]byte(params.Hostname)); err != nil {
|
||||
k.fatalf("cannot set hostname: %v", err)
|
||||
k.fatalf(msg, "cannot set hostname: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// cache sysctl before pivot_root
|
||||
lastcap := k.lastcap()
|
||||
lastcap := k.lastcap(msg)
|
||||
|
||||
if err := k.mount(zeroString, FHSRoot, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil {
|
||||
k.fatalf("cannot make / rslave: %v", err)
|
||||
k.fatalf(msg, "cannot make / rslave: %v", err)
|
||||
}
|
||||
|
||||
state := &setupState{Params: ¶ms.Params}
|
||||
state := &setupState{Params: ¶ms.Params, Msg: msg}
|
||||
|
||||
/* early is called right before pivot_root into intermediate root;
|
||||
this step is mostly for gathering information that would otherwise be difficult to obtain
|
||||
@@ -182,41 +187,41 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
the state of the mount namespace */
|
||||
for i, op := range *params.Ops {
|
||||
if op == nil || !op.Valid() {
|
||||
k.fatalf("invalid op at index %d", i)
|
||||
k.fatalf(msg, "invalid op at index %d", i)
|
||||
}
|
||||
|
||||
if err := op.early(state, k); err != nil {
|
||||
if m, ok := messageFromError(err); ok {
|
||||
k.fatal(m)
|
||||
k.fatal(msg, m)
|
||||
} else {
|
||||
k.fatalf("cannot prepare op at index %d: %v", i, err)
|
||||
k.fatalf(msg, "cannot prepare op at index %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := k.mount(SourceTmpfsRootfs, intermediateHostPath, FstypeTmpfs, MS_NODEV|MS_NOSUID, zeroString); err != nil {
|
||||
k.fatalf("cannot mount intermediate root: %v", err)
|
||||
k.fatalf(msg, "cannot mount intermediate root: %v", err)
|
||||
}
|
||||
if err := k.chdir(intermediateHostPath); err != nil {
|
||||
k.fatalf("cannot enter intermediate host path: %v", err)
|
||||
k.fatalf(msg, "cannot enter intermediate host path: %v", err)
|
||||
}
|
||||
|
||||
if err := k.mkdir(sysrootDir, 0755); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
k.fatalf(msg, "%v", err)
|
||||
}
|
||||
if err := k.mount(sysrootDir, sysrootDir, zeroString, MS_SILENT|MS_BIND|MS_REC, zeroString); err != nil {
|
||||
k.fatalf("cannot bind sysroot: %v", err)
|
||||
k.fatalf(msg, "cannot bind sysroot: %v", err)
|
||||
}
|
||||
|
||||
if err := k.mkdir(hostDir, 0755); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
k.fatalf(msg, "%v", err)
|
||||
}
|
||||
// pivot_root uncovers intermediateHostPath in hostDir
|
||||
if err := k.pivotRoot(intermediateHostPath, hostDir); err != nil {
|
||||
k.fatalf("cannot pivot into intermediate root: %v", err)
|
||||
k.fatalf(msg, "cannot pivot into intermediate root: %v", err)
|
||||
}
|
||||
if err := k.chdir(FHSRoot); err != nil {
|
||||
k.fatalf("cannot enter intermediate root: %v", err)
|
||||
k.fatalf(msg, "cannot enter intermediate root: %v", err)
|
||||
}
|
||||
|
||||
/* apply is called right after pivot_root and entering the new root;
|
||||
@@ -226,23 +231,23 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
for i, op := range *params.Ops {
|
||||
// ops already checked during early setup
|
||||
if prefix, ok := op.prefix(); ok {
|
||||
k.verbosef("%s %s", prefix, op)
|
||||
msg.Verbosef("%s %s", prefix, op)
|
||||
}
|
||||
if err := op.apply(state, k); err != nil {
|
||||
if m, ok := messageFromError(err); ok {
|
||||
k.fatal(m)
|
||||
k.fatal(msg, m)
|
||||
} else {
|
||||
k.fatalf("cannot apply op at index %d: %v", i, err)
|
||||
k.fatalf(msg, "cannot apply op at index %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup requiring host root complete at this point
|
||||
if err := k.mount(hostDir, hostDir, zeroString, MS_SILENT|MS_REC|MS_PRIVATE, zeroString); err != nil {
|
||||
k.fatalf("cannot make host root rprivate: %v", err)
|
||||
k.fatalf(msg, "cannot make host root rprivate: %v", err)
|
||||
}
|
||||
if err := k.unmount(hostDir, MNT_DETACH); err != nil {
|
||||
k.fatalf("cannot unmount host root: %v", err)
|
||||
k.fatalf(msg, "cannot unmount host root: %v", err)
|
||||
}
|
||||
|
||||
{
|
||||
@@ -251,39 +256,39 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
fd, err = k.open(FHSRoot, O_DIRECTORY|O_RDONLY, 0)
|
||||
return
|
||||
}); err != nil {
|
||||
k.fatalf("cannot open intermediate root: %v", err)
|
||||
k.fatalf(msg, "cannot open intermediate root: %v", err)
|
||||
}
|
||||
if err := k.chdir(sysrootPath); err != nil {
|
||||
k.fatalf("cannot enter sysroot: %v", err)
|
||||
k.fatalf(msg, "cannot enter sysroot: %v", err)
|
||||
}
|
||||
|
||||
if err := k.pivotRoot(".", "."); err != nil {
|
||||
k.fatalf("cannot pivot into sysroot: %v", err)
|
||||
k.fatalf(msg, "cannot pivot into sysroot: %v", err)
|
||||
}
|
||||
if err := k.fchdir(fd); err != nil {
|
||||
k.fatalf("cannot re-enter intermediate root: %v", err)
|
||||
k.fatalf(msg, "cannot re-enter intermediate root: %v", err)
|
||||
}
|
||||
if err := k.unmount(".", MNT_DETACH); err != nil {
|
||||
k.fatalf("cannot unmount intermediate root: %v", err)
|
||||
k.fatalf(msg, "cannot unmount intermediate root: %v", err)
|
||||
}
|
||||
if err := k.chdir(FHSRoot); err != nil {
|
||||
k.fatalf("cannot enter root: %v", err)
|
||||
k.fatalf(msg, "cannot enter root: %v", err)
|
||||
}
|
||||
|
||||
if err := k.close(fd); err != nil {
|
||||
k.fatalf("cannot close intermediate root: %v", err)
|
||||
k.fatalf(msg, "cannot close intermediate root: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := k.capAmbientClearAll(); err != nil {
|
||||
k.fatalf("cannot clear the ambient capability set: %v", err)
|
||||
k.fatalf(msg, "cannot clear the ambient capability set: %v", err)
|
||||
}
|
||||
for i := uintptr(0); i <= lastcap; i++ {
|
||||
if params.Privileged && i == CAP_SYS_ADMIN {
|
||||
continue
|
||||
}
|
||||
if err := k.capBoundingSetDrop(i); err != nil {
|
||||
k.fatalf("cannot drop capability from bounding set: %v", err)
|
||||
k.fatalf(msg, "cannot drop capability from bounding set: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,29 +297,29 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
keep[capToIndex(CAP_SYS_ADMIN)] |= capToMask(CAP_SYS_ADMIN)
|
||||
|
||||
if err := k.capAmbientRaise(CAP_SYS_ADMIN); err != nil {
|
||||
k.fatalf("cannot raise CAP_SYS_ADMIN: %v", err)
|
||||
k.fatalf(msg, "cannot raise CAP_SYS_ADMIN: %v", err)
|
||||
}
|
||||
}
|
||||
if err := k.capset(
|
||||
&capHeader{_LINUX_CAPABILITY_VERSION_3, 0},
|
||||
&[2]capData{{0, keep[0], keep[0]}, {0, keep[1], keep[1]}},
|
||||
); err != nil {
|
||||
k.fatalf("cannot capset: %v", err)
|
||||
k.fatalf(msg, "cannot capset: %v", err)
|
||||
}
|
||||
|
||||
if !params.SeccompDisable {
|
||||
rules := params.SeccompRules
|
||||
if len(rules) == 0 { // non-empty rules slice always overrides presets
|
||||
k.verbosef("resolving presets %#x", params.SeccompPresets)
|
||||
msg.Verbosef("resolving presets %#x", params.SeccompPresets)
|
||||
rules = seccomp.Preset(params.SeccompPresets, params.SeccompFlags)
|
||||
}
|
||||
if err := k.seccompLoad(rules, params.SeccompFlags); err != nil {
|
||||
// this also indirectly asserts PR_SET_NO_NEW_PRIVS
|
||||
k.fatalf("cannot load syscall filter: %v", err)
|
||||
k.fatalf(msg, "cannot load syscall filter: %v", err)
|
||||
}
|
||||
k.verbosef("%d filter rules loaded", len(rules))
|
||||
msg.Verbosef("%d filter rules loaded", len(rules))
|
||||
} else {
|
||||
k.verbose("syscall filter not configured")
|
||||
msg.Verbose("syscall filter not configured")
|
||||
}
|
||||
|
||||
extraFiles := make([]*os.File, params.Count)
|
||||
@@ -331,14 +336,14 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
cmd.ExtraFiles = extraFiles
|
||||
cmd.Dir = params.Dir.String()
|
||||
|
||||
k.verbosef("starting initial program %s", params.Path)
|
||||
msg.Verbosef("starting initial program %s", params.Path)
|
||||
if err := k.start(cmd); err != nil {
|
||||
k.fatalf("%v", err)
|
||||
k.fatalf(msg, "%v", err)
|
||||
}
|
||||
k.suspend()
|
||||
msg.Suspend()
|
||||
|
||||
if err := closeSetup(); err != nil {
|
||||
k.printf("cannot close setup pipe: %v", err)
|
||||
k.printf(msg, "cannot close setup pipe: %v", err)
|
||||
// not fatal
|
||||
}
|
||||
|
||||
@@ -372,7 +377,7 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
}
|
||||
}
|
||||
if !errors.Is(err, ECHILD) {
|
||||
k.printf("unexpected wait4 response: %v", err)
|
||||
k.printf(msg, "unexpected wait4 response: %v", err)
|
||||
}
|
||||
|
||||
close(done)
|
||||
@@ -389,50 +394,50 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
for {
|
||||
select {
|
||||
case s := <-sig:
|
||||
if k.resume() {
|
||||
k.verbosef("%s after process start", s.String())
|
||||
if msg.Resume() {
|
||||
msg.Verbosef("%s after process start", s.String())
|
||||
} else {
|
||||
k.verbosef("got %s", s.String())
|
||||
msg.Verbosef("got %s", s.String())
|
||||
}
|
||||
if s == CancelSignal && params.ForwardCancel && cmd.Process != nil {
|
||||
k.verbose("forwarding context cancellation")
|
||||
msg.Verbose("forwarding context cancellation")
|
||||
if err := k.signal(cmd, os.Interrupt); err != nil {
|
||||
k.printf("cannot forward cancellation: %v", err)
|
||||
k.printf(msg, "cannot forward cancellation: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
k.beforeExit()
|
||||
msg.BeforeExit()
|
||||
k.exit(0)
|
||||
|
||||
case w := <-info:
|
||||
if w.wpid == cmd.Process.Pid {
|
||||
// initial process exited, output is most likely available again
|
||||
k.resume()
|
||||
msg.Resume()
|
||||
|
||||
switch {
|
||||
case w.wstatus.Exited():
|
||||
r = w.wstatus.ExitStatus()
|
||||
k.verbosef("initial process exited with code %d", w.wstatus.ExitStatus())
|
||||
msg.Verbosef("initial process exited with code %d", w.wstatus.ExitStatus())
|
||||
|
||||
case w.wstatus.Signaled():
|
||||
r = 128 + int(w.wstatus.Signal())
|
||||
k.verbosef("initial process exited with signal %s", w.wstatus.Signal())
|
||||
msg.Verbosef("initial process exited with signal %s", w.wstatus.Signal())
|
||||
|
||||
default:
|
||||
r = 255
|
||||
k.verbosef("initial process exited with status %#x", w.wstatus)
|
||||
msg.Verbosef("initial process exited with status %#x", w.wstatus)
|
||||
}
|
||||
|
||||
go func() { time.Sleep(params.AdoptWaitDelay); close(timeout) }()
|
||||
}
|
||||
|
||||
case <-done:
|
||||
k.beforeExit()
|
||||
msg.BeforeExit()
|
||||
k.exit(r)
|
||||
|
||||
case <-timeout:
|
||||
k.printf("timeout exceeded waiting for lingering processes")
|
||||
k.beforeExit()
|
||||
k.printf(msg, "timeout exceeded waiting for lingering processes")
|
||||
msg.BeforeExit()
|
||||
k.exit(r)
|
||||
}
|
||||
}
|
||||
@@ -441,10 +446,16 @@ func initEntrypoint(k syscallDispatcher, prepareLogger func(prefix string), setV
|
||||
const initName = "init"
|
||||
|
||||
// TryArgv0 calls [Init] if the last element of argv0 is "init".
|
||||
func TryArgv0(v Msg, prepare func(prefix string), setVerbose func(verbose bool)) {
|
||||
// If a nil msg is passed, the system logger is used instead.
|
||||
func TryArgv0(msg Msg) {
|
||||
if msg == nil {
|
||||
log.SetPrefix(initName + ": ")
|
||||
log.SetFlags(0)
|
||||
msg = NewMsg(log.Default())
|
||||
}
|
||||
|
||||
if len(os.Args) > 0 && path.Base(os.Args[0]) == initName {
|
||||
msg = v
|
||||
Init(prepare, setVerbose)
|
||||
Init(msg)
|
||||
msg.BeforeExit()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
@@ -11,25 +11,9 @@ import (
|
||||
)
|
||||
|
||||
func TestInitEntrypoint(t *testing.T) {
|
||||
assertPrefix := func(prefix string) {
|
||||
if prefix != "init" {
|
||||
t.Fatalf("prepareLogger: prefix = %q", prefix)
|
||||
}
|
||||
}
|
||||
|
||||
assertVerboseFalse := func(verbose bool) {
|
||||
if verbose {
|
||||
t.Fatal("setVerbose: verbose = true, want false")
|
||||
}
|
||||
}
|
||||
assertVerboseTrue := func(verbose bool) {
|
||||
if !verbose {
|
||||
t.Fatal("setVerbose: verbose = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
checkSimple(t, "initEntrypoint", []simpleTestCase{
|
||||
{"getpid", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"getpid", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1<<10, nil),
|
||||
@@ -37,7 +21,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"receive bad fd", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"receive bad fd", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -47,7 +31,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"receive not set", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"receive not set", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -57,7 +41,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"receive payload decode", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"receive payload decode", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -67,7 +51,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"receive invalid params", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"receive invalid params", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -91,7 +75,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"setDumpable user", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"setDumpable user", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -112,13 +96,14 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(78), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, stub.UniqueError(77)),
|
||||
call("fatalf", stub.ExpectArgs{"cannot set SUID_DUMP_USER: %v", []any{stub.UniqueError(77)}}, nil, nil),
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"writeFile uid_map", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"writeFile uid_map", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -139,6 +124,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(76), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, stub.UniqueError(75)),
|
||||
@@ -146,7 +132,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"writeFile setgroups", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"writeFile setgroups", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -167,6 +153,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(74), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -175,7 +162,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"writeFile gid_map", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"writeFile gid_map", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -196,6 +183,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(72), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -205,7 +193,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"setDumpable disable", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"setDumpable disable", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -226,6 +214,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(70), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -236,7 +225,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"sethostname", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"sethostname", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -257,6 +246,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(68), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -269,7 +259,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"mount rslave root", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"mount rslave root", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -290,6 +280,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(66), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -304,7 +295,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"nil op", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"nil op", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -325,6 +316,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(64), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -341,7 +333,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"invalid op", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"invalid op", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -362,6 +354,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(63), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -378,7 +371,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"early unhandled error", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"early unhandled error", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -399,6 +392,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(62), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -416,7 +410,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"early", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"early", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -437,6 +431,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(60), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -454,7 +449,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"mount ih", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"mount ih", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -475,6 +470,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(59), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -493,7 +489,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"chdir ih", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"chdir ih", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -514,6 +510,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(57), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -533,7 +530,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"mkdir sysroot", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"mkdir sysroot", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -554,6 +551,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(55), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -574,7 +572,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"mount bind sysroot", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"mount bind sysroot", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -595,6 +593,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(53), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -616,7 +615,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"mkdir host", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"mkdir host", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -637,6 +636,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(51), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -659,7 +659,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"pivotRoot ir", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"pivotRoot ir", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -680,6 +680,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(49), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -703,7 +704,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"chdir ir", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"chdir ir", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -724,6 +725,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(47), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -748,7 +750,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"apply unhandled error", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"apply unhandled error", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -769,6 +771,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(45), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -802,7 +805,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"apply", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"apply", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -823,6 +826,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(43), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -856,7 +860,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"mount rprivate host", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"mount rprivate host", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -877,6 +881,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(42), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -911,7 +916,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"unmount host", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"unmount host", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -932,6 +937,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(40), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -967,7 +973,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"open ir", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"open ir", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -988,6 +994,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(38), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1025,7 +1032,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"chdir sysroot", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"chdir sysroot", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1046,6 +1053,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(36), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1084,7 +1092,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"pivotRoot sysroot", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"pivotRoot sysroot", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1105,6 +1113,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(34), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1144,7 +1153,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"fchdir ir", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"fchdir ir", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1165,6 +1174,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(32), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1205,7 +1215,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"unmount ir", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"unmount ir", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1226,6 +1236,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(30), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1267,7 +1278,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"chdir ir", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"chdir ir", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1288,6 +1299,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(28), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1330,7 +1342,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"close ir", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"close ir", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1351,6 +1363,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(26), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1394,7 +1407,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"capAmbientClearAll", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"capAmbientClearAll", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1415,6 +1428,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(24), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1459,7 +1473,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"capBoundingSetDrop", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"capBoundingSetDrop", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1480,6 +1494,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(22), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1532,7 +1547,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"capAmbientRaise", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"capAmbientRaise", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1553,6 +1568,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(20), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1638,7 +1654,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"capset", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"capset", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1659,6 +1675,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(18), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1745,7 +1762,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"seccompLoad", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"seccompLoad", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1766,6 +1783,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(16), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1854,7 +1872,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"start", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseFalse); return nil }, stub.Expect{
|
||||
{"start", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
call("getpid", stub.ExpectArgs{}, 1, nil),
|
||||
@@ -1874,6 +1892,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
}, 1971, 127, 2, false}, uintptr(0x39)}, stub.UniqueError(13), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{false}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("16777216 1971 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -1966,7 +1985,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
},
|
||||
}, nil},
|
||||
|
||||
{"lowlastcap signaled cancel forward error", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseFalse); return nil }, stub.Expect{
|
||||
{"lowlastcap signaled cancel forward error", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
/* entrypoint */
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
@@ -1987,6 +2006,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
}, 1971, 127, 2, false}, uintptr(0x39)}, stub.UniqueError(10), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{false}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("16777216 1971 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -2039,7 +2059,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("umask", stub.ExpectArgs{022}, 0, nil),
|
||||
call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil),
|
||||
call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil),
|
||||
call("suspend", stub.ExpectArgs{}, nil, nil),
|
||||
call("suspend", stub.ExpectArgs{}, true, nil),
|
||||
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(10)}}, nil, nil),
|
||||
call("New", stub.ExpectArgs{}, nil, nil),
|
||||
call("notify", stub.ExpectArgs{func(c chan<- os.Signal) { c <- CancelSignal }, []os.Signal{syscall.SIGINT, syscall.SIGTERM}}, nil, nil),
|
||||
@@ -2065,7 +2085,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
}}},
|
||||
}, nil},
|
||||
|
||||
{"lowlastcap signaled cancel", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseFalse); return nil }, stub.Expect{
|
||||
{"lowlastcap signaled cancel", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
/* entrypoint */
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
@@ -2086,6 +2106,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
}, 1971, 127, 2, false}, uintptr(0x39)}, stub.UniqueError(7), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{false}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("16777216 1971 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -2138,7 +2159,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("umask", stub.ExpectArgs{022}, 0, nil),
|
||||
call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil),
|
||||
call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil),
|
||||
call("suspend", stub.ExpectArgs{}, nil, nil),
|
||||
call("suspend", stub.ExpectArgs{}, true, nil),
|
||||
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(7)}}, nil, nil),
|
||||
call("New", stub.ExpectArgs{}, nil, nil),
|
||||
call("notify", stub.ExpectArgs{func(c chan<- os.Signal) { c <- os.Interrupt }, []os.Signal{syscall.SIGINT, syscall.SIGTERM}}, nil, nil),
|
||||
@@ -2155,7 +2176,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
}}},
|
||||
}, nil},
|
||||
|
||||
{"lowlastcap signaled timeout", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseFalse); return nil }, stub.Expect{
|
||||
{"lowlastcap signaled timeout", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
/* entrypoint */
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
@@ -2176,6 +2197,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
}, 1971, 127, 2, false}, uintptr(0x39)}, stub.UniqueError(5), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{false}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("16777216 1971 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -2228,7 +2250,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("umask", stub.ExpectArgs{022}, 0, nil),
|
||||
call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil),
|
||||
call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil),
|
||||
call("suspend", stub.ExpectArgs{}, nil, nil),
|
||||
call("suspend", stub.ExpectArgs{}, true, nil),
|
||||
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(5)}}, nil, nil),
|
||||
call("New", stub.ExpectArgs{}, nil, nil),
|
||||
call("notify", stub.ExpectArgs{nil, []os.Signal{syscall.SIGINT, syscall.SIGTERM}}, nil, nil),
|
||||
@@ -2247,7 +2269,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
}}},
|
||||
}, nil},
|
||||
|
||||
{"lowlastcap signaled", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseFalse); return nil }, stub.Expect{
|
||||
{"lowlastcap signaled", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
/* entrypoint */
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
@@ -2268,6 +2290,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
}, 1971, 127, 2, false}, uintptr(0x39)}, stub.UniqueError(3), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{false}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("16777216 1971 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -2320,7 +2343,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("umask", stub.ExpectArgs{022}, 0, nil),
|
||||
call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil),
|
||||
call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil),
|
||||
call("suspend", stub.ExpectArgs{}, nil, nil),
|
||||
call("suspend", stub.ExpectArgs{}, true, nil),
|
||||
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(3)}}, nil, nil),
|
||||
call("New", stub.ExpectArgs{}, nil, nil),
|
||||
call("notify", stub.ExpectArgs{nil, []os.Signal{syscall.SIGINT, syscall.SIGTERM}}, nil, nil),
|
||||
@@ -2346,7 +2369,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
}}},
|
||||
}, nil},
|
||||
|
||||
{"strangewait nopriv notty noseccomp yamafault", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseFalse); return nil }, stub.Expect{
|
||||
{"strangewait nopriv notty noseccomp yamafault", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
/* entrypoint */
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
@@ -2367,6 +2390,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
SeccompDisable: true,
|
||||
ParentPerm: 0750,
|
||||
}, 1971, 127, 2, false}, uintptr(0x39)}, stub.UniqueError(1), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{false}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("16777216 1971 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -2455,7 +2479,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("umask", stub.ExpectArgs{022}, 0, nil),
|
||||
call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/run/current-system/sw/bin/bash")}}, nil, nil),
|
||||
call("start", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent"}, &os.Process{Pid: 0xbad}, nil),
|
||||
call("suspend", stub.ExpectArgs{}, nil, nil),
|
||||
call("suspend", stub.ExpectArgs{}, true, nil),
|
||||
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(1)}}, nil, nil),
|
||||
call("New", stub.ExpectArgs{}, nil, nil),
|
||||
call("notify", stub.ExpectArgs{nil, []os.Signal{syscall.SIGINT, syscall.SIGTERM}}, nil, nil),
|
||||
@@ -2481,7 +2505,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
}}},
|
||||
}, nil},
|
||||
|
||||
{"success", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, stub.Expect{
|
||||
{"success", func(k *kstub) error { initEntrypoint(k, k); return nil }, stub.Expect{
|
||||
/* entrypoint */
|
||||
Calls: []stub.Call{
|
||||
call("lockOSThread", stub.ExpectArgs{}, nil, nil),
|
||||
@@ -2503,6 +2527,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
RetainSession: true,
|
||||
Privileged: true,
|
||||
}, 1000, 100, 3, true}, uintptr(9)}, stub.UniqueError(0), nil),
|
||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
||||
call("verbose", stub.ExpectArgs{[]any{"received setup parameters"}}, nil, nil),
|
||||
call("setDumpable", stub.ExpectArgs{uintptr(1)}, nil, nil),
|
||||
call("writeFile", stub.ExpectArgs{"/proc/self/uid_map", []byte("4294967296 1000 1\n"), os.FileMode(0)}, nil, nil),
|
||||
@@ -2594,7 +2619,7 @@ func TestInitEntrypoint(t *testing.T) {
|
||||
call("umask", stub.ExpectArgs{022}, 0, nil),
|
||||
call("verbosef", stub.ExpectArgs{"starting initial program %s", []any{MustAbs("/bin/zsh")}}, nil, nil),
|
||||
call("start", stub.ExpectArgs{"/bin/zsh", []string{"zsh", "-c", "exec vim"}, []string{"DISPLAY=:0"}, "/.hakurei"}, &os.Process{Pid: 0xcafe}, nil),
|
||||
call("suspend", stub.ExpectArgs{}, nil, nil),
|
||||
call("suspend", stub.ExpectArgs{}, true, nil),
|
||||
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(0)}}, nil, nil),
|
||||
call("New", stub.ExpectArgs{}, nil, nil),
|
||||
call("notify", stub.ExpectArgs{nil, []os.Signal{syscall.SIGINT, syscall.SIGTERM}}, nil, nil),
|
||||
|
||||
@@ -59,7 +59,7 @@ func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (b *BindMountOp) apply(_ *setupState, k syscallDispatcher) error {
|
||||
func (b *BindMountOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
if b.sourceFinal == nil {
|
||||
if b.Flags&BindOptional == 0 {
|
||||
// unreachable
|
||||
@@ -92,11 +92,11 @@ func (b *BindMountOp) apply(_ *setupState, k syscallDispatcher) error {
|
||||
}
|
||||
|
||||
if b.sourceFinal.String() == b.Target.String() {
|
||||
k.verbosef("mounting %q flags %#x", target, flags)
|
||||
state.Verbosef("mounting %q flags %#x", target, flags)
|
||||
} else {
|
||||
k.verbosef("mounting %q on %q flags %#x", source, target, flags)
|
||||
state.Verbosef("mounting %q on %q flags %#x", source, target, flags)
|
||||
}
|
||||
return k.bindMount(source, target, flags)
|
||||
return k.bindMount(state, source, target, flags)
|
||||
}
|
||||
|
||||
func (b *BindMountOp) Is(op Op) bool {
|
||||
|
||||
@@ -46,6 +46,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
return err
|
||||
}
|
||||
if err := k.bindMount(
|
||||
state,
|
||||
toHost(FHSDev+name),
|
||||
targetPath,
|
||||
0,
|
||||
@@ -93,6 +94,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
if name, err := k.readlink(hostProc.stdout()); err != nil {
|
||||
return err
|
||||
} else if err = k.bindMount(
|
||||
state,
|
||||
toHost(name),
|
||||
consolePath,
|
||||
0,
|
||||
@@ -116,7 +118,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := k.remount(target, MS_RDONLY); err != nil {
|
||||
if err := k.remount(state, target, MS_RDONLY); err != nil {
|
||||
return err
|
||||
}
|
||||
return k.mountTmpfs(SourceTmpfs, devShmPath, MS_NOSUID|MS_NODEV, 0, 01777)
|
||||
|
||||
@@ -52,6 +52,7 @@ func (t *TmpfileOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
if err := k.ensureFile(target, 0444, state.ParentPerm); err != nil {
|
||||
return err
|
||||
} else if err = k.bindMount(
|
||||
state,
|
||||
tmpPath,
|
||||
target,
|
||||
syscall.MS_RDONLY|syscall.MS_NODEV,
|
||||
|
||||
@@ -21,8 +21,8 @@ type RemountOp struct {
|
||||
|
||||
func (r *RemountOp) Valid() bool { return r != nil && r.Target != nil }
|
||||
func (*RemountOp) early(*setupState, syscallDispatcher) error { return nil }
|
||||
func (r *RemountOp) apply(_ *setupState, k syscallDispatcher) error {
|
||||
return k.remount(toSysroot(r.Target.String()), r.Flags)
|
||||
func (r *RemountOp) apply(state *setupState, k syscallDispatcher) error {
|
||||
return k.remount(state, toSysroot(r.Target.String()), r.Flags)
|
||||
}
|
||||
|
||||
func (r *RemountOp) Is(op Op) bool {
|
||||
|
||||
@@ -96,18 +96,17 @@ const (
|
||||
)
|
||||
|
||||
// bindMount mounts source on target and recursively applies flags if MS_REC is set.
|
||||
func (p *procPaths) bindMount(source, target string, flags uintptr) error {
|
||||
func (p *procPaths) bindMount(msg Msg, source, target string, flags uintptr) error {
|
||||
// syscallDispatcher.bindMount and procPaths.remount must not be called from this function
|
||||
|
||||
if err := p.k.mount(source, target, FstypeNULL, MS_SILENT|MS_BIND|flags&MS_REC, zeroString); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return p.k.remount(target, flags)
|
||||
return p.k.remount(msg, target, flags)
|
||||
}
|
||||
|
||||
// remount applies flags on target, recursively if MS_REC is set.
|
||||
func (p *procPaths) remount(target string, flags uintptr) error {
|
||||
func (p *procPaths) remount(msg Msg, target string, flags uintptr) error {
|
||||
// syscallDispatcher methods bindMount, remount must not be called from this function
|
||||
|
||||
var targetFinal string
|
||||
@@ -116,7 +115,7 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
||||
} else {
|
||||
targetFinal = v
|
||||
if targetFinal != target {
|
||||
p.k.verbosef("target resolves to %q", targetFinal)
|
||||
msg.Verbosef("target resolves to %q", targetFinal)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +145,7 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = remountWithFlags(p.k, n, mf); err != nil {
|
||||
if err = remountWithFlags(p.k, msg, n, mf); err != nil {
|
||||
return err
|
||||
}
|
||||
if flags&MS_REC == 0 {
|
||||
@@ -159,7 +158,7 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
||||
continue
|
||||
}
|
||||
|
||||
if err = remountWithFlags(p.k, cur, mf); err != nil && !errors.Is(err, EACCES) {
|
||||
if err = remountWithFlags(p.k, msg, cur, mf); err != nil && !errors.Is(err, EACCES) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -169,12 +168,12 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
||||
}
|
||||
|
||||
// remountWithFlags remounts mount point described by [vfs.MountInfoNode].
|
||||
func remountWithFlags(k syscallDispatcher, n *vfs.MountInfoNode, mf uintptr) error {
|
||||
func remountWithFlags(k syscallDispatcher, msg Msg, n *vfs.MountInfoNode, mf uintptr) error {
|
||||
// syscallDispatcher methods bindMount, remount must not be called from this function
|
||||
|
||||
kf, unmatched := n.Flags()
|
||||
if len(unmatched) != 0 {
|
||||
k.verbosef("unmatched vfs options: %q", unmatched)
|
||||
msg.Verbosef("unmatched vfs options: %q", unmatched)
|
||||
}
|
||||
|
||||
if kf&mf != mf {
|
||||
|
||||
@@ -11,21 +11,21 @@ import (
|
||||
|
||||
func TestBindMount(t *testing.T) {
|
||||
checkSimple(t, "bindMount", []simpleTestCase{
|
||||
{"mount", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/nix", syscall.MS_RDONLY)
|
||||
{"mount", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).bindMount(nil, "/host/nix", "/sysroot/nix", syscall.MS_RDONLY)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("mount", stub.ExpectArgs{"/host/nix", "/sysroot/nix", "", uintptr(0x9000), ""}, nil, stub.UniqueError(0xbad)),
|
||||
}}, stub.UniqueError(0xbad)},
|
||||
|
||||
{"success ne", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/.host-nix", syscall.MS_RDONLY)
|
||||
{"success ne", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).bindMount(k, "/host/nix", "/sysroot/.host-nix", syscall.MS_RDONLY)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("mount", stub.ExpectArgs{"/host/nix", "/sysroot/.host-nix", "", uintptr(0x9000), ""}, nil, nil),
|
||||
call("remount", stub.ExpectArgs{"/sysroot/.host-nix", uintptr(1)}, nil, nil),
|
||||
}}, nil},
|
||||
|
||||
{"success", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/nix", syscall.MS_RDONLY)
|
||||
{"success", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).bindMount(k, "/host/nix", "/sysroot/nix", syscall.MS_RDONLY)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("mount", stub.ExpectArgs{"/host/nix", "/sysroot/nix", "", uintptr(0x9000), ""}, nil, nil),
|
||||
call("remount", stub.ExpectArgs{"/sysroot/nix", uintptr(1)}, nil, nil),
|
||||
@@ -77,29 +77,29 @@ func TestRemount(t *testing.T) {
|
||||
416 415 0:30 / /sysroot/nix/store ro,relatime master:5 - overlay overlay rw,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work`
|
||||
|
||||
checkSimple(t, "remount", []simpleTestCase{
|
||||
{"evalSymlinks", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"evalSymlinks", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", stub.UniqueError(6)),
|
||||
}}, stub.UniqueError(6)},
|
||||
|
||||
{"open", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"open", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, stub.UniqueError(5)),
|
||||
}}, &os.PathError{Op: "open", Path: "/sysroot/nix", Err: stub.UniqueError(5)}},
|
||||
|
||||
{"readlink", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"readlink", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", stub.UniqueError(4)),
|
||||
}}, stub.UniqueError(4)},
|
||||
|
||||
{"close", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"close", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
@@ -107,8 +107,8 @@ func TestRemount(t *testing.T) {
|
||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, stub.UniqueError(3)),
|
||||
}}, &os.PathError{Op: "close", Path: "/sysroot/nix", Err: stub.UniqueError(3)}},
|
||||
|
||||
{"mountinfo no match", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"mountinfo no match", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(k, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/.hakurei", nil),
|
||||
call("verbosef", stub.ExpectArgs{"target resolves to %q", []any{"/sysroot/.hakurei"}}, nil, nil),
|
||||
@@ -118,8 +118,8 @@ func TestRemount(t *testing.T) {
|
||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||
}}, &vfs.DecoderError{Op: "unfold", Line: -1, Err: vfs.UnfoldTargetError("/sysroot/.hakurei")}},
|
||||
|
||||
{"mountinfo", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"mountinfo", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
@@ -128,8 +128,8 @@ func TestRemount(t *testing.T) {
|
||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile("\x00"), nil),
|
||||
}}, &vfs.DecoderError{Op: "parse", Line: 0, Err: vfs.ErrMountInfoFields}},
|
||||
|
||||
{"mount", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"mount", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
@@ -139,8 +139,8 @@ func TestRemount(t *testing.T) {
|
||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, stub.UniqueError(2)),
|
||||
}}, stub.UniqueError(2)},
|
||||
|
||||
{"mount propagate", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"mount propagate", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
@@ -151,8 +151,8 @@ func TestRemount(t *testing.T) {
|
||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, stub.UniqueError(1)),
|
||||
}}, stub.UniqueError(1)},
|
||||
|
||||
{"success toplevel", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/bin", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"success toplevel", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/bin", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/bin"}, "/sysroot/bin", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/bin", 0x280000, uint32(0)}, 0xbabe, nil),
|
||||
@@ -162,8 +162,8 @@ func TestRemount(t *testing.T) {
|
||||
call("mount", stub.ExpectArgs{"none", "/sysroot/bin", "", uintptr(0x209027), ""}, nil, nil),
|
||||
}}, nil},
|
||||
|
||||
{"success EACCES", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"success EACCES", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
@@ -175,8 +175,8 @@ func TestRemount(t *testing.T) {
|
||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/store", "", uintptr(0x209027), ""}, nil, nil),
|
||||
}}, nil},
|
||||
|
||||
{"success no propagate", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"success no propagate", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
@@ -186,8 +186,8 @@ func TestRemount(t *testing.T) {
|
||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
||||
}}, nil},
|
||||
|
||||
{"success case sensitive", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"success case sensitive", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
||||
@@ -199,8 +199,8 @@ func TestRemount(t *testing.T) {
|
||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/store", "", uintptr(0x209027), ""}, nil, nil),
|
||||
}}, nil},
|
||||
|
||||
{"success", func(k syscallDispatcher) error {
|
||||
return newProcPaths(k, hostPath).remount("/sysroot/.nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
{"success", func(k *kstub) error {
|
||||
return newProcPaths(k, hostPath).remount(k, "/sysroot/.nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/.nix"}, "/sysroot/NIX", nil),
|
||||
call("verbosef", stub.ExpectArgs{"target resolves to %q", []any{"/sysroot/NIX"}}, nil, nil),
|
||||
@@ -217,18 +217,18 @@ func TestRemount(t *testing.T) {
|
||||
|
||||
func TestRemountWithFlags(t *testing.T) {
|
||||
checkSimple(t, "remountWithFlags", []simpleTestCase{
|
||||
{"noop unmatched", func(k syscallDispatcher) error {
|
||||
return remountWithFlags(k, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime,cat"}}, 0)
|
||||
{"noop unmatched", func(k *kstub) error {
|
||||
return remountWithFlags(k, k, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime,cat"}}, 0)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("verbosef", stub.ExpectArgs{"unmatched vfs options: %q", []any{[]string{"cat"}}}, nil, nil),
|
||||
}}, nil},
|
||||
|
||||
{"noop", func(k syscallDispatcher) error {
|
||||
return remountWithFlags(k, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime"}}, 0)
|
||||
{"noop", func(k *kstub) error {
|
||||
return remountWithFlags(k, nil, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime"}}, 0)
|
||||
}, stub.Expect{}, nil},
|
||||
|
||||
{"success", func(k syscallDispatcher) error {
|
||||
return remountWithFlags(k, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime"}}, syscall.MS_RDONLY)
|
||||
{"success", func(k *kstub) error {
|
||||
return remountWithFlags(k, nil, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime"}}, syscall.MS_RDONLY)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("mount", stub.ExpectArgs{"none", "", "", uintptr(0x209021), ""}, nil, nil),
|
||||
}}, nil},
|
||||
@@ -237,20 +237,20 @@ func TestRemountWithFlags(t *testing.T) {
|
||||
|
||||
func TestMountTmpfs(t *testing.T) {
|
||||
checkSimple(t, "mountTmpfs", []simpleTestCase{
|
||||
{"mkdirAll", func(k syscallDispatcher) error {
|
||||
{"mkdirAll", func(k *kstub) error {
|
||||
return mountTmpfs(k, "ephemeral", "/sysroot/run/user/1000", 0, 1<<10, 0700)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/run/user/1000", os.FileMode(0700)}, nil, stub.UniqueError(0)),
|
||||
}}, stub.UniqueError(0)},
|
||||
|
||||
{"success no size", func(k syscallDispatcher) error {
|
||||
{"success no size", func(k *kstub) error {
|
||||
return mountTmpfs(k, "ephemeral", "/sysroot/run/user/1000", 0, 0, 0710)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/run/user/1000", os.FileMode(0750)}, nil, nil),
|
||||
call("mount", stub.ExpectArgs{"ephemeral", "/sysroot/run/user/1000", "tmpfs", uintptr(0), "mode=0710"}, nil, nil),
|
||||
}}, nil},
|
||||
|
||||
{"success", func(k syscallDispatcher) error {
|
||||
{"success", func(k *kstub) error {
|
||||
return mountTmpfs(k, "ephemeral", "/sysroot/run/user/1000", 0, 1<<10, 0700)
|
||||
}, stub.Expect{Calls: []stub.Call{
|
||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/run/user/1000", os.FileMode(0700)}, nil, nil),
|
||||
|
||||
@@ -23,45 +23,88 @@ func GetErrorMessage(err error) (string, bool) {
|
||||
return e.Message(), true
|
||||
}
|
||||
|
||||
// Msg is used for package-wide verbose logging.
|
||||
type Msg interface {
|
||||
// GetLogger returns the address of the underlying [log.Logger].
|
||||
GetLogger() *log.Logger
|
||||
|
||||
// IsVerbose atomically loads and returns whether [Msg] has verbose logging enabled.
|
||||
IsVerbose() bool
|
||||
// SwapVerbose atomically stores a new verbose state and returns the previous value held by [Msg].
|
||||
SwapVerbose(verbose bool) bool
|
||||
// Verbose passes its argument to the Println method of the underlying [log.Logger] if IsVerbose returns true.
|
||||
Verbose(v ...any)
|
||||
// Verbosef passes its argument to the Printf method of the underlying [log.Logger] if IsVerbose returns true.
|
||||
Verbosef(format string, v ...any)
|
||||
|
||||
Suspend()
|
||||
// Suspend causes the embedded [Suspendable] to withhold writes to its downstream [io.Writer].
|
||||
// Suspend returns false and is a noop if called between calls to Suspend and Resume.
|
||||
Suspend() bool
|
||||
|
||||
// Resume dumps the entire buffer held by the embedded [Suspendable] and stops withholding future writes.
|
||||
// Resume returns false and is a noop if a call to Suspend does not precede it.
|
||||
Resume() bool
|
||||
|
||||
// BeforeExit runs implementation-specific cleanup code, and optionally prints warnings.
|
||||
// BeforeExit is called before [os.Exit].
|
||||
BeforeExit()
|
||||
}
|
||||
|
||||
type DefaultMsg struct{ inactive atomic.Bool }
|
||||
// defaultMsg is the default implementation of the [Msg] interface.
|
||||
// The zero value is not safe for use. Callers should use the [NewMsg] function instead.
|
||||
type defaultMsg struct {
|
||||
verbose atomic.Bool
|
||||
|
||||
func (msg *DefaultMsg) IsVerbose() bool { return true }
|
||||
func (msg *DefaultMsg) Verbose(v ...any) {
|
||||
if !msg.inactive.Load() {
|
||||
log.Println(v...)
|
||||
logger *log.Logger
|
||||
Suspendable
|
||||
}
|
||||
|
||||
// NewMsg initialises a downstream [log.Logger] for a new [Msg].
|
||||
// The [log.Logger] should no longer be configured after NewMsg returns.
|
||||
// If downstream is nil, a new logger is initialised in its place.
|
||||
func NewMsg(downstream *log.Logger) Msg {
|
||||
if downstream == nil {
|
||||
downstream = log.New(log.Writer(), "container: ", 0)
|
||||
}
|
||||
|
||||
m := defaultMsg{logger: downstream}
|
||||
m.Suspendable.Downstream = downstream.Writer()
|
||||
downstream.SetOutput(&m.Suspendable)
|
||||
return &m
|
||||
}
|
||||
|
||||
func (msg *defaultMsg) GetLogger() *log.Logger { return msg.logger }
|
||||
|
||||
func (msg *defaultMsg) IsVerbose() bool { return msg.verbose.Load() }
|
||||
func (msg *defaultMsg) SwapVerbose(verbose bool) bool { return msg.verbose.Swap(verbose) }
|
||||
func (msg *defaultMsg) Verbose(v ...any) {
|
||||
if msg.verbose.Load() {
|
||||
msg.logger.Println(v...)
|
||||
}
|
||||
}
|
||||
func (msg *DefaultMsg) Verbosef(format string, v ...any) {
|
||||
if !msg.inactive.Load() {
|
||||
log.Printf(format, v...)
|
||||
func (msg *defaultMsg) Verbosef(format string, v ...any) {
|
||||
if msg.verbose.Load() {
|
||||
msg.logger.Printf(format, v...)
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *DefaultMsg) Suspend() { msg.inactive.Store(true) }
|
||||
func (msg *DefaultMsg) Resume() bool { return msg.inactive.CompareAndSwap(true, false) }
|
||||
func (msg *DefaultMsg) BeforeExit() {}
|
||||
// Resume calls [Suspendable.Resume] and prints a message if buffer was filled
|
||||
// between calls to [Suspendable.Suspend] and Resume.
|
||||
func (msg *defaultMsg) Resume() bool {
|
||||
resumed, dropped, _, err := msg.Suspendable.Resume()
|
||||
if err != nil {
|
||||
// probably going to result in an error as well, so this message is as good as unreachable
|
||||
msg.logger.Printf("cannot dump buffer on resume: %v", err)
|
||||
}
|
||||
if resumed && dropped > 0 {
|
||||
msg.logger.Printf("dropped %d bytes while output is suspended", dropped)
|
||||
}
|
||||
return resumed
|
||||
}
|
||||
|
||||
// msg is the [Msg] implemented used by all exported [container] functions.
|
||||
var msg Msg = new(DefaultMsg)
|
||||
|
||||
// GetOutput returns the current active [Msg] implementation.
|
||||
func GetOutput() Msg { return msg }
|
||||
|
||||
// SetOutput replaces the current active [Msg] implementation.
|
||||
func SetOutput(v Msg) {
|
||||
if v == nil {
|
||||
msg = new(DefaultMsg)
|
||||
} else {
|
||||
msg = v
|
||||
// BeforeExit prints a message if called between calls to [Suspendable.Suspend] and Resume.
|
||||
func (msg *defaultMsg) BeforeExit() {
|
||||
if msg.Resume() {
|
||||
msg.logger.Printf("beforeExit reached on suspended output")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
package container_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"testing"
|
||||
|
||||
"hakurei.app/container"
|
||||
"hakurei.app/container/stub"
|
||||
)
|
||||
|
||||
func TestMessageError(t *testing.T) {
|
||||
@@ -39,146 +41,137 @@ func TestMessageError(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDefaultMsg(t *testing.T) {
|
||||
{
|
||||
w := log.Writer()
|
||||
f := log.Flags()
|
||||
t.Cleanup(func() { log.SetOutput(w); log.SetFlags(f) })
|
||||
}
|
||||
msg := new(container.DefaultMsg)
|
||||
// copied from output.go
|
||||
const suspendBufMax = 1 << 24
|
||||
|
||||
t.Run("is verbose", func(t *testing.T) {
|
||||
if !msg.IsVerbose() {
|
||||
t.Error("IsVerbose unexpected outcome")
|
||||
}
|
||||
})
|
||||
t.Run("logger", func(t *testing.T) {
|
||||
t.Run("nil", func(t *testing.T) {
|
||||
got := container.NewMsg(nil).GetLogger()
|
||||
|
||||
t.Run("verbose", func(t *testing.T) {
|
||||
log.SetOutput(panicWriter{})
|
||||
msg.Suspend()
|
||||
msg.Verbose()
|
||||
msg.Verbosef("\x00")
|
||||
msg.Resume()
|
||||
|
||||
buf := new(strings.Builder)
|
||||
log.SetOutput(buf)
|
||||
log.SetFlags(0)
|
||||
msg.Verbose()
|
||||
msg.Verbosef("\x00")
|
||||
|
||||
want := "\n\x00\n"
|
||||
if buf.String() != want {
|
||||
t.Errorf("Verbose: %q, want %q", buf.String(), want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("inactive", func(t *testing.T) {
|
||||
{
|
||||
inactive := msg.Resume()
|
||||
if inactive {
|
||||
t.Cleanup(func() { msg.Suspend() })
|
||||
if out := got.Writer().(*container.Suspendable).Downstream; out != log.Writer() {
|
||||
t.Errorf("GetLogger: Downstream = %#v", out)
|
||||
}
|
||||
}
|
||||
|
||||
if msg.Resume() {
|
||||
t.Error("Resume unexpected outcome")
|
||||
}
|
||||
if prefix := got.Prefix(); prefix != "container: " {
|
||||
t.Errorf("GetLogger: prefix = %q", prefix)
|
||||
}
|
||||
})
|
||||
|
||||
msg.Suspend()
|
||||
if !msg.Resume() {
|
||||
t.Error("Resume unexpected outcome")
|
||||
}
|
||||
t.Run("takeover", func(t *testing.T) {
|
||||
l := log.New(io.Discard, "\x00", 0xdeadbeef)
|
||||
got := container.NewMsg(l)
|
||||
|
||||
if logger := got.GetLogger(); logger != l {
|
||||
t.Errorf("GetLogger: %#v, want %#v", logger, l)
|
||||
}
|
||||
|
||||
if ds := l.Writer().(*container.Suspendable).Downstream; ds != io.Discard {
|
||||
t.Errorf("GetLogger: Downstream = %#v", ds)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// the function is a noop
|
||||
t.Run("beforeExit", func(t *testing.T) { msg.BeforeExit() })
|
||||
}
|
||||
dw := expectWriter{t: t}
|
||||
|
||||
type panicWriter struct{}
|
||||
steps := []struct {
|
||||
name string
|
||||
pt, next []byte
|
||||
err error
|
||||
|
||||
func (panicWriter) Write([]byte) (int, error) { panic("unreachable") }
|
||||
f func(t *testing.T, msg container.Msg)
|
||||
}{
|
||||
{"zero verbose", nil, nil, nil, func(t *testing.T, msg container.Msg) {
|
||||
if msg.IsVerbose() {
|
||||
t.Error("IsVerbose unexpected true")
|
||||
}
|
||||
}},
|
||||
|
||||
func saveRestoreOutput(t *testing.T) {
|
||||
out := container.GetOutput()
|
||||
t.Cleanup(func() { container.SetOutput(out) })
|
||||
}
|
||||
{"swap false", nil, nil, nil, func(t *testing.T, msg container.Msg) {
|
||||
if msg.SwapVerbose(false) {
|
||||
t.Error("SwapVerbose unexpected true")
|
||||
}
|
||||
}},
|
||||
{"write discard", nil, nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.Verbose("\x00")
|
||||
msg.Verbosef("\x00")
|
||||
}},
|
||||
{"verbose false", nil, nil, nil, func(t *testing.T, msg container.Msg) {
|
||||
if msg.IsVerbose() {
|
||||
t.Error("IsVerbose unexpected true")
|
||||
}
|
||||
}},
|
||||
|
||||
func replaceOutput(t *testing.T) {
|
||||
saveRestoreOutput(t)
|
||||
container.SetOutput(&testOutput{t: t})
|
||||
}
|
||||
{"swap true", nil, nil, nil, func(t *testing.T, msg container.Msg) {
|
||||
if msg.SwapVerbose(true) {
|
||||
t.Error("SwapVerbose unexpected true")
|
||||
}
|
||||
}},
|
||||
{"write verbose", []byte("test: \x00\n"), nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.Verbose("\x00")
|
||||
}},
|
||||
{"write verbosef", []byte(`test: "\x00"` + "\n"), nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.Verbosef("%q", "\x00")
|
||||
}},
|
||||
{"verbose true", nil, nil, nil, func(t *testing.T, msg container.Msg) {
|
||||
if !msg.IsVerbose() {
|
||||
t.Error("IsVerbose unexpected false")
|
||||
}
|
||||
}},
|
||||
|
||||
type testOutput struct {
|
||||
t *testing.T
|
||||
suspended atomic.Bool
|
||||
}
|
||||
{"resume noop", nil, nil, nil, func(t *testing.T, msg container.Msg) {
|
||||
if msg.Resume() {
|
||||
t.Error("Resume unexpected success")
|
||||
}
|
||||
}},
|
||||
{"beforeExit noop", nil, nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.BeforeExit()
|
||||
}},
|
||||
|
||||
func (out *testOutput) IsVerbose() bool { return testing.Verbose() }
|
||||
{"beforeExit suspend", nil, nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.Suspend()
|
||||
}},
|
||||
{"beforeExit message", []byte("test: beforeExit reached on suspended output\n"), nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.BeforeExit()
|
||||
}},
|
||||
{"post beforeExit resume noop", nil, nil, nil, func(t *testing.T, msg container.Msg) {
|
||||
if msg.Resume() {
|
||||
t.Error("Resume unexpected success")
|
||||
}
|
||||
}},
|
||||
|
||||
func (out *testOutput) Verbose(v ...any) {
|
||||
if !out.IsVerbose() {
|
||||
return
|
||||
}
|
||||
out.t.Log(v...)
|
||||
}
|
||||
{"suspend", nil, nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.Suspend()
|
||||
}},
|
||||
{"suspend write", nil, nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.GetLogger().Print("\x00")
|
||||
}},
|
||||
{"resume error", []byte("test: \x00\n"), []byte("test: cannot dump buffer on resume: unique error 0 injected by the test suite\n"), stub.UniqueError(0), func(t *testing.T, msg container.Msg) {
|
||||
if !msg.Resume() {
|
||||
t.Error("Resume unexpected failure")
|
||||
}
|
||||
}},
|
||||
|
||||
func (out *testOutput) Verbosef(format string, v ...any) {
|
||||
if !out.IsVerbose() {
|
||||
return
|
||||
}
|
||||
out.t.Logf(format, v...)
|
||||
}
|
||||
|
||||
func (out *testOutput) Suspend() {
|
||||
if out.suspended.CompareAndSwap(false, true) {
|
||||
out.Verbose("suspend called")
|
||||
return
|
||||
}
|
||||
out.Verbose("suspend called on suspended output")
|
||||
}
|
||||
|
||||
func (out *testOutput) Resume() bool {
|
||||
if out.suspended.CompareAndSwap(true, false) {
|
||||
out.Verbose("resume called")
|
||||
return true
|
||||
}
|
||||
out.Verbose("resume called on unsuspended output")
|
||||
return false
|
||||
}
|
||||
|
||||
func (out *testOutput) BeforeExit() { out.Verbose("beforeExit called") }
|
||||
|
||||
func TestGetSetOutput(t *testing.T) {
|
||||
{
|
||||
out := container.GetOutput()
|
||||
t.Cleanup(func() { container.SetOutput(out) })
|
||||
{"suspend drop", nil, nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.Suspend()
|
||||
}},
|
||||
{"suspend write fill", nil, nil, nil, func(_ *testing.T, msg container.Msg) {
|
||||
msg.GetLogger().Print(strings.Repeat("\x00", suspendBufMax))
|
||||
}},
|
||||
{"resume dropped", append([]byte("test: "), bytes.Repeat([]byte{0}, suspendBufMax-6)...), []byte("test: dropped 7 bytes while output is suspended\n"), nil, func(t *testing.T, msg container.Msg) {
|
||||
if !msg.Resume() {
|
||||
t.Error("Resume unexpected failure")
|
||||
}
|
||||
}},
|
||||
}
|
||||
|
||||
t.Run("default", func(t *testing.T) {
|
||||
container.SetOutput(new(stubOutput))
|
||||
if v, ok := container.GetOutput().(*container.DefaultMsg); ok {
|
||||
t.Fatalf("SetOutput: got unexpected output %#v", v)
|
||||
msg := container.NewMsg(log.New(&dw, "test: ", 0))
|
||||
for _, step := range steps {
|
||||
// these share the same writer, so cannot be subtests
|
||||
t.Logf("running step %q", step.name)
|
||||
dw.expect, dw.next, dw.err = step.pt, step.next, step.err
|
||||
step.f(t, msg)
|
||||
if dw.expect != nil {
|
||||
t.Errorf("expect: %q", string(dw.expect))
|
||||
}
|
||||
container.SetOutput(nil)
|
||||
if _, ok := container.GetOutput().(*container.DefaultMsg); !ok {
|
||||
t.Fatalf("SetOutput: got unexpected output %#v", container.GetOutput())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("stub", func(t *testing.T) {
|
||||
container.SetOutput(new(stubOutput))
|
||||
if _, ok := container.GetOutput().(*stubOutput); !ok {
|
||||
t.Fatalf("SetOutput: got unexpected output %#v", container.GetOutput())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type stubOutput struct {
|
||||
wrapF func(error, ...any) error
|
||||
}
|
||||
|
||||
func (*stubOutput) IsVerbose() bool { panic("unreachable") }
|
||||
func (*stubOutput) Verbose(...any) { panic("unreachable") }
|
||||
func (*stubOutput) Verbosef(string, ...any) { panic("unreachable") }
|
||||
func (*stubOutput) Suspend() { panic("unreachable") }
|
||||
func (*stubOutput) Resume() bool { panic("unreachable") }
|
||||
func (*stubOutput) BeforeExit() { panic("unreachable") }
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestSuspendable(t *testing.T) {
|
||||
)
|
||||
|
||||
// shares the same writer
|
||||
testCases := []struct {
|
||||
steps := []struct {
|
||||
name string
|
||||
w, pt []byte
|
||||
err error
|
||||
@@ -75,25 +75,25 @@ func TestSuspendable(t *testing.T) {
|
||||
var dw expectWriter
|
||||
|
||||
w := container.Suspendable{Downstream: &dw}
|
||||
for _, tc := range testCases {
|
||||
for _, step := range steps {
|
||||
// these share the same writer, so cannot be subtests
|
||||
t.Logf("writing step %q", tc.name)
|
||||
dw.expect, dw.err = tc.pt, tc.err
|
||||
t.Logf("writing step %q", step.name)
|
||||
dw.expect, dw.err = step.pt, step.err
|
||||
|
||||
var (
|
||||
gotN int
|
||||
gotErr error
|
||||
)
|
||||
|
||||
wantN := tc.n
|
||||
wantN := step.n
|
||||
switch wantN {
|
||||
case nSpecialPtEquiv:
|
||||
wantN = len(tc.pt)
|
||||
gotN, gotErr = w.Write(tc.w)
|
||||
wantN = len(step.pt)
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
|
||||
case nSpecialWEquiv:
|
||||
wantN = len(tc.w)
|
||||
gotN, gotErr = w.Write(tc.w)
|
||||
wantN = len(step.w)
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
|
||||
case nSpecialSuspend:
|
||||
s := w.IsSuspended()
|
||||
@@ -101,8 +101,8 @@ func TestSuspendable(t *testing.T) {
|
||||
t.Fatal("Suspend: unexpected success")
|
||||
}
|
||||
|
||||
wantN = len(tc.w)
|
||||
gotN, gotErr = w.Write(tc.w)
|
||||
wantN = len(step.w)
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
|
||||
default:
|
||||
if wantN <= nSpecialDump {
|
||||
@@ -118,10 +118,10 @@ func TestSuspendable(t *testing.T) {
|
||||
t.Errorf("Resume: dropped = %d, want %d", dropped, wantDropped)
|
||||
}
|
||||
|
||||
wantN = len(tc.pt)
|
||||
wantN = len(step.pt)
|
||||
gotN, gotErr = int(n), err
|
||||
} else {
|
||||
gotN, gotErr = w.Write(tc.w)
|
||||
gotN, gotErr = w.Write(step.w)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,9 +129,13 @@ func TestSuspendable(t *testing.T) {
|
||||
t.Errorf("Write: n = %d, want %d", gotN, wantN)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(gotErr, tc.wantErr) {
|
||||
if !reflect.DeepEqual(gotErr, step.wantErr) {
|
||||
t.Errorf("Write: %v", gotErr)
|
||||
}
|
||||
|
||||
if dw.expect != nil {
|
||||
t.Errorf("expect: %q", string(dw.expect))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,17 +143,31 @@ func TestSuspendable(t *testing.T) {
|
||||
type expectWriter struct {
|
||||
expect []byte
|
||||
err error
|
||||
|
||||
// optional consecutive write
|
||||
next []byte
|
||||
|
||||
// optional, calls Error on failure if not nil
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (w *expectWriter) Write(p []byte) (n int, err error) {
|
||||
defer func() { w.expect = nil }()
|
||||
defer func() { w.expect = w.next; w.next = nil }()
|
||||
|
||||
n, err = len(p), w.err
|
||||
if w.expect == nil {
|
||||
return 0, errors.New("unexpected call to Write: " + strconv.Quote(string(p)))
|
||||
n, err = 0, errors.New("unexpected call to Write: "+strconv.Quote(string(p)))
|
||||
if w.t != nil {
|
||||
w.t.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
if string(p) != string(w.expect) {
|
||||
return 0, errors.New("p = " + strconv.Quote(string(p)) + ", want " + strconv.Quote(string(w.expect)))
|
||||
n, err = 0, errors.New("p = "+strconv.Quote(string(p))+", want "+strconv.Quote(string(w.expect)))
|
||||
if w.t != nil {
|
||||
w.t.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package container
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
@@ -22,26 +21,28 @@ const (
|
||||
kernelCapLastCapPath = FHSProcSys + "kernel/cap_last_cap"
|
||||
)
|
||||
|
||||
func mustReadSysctl() {
|
||||
if v, err := os.ReadFile(kernelOverflowuidPath); err != nil {
|
||||
log.Fatalf("cannot read %q: %v", kernelOverflowuidPath, err)
|
||||
} else if kernelOverflowuid, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
|
||||
log.Fatalf("cannot interpret %q: %v", kernelOverflowuidPath, err)
|
||||
}
|
||||
func mustReadSysctl(msg Msg) {
|
||||
sysctlOnce.Do(func() {
|
||||
if v, err := os.ReadFile(kernelOverflowuidPath); err != nil {
|
||||
msg.GetLogger().Fatalf("cannot read %q: %v", kernelOverflowuidPath, err)
|
||||
} else if kernelOverflowuid, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
|
||||
msg.GetLogger().Fatalf("cannot interpret %q: %v", kernelOverflowuidPath, err)
|
||||
}
|
||||
|
||||
if v, err := os.ReadFile(kernelOverflowgidPath); err != nil {
|
||||
log.Fatalf("cannot read %q: %v", kernelOverflowgidPath, err)
|
||||
} else if kernelOverflowgid, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
|
||||
log.Fatalf("cannot interpret %q: %v", kernelOverflowgidPath, err)
|
||||
}
|
||||
if v, err := os.ReadFile(kernelOverflowgidPath); err != nil {
|
||||
msg.GetLogger().Fatalf("cannot read %q: %v", kernelOverflowgidPath, err)
|
||||
} else if kernelOverflowgid, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
|
||||
msg.GetLogger().Fatalf("cannot interpret %q: %v", kernelOverflowgidPath, err)
|
||||
}
|
||||
|
||||
if v, err := os.ReadFile(kernelCapLastCapPath); err != nil {
|
||||
log.Fatalf("cannot read %q: %v", kernelCapLastCapPath, err)
|
||||
} else if kernelCapLastCap, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
|
||||
log.Fatalf("cannot interpret %q: %v", kernelCapLastCapPath, err)
|
||||
}
|
||||
if v, err := os.ReadFile(kernelCapLastCapPath); err != nil {
|
||||
msg.GetLogger().Fatalf("cannot read %q: %v", kernelCapLastCapPath, err)
|
||||
} else if kernelCapLastCap, err = strconv.Atoi(string(bytes.TrimSpace(v))); err != nil {
|
||||
msg.GetLogger().Fatalf("cannot interpret %q: %v", kernelCapLastCapPath, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func OverflowUid() int { sysctlOnce.Do(mustReadSysctl); return kernelOverflowuid }
|
||||
func OverflowGid() int { sysctlOnce.Do(mustReadSysctl); return kernelOverflowgid }
|
||||
func LastCap() uintptr { sysctlOnce.Do(mustReadSysctl); return uintptr(kernelCapLastCap) }
|
||||
func OverflowUid(msg Msg) int { mustReadSysctl(msg); return kernelOverflowuid }
|
||||
func OverflowGid(msg Msg) int { mustReadSysctl(msg); return kernelOverflowgid }
|
||||
func LastCap(msg Msg) uintptr { mustReadSysctl(msg); return uintptr(kernelCapLastCap) }
|
||||
|
||||
Reference in New Issue
Block a user