aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--cmd/sharefs/fuse.go17
-rw-r--r--container/container.go42
-rw-r--r--container/params.go11
-rw-r--r--container/params_test.go72
-rw-r--r--internal/outcome/process.go22
5 files changed, 50 insertions, 114 deletions
diff --git a/cmd/sharefs/fuse.go b/cmd/sharefs/fuse.go
index 1dc34e21..c9855eb7 100644
--- a/cmd/sharefs/fuse.go
+++ b/cmd/sharefs/fuse.go
@@ -19,7 +19,6 @@ import (
"encoding/gob"
"errors"
"fmt"
- "io"
"log"
"os"
"os/exec"
@@ -470,13 +469,14 @@ func _main(s ...string) (exitCode int) {
os.NewFile(uintptr(C.fuse_session_fd(se)), "fuse"),
))
- var setupWriter io.WriteCloser
- if fd, w, err := container.Setup(&z.ExtraFiles); err != nil {
+ var setupPipe [2]*os.File
+ if r, w, err := os.Pipe(); err != nil {
log.Println(err)
return 5
} else {
- z.Args = append(z.Args, "-osetup="+strconv.Itoa(fd))
- setupWriter = w
+ z.Args = append(z.Args, "-osetup="+strconv.Itoa(3+len(z.ExtraFiles)))
+ z.ExtraFiles = append(z.ExtraFiles, r)
+ setupPipe[0], setupPipe[1] = r, w
}
if err := z.Start(); err != nil {
@@ -487,6 +487,9 @@ func _main(s ...string) (exitCode int) {
}
return 5
}
+ if err := setupPipe[0].Close(); err != nil {
+ log.Println(err)
+ }
if err := z.Serve(); err != nil {
if m, ok := message.GetMessage(err); ok {
log.Println(m)
@@ -496,10 +499,10 @@ func _main(s ...string) (exitCode int) {
return 5
}
- if err := gob.NewEncoder(setupWriter).Encode(&setup); err != nil {
+ if err := gob.NewEncoder(setupPipe[1]).Encode(&setup); err != nil {
log.Println(err)
return 5
- } else if err = setupWriter.Close(); err != nil {
+ } else if err = setupPipe[1].Close(); err != nil {
log.Println(err)
}
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) })
- })
}
diff --git a/internal/outcome/process.go b/internal/outcome/process.go
index 9b8fc537..44a62463 100644
--- a/internal/outcome/process.go
+++ b/internal/outcome/process.go
@@ -13,7 +13,6 @@ import (
"time"
"hakurei.app/check"
- "hakurei.app/container"
"hakurei.app/fhs"
"hakurei.app/hst"
"hakurei.app/internal/info"
@@ -372,17 +371,18 @@ func (k *outcome) start(ctx context.Context, msg message.Msg,
// shim runs in the same session as monitor; see shim.go for behaviour
cmd.Cancel = func() error { return cmd.Process.Signal(syscall.SIGCONT) }
- var shimPipe *os.File
- if fd, w, err := container.Setup(&cmd.ExtraFiles); err != nil {
+ var shimPipe [2]*os.File
+ if r, w, err := os.Pipe(); err != nil {
return cmd, nil, &hst.AppError{Step: "create shim setup pipe", Err: err}
} else {
- shimPipe = w
cmd.Env = []string{
// passed through to shim by hsu
- shimEnv + "=" + strconv.Itoa(fd),
+ shimEnv + "=" + strconv.Itoa(3+len(cmd.ExtraFiles)),
// interpreted by hsu
"HAKUREI_IDENTITY=" + k.state.identity.String(),
}
+ cmd.ExtraFiles = append(cmd.ExtraFiles, r)
+ shimPipe[0], shimPipe[1] = r, w
}
if len(k.supp) > 0 {
@@ -393,12 +393,16 @@ func (k *outcome) start(ctx context.Context, msg message.Msg,
msg.Verbosef("setuid helper at %s", hsuPath)
if err := cmd.Start(); err != nil {
+ _, _ = shimPipe[0].Close(), shimPipe[1].Close()
msg.Resume()
- return cmd, shimPipe, &hst.AppError{Step: "start setuid wrapper", Err: err}
+ return cmd, nil, &hst.AppError{Step: "start setuid wrapper", Err: err}
+ }
+ if err := shimPipe[0].Close(); err != nil {
+ msg.Verbose(err)
}
*startTime = time.Now().UTC()
- return cmd, shimPipe, nil
+ return cmd, shimPipe[1], nil
}
// serveShim serves outcomeState through the shim setup pipe.
@@ -411,11 +415,11 @@ func serveShim(msg message.Msg, shimPipe *os.File, state *outcomeState) error {
msg.Verbose(err.Error())
}
if err := gob.NewEncoder(shimPipe).Encode(state); err != nil {
+ _ = shimPipe.Close()
msg.Resume()
return &hst.AppError{Step: "transmit shim config", Err: err}
}
- _ = shimPipe.Close()
- return nil
+ return shimPipe.Close()
}
// printMessageError prints the error message according to [message.GetMessage],