container/init: wrap syscall helper functions
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m7s
Test / Hakurei (push) Successful in 3m8s
Test / Hpkg (push) Successful in 3m59s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 5m6s
Test / Flake checks (push) Successful in 1m26s

This allows tests to stub all kernel behaviour, enabling measurement of all function call arguments and error injection.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-08-21 21:59:07 +09:00
parent d500d6e559
commit 09d2844981
32 changed files with 2835 additions and 362 deletions

View File

@@ -3,10 +3,8 @@ package container
import (
"encoding/gob"
"fmt"
"os"
"path"
. "syscall"
"unsafe"
)
func init() { gob.Register(new(MountDevOp)) }
@@ -33,21 +31,21 @@ type MountDevOp struct {
Write bool
}
func (d *MountDevOp) Valid() bool { return d != nil && d.Target != nil }
func (d *MountDevOp) early(*setupState) error { return nil }
func (d *MountDevOp) apply(state *setupState) error {
func (d *MountDevOp) Valid() bool { return d != nil && d.Target != nil }
func (d *MountDevOp) early(*setupState, syscallDispatcher) error { return nil }
func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
target := toSysroot(d.Target.String())
if err := mountTmpfs(SourceTmpfsDevtmpfs, target, MS_NOSUID|MS_NODEV, 0, state.ParentPerm); err != nil {
if err := k.mountTmpfs(SourceTmpfsDevtmpfs, target, MS_NOSUID|MS_NODEV, 0, state.ParentPerm); err != nil {
return err
}
for _, name := range []string{"null", "zero", "full", "random", "urandom", "tty"} {
targetPath := path.Join(target, name)
if err := ensureFile(targetPath, 0444, state.ParentPerm); err != nil {
if err := k.ensureFile(targetPath, 0444, state.ParentPerm); err != nil {
return err
}
if err := hostProc.bindMount(
if err := k.bindMount(
toHost(FHSDev+name),
targetPath,
0,
@@ -57,7 +55,7 @@ func (d *MountDevOp) apply(state *setupState) error {
}
}
for i, name := range []string{"stdin", "stdout", "stderr"} {
if err := os.Symlink(
if err := k.symlink(
FHSProc+"self/fd/"+string(rune(i+'0')),
path.Join(target, name),
); err != nil {
@@ -69,34 +67,33 @@ func (d *MountDevOp) apply(state *setupState) error {
{FHSProc + "kcore", "core"},
{"pts/ptmx", "ptmx"},
} {
if err := os.Symlink(pair[0], path.Join(target, pair[1])); err != nil {
if err := k.symlink(pair[0], path.Join(target, pair[1])); err != nil {
return wrapErrSelf(err)
}
}
devPtsPath := path.Join(target, "pts")
for _, name := range []string{path.Join(target, "shm"), devPtsPath} {
if err := os.Mkdir(name, state.ParentPerm); err != nil {
if err := k.mkdir(name, state.ParentPerm); err != nil {
return wrapErrSelf(err)
}
}
if err := Mount(SourceDevpts, devPtsPath, FstypeDevpts, MS_NOSUID|MS_NOEXEC,
if err := k.mount(SourceDevpts, devPtsPath, FstypeDevpts, MS_NOSUID|MS_NOEXEC,
"newinstance,ptmxmode=0666,mode=620"); err != nil {
return wrapErrSuffix(err,
fmt.Sprintf("cannot mount devpts on %q:", devPtsPath))
}
if state.RetainSession {
var buf [8]byte
if _, _, errno := Syscall(SYS_IOCTL, 1, TIOCGWINSZ, uintptr(unsafe.Pointer(&buf[0]))); errno == 0 {
if k.isatty(Stdout) {
consolePath := path.Join(target, "console")
if err := ensureFile(consolePath, 0444, state.ParentPerm); err != nil {
if err := k.ensureFile(consolePath, 0444, state.ParentPerm); err != nil {
return err
}
if name, err := os.Readlink(hostProc.stdout()); err != nil {
if name, err := k.readlink(hostProc.stdout()); err != nil {
return wrapErrSelf(err)
} else if err = hostProc.bindMount(
} else if err = k.bindMount(
toHost(name),
consolePath,
0,
@@ -109,10 +106,10 @@ func (d *MountDevOp) apply(state *setupState) error {
if d.Mqueue {
mqueueTarget := path.Join(target, "mqueue")
if err := os.Mkdir(mqueueTarget, state.ParentPerm); err != nil {
if err := k.mkdir(mqueueTarget, state.ParentPerm); err != nil {
return wrapErrSelf(err)
}
if err := Mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil {
if err := k.mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil {
return wrapErrSuffix(err, "cannot mount mqueue:")
}
}
@@ -120,7 +117,7 @@ func (d *MountDevOp) apply(state *setupState) error {
if d.Write {
return nil
}
return wrapErrSuffix(hostProc.remount(target, MS_RDONLY),
return wrapErrSuffix(k.remount(target, MS_RDONLY),
fmt.Sprintf("cannot remount %q:", target))
}