diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-08-21 21:59:07 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-08-22 19:27:31 +0900 |
| commit | 09d284498109b847da0da1e2c5f883268a7f2d46 (patch) | |
| tree | 3784dee4b4e4ec97a95cb222c70d05463ae640ef /container/dispatcher.go | |
| parent | d500d6e55917e12a3f98b39cf0d29b6c96de9667 (diff) | |
container/init: wrap syscall helper functions
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>
Diffstat (limited to 'container/dispatcher.go')
| -rw-r--r-- | container/dispatcher.go | 229 |
1 files changed, 229 insertions, 0 deletions
diff --git a/container/dispatcher.go b/container/dispatcher.go new file mode 100644 index 00000000..38ed8f8e --- /dev/null +++ b/container/dispatcher.go @@ -0,0 +1,229 @@ +package container + +import ( + "io" + "io/fs" + "log" + "os" + "os/exec" + "os/signal" + "path/filepath" + "syscall" + + "hakurei.app/container/seccomp" +) + +type osFile interface { + Name() string + io.Writer + fs.File +} + +// syscallDispatcher provides methods that make state-dependent system calls as part of their behaviour. +type syscallDispatcher interface { + // setPtracer provides [SetPtracer]. + setPtracer(pid uintptr) error + // setDumpable provides [SetDumpable]. + setDumpable(dumpable uintptr) error + // setNoNewPrivs provides [SetNoNewPrivs]. + setNoNewPrivs() error + + // lastcap provides [LastCap]. + lastcap() uintptr + // capset provides capset. + capset(hdrp *capHeader, datap *[2]capData) error + // capBoundingSetDrop provides capBoundingSetDrop. + capBoundingSetDrop(cap uintptr) error + // capAmbientClearAll provides capAmbientClearAll. + capAmbientClearAll() error + // capAmbientRaise provides capAmbientRaise. + capAmbientRaise(cap uintptr) error + // isatty provides [Isatty]. + isatty(fd int) bool + // receive provides [Receive]. + receive(key string, e any, v **os.File) (closeFunc func() error, err error) + + // bindMount provides procPaths.bindMount. + bindMount(source, target string, flags uintptr, eq bool) error + // remount provides procPaths.remount. + remount(target string, flags uintptr) error + // mountTmpfs provides mountTmpfs. + mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error + // ensureFile provides ensureFile. + ensureFile(name string, perm, pperm os.FileMode) error + + // seccompLoad provides [seccomp.Load]. + seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error + // notify provides [signal.Notify]. + notify(c chan<- os.Signal, sig ...os.Signal) + // start starts [os/exec.Cmd]. + start(c *exec.Cmd) error + // signal signals the underlying process of [os/exec.Cmd]. + signal(c *exec.Cmd, sig os.Signal) error + // evalSymlinks provides [filepath.EvalSymlinks]. + evalSymlinks(path string) (string, error) + + // exit provides [os.Exit]. + exit(code int) + // getpid provides [os.Getpid]. + getpid() int + // stat provides [os.Stat]. + stat(name string) (os.FileInfo, error) + // mkdir provides [os.Mkdir]. + mkdir(name string, perm os.FileMode) error + // mkdirTemp provides [os.MkdirTemp]. + mkdirTemp(dir, pattern string) (string, error) + // mkdirAll provides [os.MkdirAll]. + mkdirAll(path string, perm os.FileMode) error + // readdir provides [os.ReadDir]. + readdir(name string) ([]os.DirEntry, error) + // writeFile provides [os.WriteFile]. + writeFile(name string, data []byte, perm os.FileMode) error + // createTemp provides [os.CreateTemp]. + createTemp(dir, pattern string) (osFile, error) + // remove provides os.Remove. + remove(name string) error + // newFile provides os.NewFile. + newFile(fd uintptr, name string) *os.File + // symlink provides os.Symlink. + symlink(oldname, newname string) error + // readlink provides [os.Readlink]. + readlink(name string) (string, error) + + // umask provides syscall.Umask. + umask(mask int) (oldmask int) + // sethostname provides syscall.Sethostname + sethostname(p []byte) (err error) + // chdir provides syscall.Chdir + chdir(path string) (err error) + // fchdir provides syscall.Fchdir + fchdir(fd int) (err error) + // open provides syscall.Open + open(path string, mode int, perm uint32) (fd int, err error) + // close provides syscall.Close + close(fd int) (err error) + // pivotRoot provides syscall.PivotRoot + pivotRoot(newroot, putold string) (err error) + // mount provides syscall.Mount + mount(source, target, fstype string, flags uintptr, data string) (err error) + // unmount provides syscall.Unmount + unmount(target string, flags int) (err error) + // 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() + // printBaseErr provides [Msg.PrintBaseErr]. + printBaseErr(err error, fallback string) +} + +// direct implements syscallDispatcher on the current kernel. +type direct struct{} + +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) 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() } +func (direct) capAmbientRaise(cap uintptr) error { return capAmbientRaise(cap) } +func (direct) isatty(fd int) bool { return Isatty(fd) } +func (direct) receive(key string, e any, v **os.File) (func() error, error) { + return Receive(key, e, v) +} + +func (direct) bindMount(source, target string, flags uintptr, eq bool) error { + return hostProc.bindMount(source, target, flags, eq) +} +func (direct) remount(target string, flags uintptr) error { + return hostProc.remount(target, flags) +} +func (direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error { + return mountTmpfs(fsname, target, flags, size, perm) +} +func (direct) ensureFile(name string, perm, pperm os.FileMode) error { + return ensureFile(name, perm, pperm) +} + +func (direct) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error { + return seccomp.Load(rules, flags) +} +func (direct) notify(c chan<- os.Signal, sig ...os.Signal) { signal.Notify(c, sig...) } +func (direct) start(c *exec.Cmd) error { return c.Start() } +func (direct) signal(c *exec.Cmd, sig os.Signal) error { return c.Process.Signal(sig) } +func (direct) evalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) } + +func (direct) exit(code int) { os.Exit(code) } +func (direct) getpid() int { return os.Getpid() } +func (direct) stat(name string) (os.FileInfo, error) { return os.Stat(name) } +func (direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) } +func (direct) mkdirTemp(dir, pattern string) (string, error) { return os.MkdirTemp(dir, pattern) } +func (direct) mkdirAll(path string, perm os.FileMode) error { return os.MkdirAll(path, perm) } +func (direct) readdir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) } +func (direct) writeFile(name string, data []byte, perm os.FileMode) error { + return os.WriteFile(name, data, perm) +} +func (direct) createTemp(dir, pattern string) (osFile, error) { + return os.CreateTemp(dir, pattern) +} +func (direct) remove(name string) error { + return os.Remove(name) +} +func (direct) newFile(fd uintptr, name string) *os.File { + return os.NewFile(fd, name) +} +func (direct) symlink(oldname, newname string) error { + return os.Symlink(oldname, newname) +} +func (direct) readlink(name string) (string, error) { + return os.Readlink(name) +} + +func (direct) umask(mask int) (oldmask int) { return syscall.Umask(mask) } +func (direct) sethostname(p []byte) (err error) { return syscall.Sethostname(p) } +func (direct) chdir(path string) (err error) { return syscall.Chdir(path) } +func (direct) fchdir(fd int) (err error) { return syscall.Fchdir(fd) } +func (direct) open(path string, mode int, perm uint32) (fd int, err error) { + return syscall.Open(path, mode, perm) +} +func (direct) close(fd int) (err error) { + return syscall.Close(fd) +} +func (direct) pivotRoot(newroot, putold string) (err error) { + return syscall.PivotRoot(newroot, putold) +} +func (direct) mount(source, target, fstype string, flags uintptr, data string) (err error) { + return syscall.Mount(source, target, fstype, flags, data) +} +func (direct) unmount(target string, flags int) (err error) { + return syscall.Unmount(target, flags) +} +func (direct) wait4(pid int, wstatus *syscall.WaitStatus, options int, rusage *syscall.Rusage) (wpid int, err error) { + 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) printBaseErr(err error, fallback string) { msg.PrintBaseErr(err, fallback) } |
