commit 7bb33aba93ad767c13be9776bb0e90eeb771db4f Author: Yawning Angel yawning@schwanenlied.me Date: Mon Nov 28 02:03:34 2016 +0000
Handle bubblewrap crashing/exiting mid-setup. --- .../internal/sandbox/hugbox.go | 103 ++++++++++++++------- 1 file changed, 70 insertions(+), 33 deletions(-)
diff --git a/src/cmd/sandboxed-tor-browser/internal/sandbox/hugbox.go b/src/cmd/sandboxed-tor-browser/internal/sandbox/hugbox.go index 8ecafa1..6f7528e 100644 --- a/src/cmd/sandboxed-tor-browser/internal/sandbox/hugbox.go +++ b/src/cmd/sandboxed-tor-browser/internal/sandbox/hugbox.go @@ -28,6 +28,7 @@ import ( "strconv" "strings" "syscall" + "time"
"cmd/sandboxed-tor-browser/internal/data" . "cmd/sandboxed-tor-browser/internal/utils" @@ -283,47 +284,83 @@ func (h *hugbox) run() (*exec.Cmd, error) { // Fork/exec. cmd.Start()
- // Flush the pending writes. - for i, wrFd := range pendingWriteFds { - d := pendingWrites[i] - if err := writeBuffer(wrFd, d); err != nil { - cmd.Process.Kill() - return nil, err + // Do the rest of the setup in a go routine, and monitor completion and + // a watchdog timer. + doneCh := make(chan error) + bwrapPid := cmd.Process.Pid + hz := time.NewTicker(1 * time.Second) + defer hz.Stop() + + go func() { + // Flush the pending writes. + for i, wrFd := range pendingWriteFds { + d := pendingWrites[i] + if err := writeBuffer(wrFd, d); err != nil { + doneCh <- err + return + } + cmd.ExtraFiles = cmd.ExtraFiles[1:] } - cmd.ExtraFiles = cmd.ExtraFiles[1:] - }
- // Write the seccomp rules. - if h.seccompFn != nil { - // This should be the one and only remaining extra file. - if len(cmd.ExtraFiles) != 2 { - panic("sandbox: unexpected extra files when writing seccomp rules") - } else if seccompWrFd == nil { - panic("sandbox: missing fd when writing seccomp rules") + // Write the seccomp rules. + if h.seccompFn != nil { + // This should be the one and only remaining extra file. + if len(cmd.ExtraFiles) != 2 { + panic("sandbox: unexpected extra files when writing seccomp rules") + } else if seccompWrFd == nil { + panic("sandbox: missing fd when writing seccomp rules") + } + if err := h.seccompFn(seccompWrFd); err != nil { + doneCh <- err + return + } + cmd.ExtraFiles = cmd.ExtraFiles[1:] + } else if seccompWrFd != nil { + panic("sandbox: seccomp fd exists when there are no rules to be written") } - if err := h.seccompFn(seccompWrFd); err != nil { - cmd.Process.Kill() - return nil, err + + // Read back the child pid. + decoder := json.NewDecoder(infoRdFd) + info := &bwrapInfo{} + if err := decoder.Decode(info); err != nil { + doneCh <- err + return } - cmd.ExtraFiles = cmd.ExtraFiles[1:] - } else if seccompWrFd != nil { - panic("sandbox: seccomp fd exists when there are no rules to be written") - }
- // Read back the child pid. - decoder := json.NewDecoder(infoRdFd) - info := &bwrapInfo{} - if err := decoder.Decode(info); err != nil { - return nil, err - } + Debugf("sandbox: bwrap pid is: %v", cmd.Process.Pid) + Debugf("sandbox: child pid is: %v", info.Pid)
- Debugf("sandbox: bwrap pid is: %v", cmd.Process.Pid) - Debugf("sandbox: child pid is: %v", info.Pid) + // This is more useful to us, since it's fork of bubblewrap that will + // execvp. + cmd.Process.Pid = info.Pid + + doneCh <- nil + }()
- // This is more useful to us. - cmd.Process.Pid = info.Pid + err := fmt.Errorf("sandbox: timeout waiting for bubblewrap to start") +timeoutLoop: + for nTicks := 0; nTicks < 10; { // 10 second timeout, probably excessive. + select { + case err = <-doneCh: + if err == nil { + return cmd, nil + } + break timeoutLoop + case <-hz.C: + var wstatus syscall.WaitStatus + _, err = syscall.Wait4(bwrapPid, &wstatus, syscall.WNOHANG, nil) + if err != nil { + break timeoutLoop + } else if wstatus.Exited() { + err = fmt.Errorf("sandbox: bubblewrap exited unexpectedly") + break timeoutLoop + } + nTicks++ + } + }
- return cmd, nil + cmd.Process.Kill() + return nil, err }
type bwrapInfo struct {