helper: implement native container backend
Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
1576fea8a3
commit
42de09e896
75
helper/container.go
Normal file
75
helper/container.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package helper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"git.gensokyo.uk/security/fortify/helper/proc"
|
||||||
|
"git.gensokyo.uk/security/fortify/internal/sandbox"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New initialises a Helper instance with wt as the null-terminated argument writer.
|
||||||
|
func New(
|
||||||
|
ctx context.Context,
|
||||||
|
name string,
|
||||||
|
wt io.WriterTo,
|
||||||
|
stat bool,
|
||||||
|
argF func(argsFd, statFd int) []string,
|
||||||
|
cmdF func(container *sandbox.Container),
|
||||||
|
extraFiles []*os.File,
|
||||||
|
) Helper {
|
||||||
|
var args []string
|
||||||
|
h := new(helperContainer)
|
||||||
|
h.helperFiles, args = newHelperFiles(ctx, wt, stat, argF, extraFiles)
|
||||||
|
h.Container = sandbox.New(ctx, name, args...)
|
||||||
|
h.WaitDelay = WaitDelay
|
||||||
|
if cmdF != nil {
|
||||||
|
cmdF(h.Container)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// helperContainer provides a [sandbox.Container] wrapper around helper ipc.
|
||||||
|
type helperContainer struct {
|
||||||
|
started bool
|
||||||
|
|
||||||
|
mu sync.Mutex
|
||||||
|
*helperFiles
|
||||||
|
*sandbox.Container
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *helperContainer) Start() error {
|
||||||
|
h.mu.Lock()
|
||||||
|
defer h.mu.Unlock()
|
||||||
|
|
||||||
|
if h.started {
|
||||||
|
return errors.New("helper: already started")
|
||||||
|
}
|
||||||
|
h.started = true
|
||||||
|
|
||||||
|
h.Env = slices.Grow(h.Env, 2)
|
||||||
|
if h.useArgsFd {
|
||||||
|
h.Env = append(h.Env, FortifyHelper+"=1")
|
||||||
|
} else {
|
||||||
|
h.Env = append(h.Env, FortifyHelper+"=0")
|
||||||
|
}
|
||||||
|
if h.useStatFd {
|
||||||
|
h.Env = append(h.Env, FortifyStatus+"=1")
|
||||||
|
|
||||||
|
// stat is populated on fulfill
|
||||||
|
h.Cancel = func() error { return h.stat.Close() }
|
||||||
|
} else {
|
||||||
|
h.Env = append(h.Env, FortifyStatus+"=0")
|
||||||
|
}
|
||||||
|
|
||||||
|
return proc.Fulfill(h.helperFiles.ctx, &h.ExtraFiles, func() error {
|
||||||
|
if err := h.Container.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return h.Container.Serve()
|
||||||
|
}, h.files, h.extraFiles)
|
||||||
|
}
|
55
helper/container_test.go
Normal file
55
helper/container_test.go
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package helper_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.gensokyo.uk/security/fortify/helper"
|
||||||
|
"git.gensokyo.uk/security/fortify/internal"
|
||||||
|
"git.gensokyo.uk/security/fortify/internal/sandbox"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestContainer(t *testing.T) {
|
||||||
|
t.Run("start empty container", func(t *testing.T) {
|
||||||
|
h := helper.New(context.Background(), "/nonexistent", argsWt, false, argF, nil, nil)
|
||||||
|
|
||||||
|
wantErr := "sandbox: starting an empty container"
|
||||||
|
if err := h.Start(); err == nil || err.Error() != wantErr {
|
||||||
|
t.Errorf("Start: error = %v, wantErr %q",
|
||||||
|
err, wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("valid new helper nil check", func(t *testing.T) {
|
||||||
|
if got := helper.New(context.TODO(), "fortify", argsWt, false, argF, nil, nil); got == nil {
|
||||||
|
t.Errorf("New(%q, %q) got nil",
|
||||||
|
argsWt, "fortify")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("implementation compliance", func(t *testing.T) {
|
||||||
|
testHelper(t, func(ctx context.Context, setOutput func(stdoutP, stderrP *io.Writer), stat bool) helper.Helper {
|
||||||
|
return helper.New(ctx, os.Args[0], argsWt, stat, argF, func(container *sandbox.Container) {
|
||||||
|
setOutput(&container.Stdout, &container.Stderr)
|
||||||
|
container.CommandContext = func(ctx context.Context) (cmd *exec.Cmd) {
|
||||||
|
return exec.CommandContext(ctx, os.Args[0], "-test.v",
|
||||||
|
"-test.run=TestHelperInit", "--", "init")
|
||||||
|
}
|
||||||
|
container.Bind("/", "/", 0)
|
||||||
|
container.Proc("/proc")
|
||||||
|
container.Dev("/dev")
|
||||||
|
}, nil)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHelperInit(t *testing.T) {
|
||||||
|
if len(os.Args) != 5 || os.Args[4] != "init" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sandbox.Init(internal.Exit)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user