aboutsummaryrefslogtreecommitdiffhomepage
path: root/container
diff options
context:
space:
mode:
Diffstat (limited to 'container')
-rw-r--r--container/container.go42
-rw-r--r--container/params.go11
-rw-r--r--container/params_test.go72
3 files changed, 27 insertions, 98 deletions
diff --git a/container/container.go b/container/container.go
index 480452cd..d45d7a97 100644
--- a/container/container.go
+++ b/container/container.go
@@ -53,7 +53,7 @@ type (
ExtraFiles []*os.File
// Write end of a pipe connected to the init to deliver [Params].
- setup *os.File
+ setup [2]*os.File
// Cancels the context passed to the underlying cmd.
cancel context.CancelFunc
// Closed after Wait returns. Keeps the spawning thread alive.
@@ -287,14 +287,16 @@ func (p *Container) Start() error {
}
// place setup pipe before user supplied extra files, this is later restored by init
- if fd, f, err := Setup(&p.cmd.ExtraFiles); err != nil {
+ if r, w, err := os.Pipe(); err != nil {
return &StartError{
Fatal: true,
Step: "set up params stream",
Err: err,
}
} else {
- p.setup = f
+ fd := 3 + len(p.cmd.ExtraFiles)
+ p.cmd.ExtraFiles = append(p.cmd.ExtraFiles, r)
+ p.setup[0], p.setup[1] = r, w
p.cmd.Env = []string{setupEnv + "=" + strconv.Itoa(fd)}
}
p.cmd.ExtraFiles = append(p.cmd.ExtraFiles, p.ExtraFiles...)
@@ -428,14 +430,30 @@ func (p *Container) Start() error {
// Serve serves [Container.Params] to the container init.
//
// Serve must only be called once.
-func (p *Container) Serve() error {
- if p.setup == nil {
+func (p *Container) Serve() (err error) {
+ if p.setup[0] == nil || p.setup[1] == nil {
panic("invalid serve")
}
+ defer func() {
+ if closeErr := p.setup[1].Close(); err == nil {
+ err = closeErr
+ }
+
+ if err != nil {
+ p.cancel()
+ }
+ p.setup[0], p.setup[1] = nil, nil
+ }()
+ if err = p.setup[0].Close(); err != nil {
+ return &StartError{
+ Fatal: true,
+ Step: "close read end of init pipe",
+ Err: err,
+ Passthrough: true,
+ }
+ }
- setup := p.setup
- p.setup = nil
- if err := setup.SetDeadline(time.Now().Add(initSetupTimeout)); err != nil {
+ if err = p.setup[1].SetDeadline(time.Now().Add(initSetupTimeout)); err != nil {
return &StartError{
Fatal: true,
Step: "set init pipe deadline",
@@ -445,7 +463,6 @@ func (p *Container) Serve() error {
}
if p.Path == nil {
- p.cancel()
return &StartError{
Step: "invalid executable pathname",
Err: EINVAL,
@@ -461,18 +478,13 @@ func (p *Container) Serve() error {
p.SeccompRules = make([]std.NativeRule, 0)
}
- err := gob.NewEncoder(setup).Encode(&initParams{
+ return gob.NewEncoder(p.setup[1]).Encode(&initParams{
p.Params,
Getuid(),
Getgid(),
len(p.ExtraFiles),
p.msg.IsVerbose(),
})
- _ = setup.Close()
- if err != nil {
- p.cancel()
- }
- return err
}
// Wait blocks until the container init process to exit and releases any
diff --git a/container/params.go b/container/params.go
index 46c3b9b2..e6cd26f8 100644
--- a/container/params.go
+++ b/container/params.go
@@ -8,17 +8,6 @@ import (
"syscall"
)
-// Setup appends the read end of a pipe for setup params transmission and returns its fd.
-func Setup(extraFiles *[]*os.File) (int, *os.File, error) {
- if r, w, err := os.Pipe(); err != nil {
- return -1, nil, err
- } else {
- fd := 3 + len(*extraFiles)
- *extraFiles = append(*extraFiles, r)
- return fd, w, nil
- }
-}
-
var (
ErrReceiveEnv = errors.New("environment variable not set")
)
diff --git a/container/params_test.go b/container/params_test.go
index 11d08850..4d2f84f6 100644
--- a/container/params_test.go
+++ b/container/params_test.go
@@ -1,10 +1,8 @@
package container_test
import (
- "encoding/gob"
"errors"
"os"
- "slices"
"strconv"
"syscall"
"testing"
@@ -52,74 +50,4 @@ func TestSetupReceive(t *testing.T) {
t.Errorf("Receive: error = %v, want %v", err, syscall.EDOM)
}
})
-
- t.Run("setup receive", func(t *testing.T) {
- check := func(t *testing.T, useNilFdp bool) {
- const key = "TEST_SETUP_RECEIVE"
- payload := []uint64{syscall.MS_MGC_VAL, syscall.MS_MGC_MSK, syscall.MS_ASYNC, syscall.MS_ACTIVE}
-
- encoderDone := make(chan error, 1)
- extraFiles := make([]*os.File, 0, 1)
- deadline, _ := t.Deadline()
- if fd, f, err := container.Setup(&extraFiles); err != nil {
- t.Fatalf("Setup: error = %v", err)
- } else if fd != 3 {
- t.Fatalf("Setup: fd = %d, want 3", fd)
- } else {
- if err = f.SetDeadline(deadline); err != nil {
- t.Fatal(err.Error())
- }
- go func() { encoderDone <- gob.NewEncoder(f).Encode(payload) }()
- }
-
- if len(extraFiles) != 1 {
- t.Fatalf("extraFiles: len = %v, want 1", len(extraFiles))
- }
-
- var dupFd int
- if fd, err := syscall.Dup(int(extraFiles[0].Fd())); err != nil {
- t.Fatalf("Dup: error = %v", err)
- } else {
- syscall.CloseOnExec(fd)
- dupFd = fd
- t.Setenv(key, strconv.Itoa(fd))
- }
-
- var (
- gotPayload []uint64
- fdp *uintptr
- )
- if !useNilFdp {
- fdp = new(uintptr)
- }
- var closeFile func() error
- if f, err := container.Receive(key, &gotPayload, fdp); err != nil {
- t.Fatalf("Receive: error = %v", err)
- } else {
- closeFile = f
-
- if !slices.Equal(payload, gotPayload) {
- t.Errorf("Receive: %#v, want %#v", gotPayload, payload)
- }
- }
- if !useNilFdp {
- if int(*fdp) != dupFd {
- t.Errorf("Fd: %d, want %d", *fdp, dupFd)
- }
- }
-
- if err := <-encoderDone; err != nil {
- t.Errorf("Encode: error = %v", err)
- }
-
- if closeFile != nil {
- if err := closeFile(); err != nil {
- t.Errorf("Close: error = %v", err)
- }
- }
- }
-
- t.Run("fp", func(t *testing.T) { check(t, false) })
- t.Run("nil", func(t *testing.T) { check(t, true) })
- })
}