[tor-commits] [meek/master] Be more careful about terminating meek-client.

dcf at torproject.org dcf at torproject.org
Tue Apr 30 21:09:07 UTC 2019


commit adf41cd3adf6e3884626b6b7e4c7f131660343dd
Author: David Fifield <david at bamsoftware.com>
Date:   Sat Feb 23 02:23:05 2019 -0700

    Be more careful about terminating meek-client.
    
    First close its stdin and send SIGTERM; and then kill it if that doesn't
    work. Set TOR_PT_EXIT_ON_STDIN_EOF=1 unconditionally in the subprocess.
    On Windows it's the same, except don't send SIGTERM.
    
    https://bugs.torproject.org/15125
    https://bugs.torproject.org/25613
---
 meek-client-torbrowser/meek-client-torbrowser.go | 27 ++++++++++++++-----
 meek-client-torbrowser/terminate_other.go        | 33 ++++++++++++++++++++++++
 meek-client-torbrowser/terminate_windows.go      | 30 +++++++++++++++++++++
 3 files changed, 84 insertions(+), 6 deletions(-)

diff --git a/meek-client-torbrowser/meek-client-torbrowser.go b/meek-client-torbrowser/meek-client-torbrowser.go
index ce79193..0f295ff 100644
--- a/meek-client-torbrowser/meek-client-torbrowser.go
+++ b/meek-client-torbrowser/meek-client-torbrowser.go
@@ -35,16 +35,27 @@ import (
 	"regexp"
 	"strings"
 	"syscall"
+	"time"
 )
 
 // This magic string is emitted by meek-http-helper.
 var helperAddrPattern = regexp.MustCompile(`^meek-http-helper: listen (127\.0\.0\.1:\d+)$`)
 
+// How long to wait for child processes to exit gracefully before killing them.
+const terminateTimeout = 2 * time.Second
+
 func usage() {
 	fmt.Fprintf(os.Stderr, "Usage: %s [meek-client-torbrowser args] -- meek-client [meek-client args]\n", os.Args[0])
 	flag.PrintDefaults()
 }
 
+// ptCmd is a *exec.Cmd augmented with an io.WriteCloser for its stdin, which we
+// can close to instruct the PT subprocess to terminate.
+type ptCmd struct {
+	*exec.Cmd
+	StdinCloser io.WriteCloser
+}
+
 // Log a call to os.Process.Kill.
 func logKill(p *os.Process) error {
 	log.Printf("killing PID %d", p.Pid)
@@ -293,14 +304,16 @@ func grepHelperAddr(r io.Reader) (string, error) {
 }
 
 // Run meek-client and return its exec.Cmd.
-func runMeekClient(helperAddr string, meekClientCommandLine []string) (cmd *exec.Cmd, err error) {
+func runMeekClient(helperAddr string, meekClientCommandLine []string) (cmd *ptCmd, err error) {
 	meekClientPath := meekClientCommandLine[0]
 	args := meekClientCommandLine[1:]
 	args = append(args, []string{"--helper", helperAddr}...)
-	cmd = exec.Command(meekClientPath, args...)
+	cmd = new(ptCmd)
+	cmd.Cmd = exec.Command(meekClientPath, args...)
 	// Give the subprocess a stdin for TOR_PT_EXIT_ON_STDIN_CLOSE purposes.
 	// https://bugs.torproject.org/24642
-	_, err = cmd.StdinPipe()
+	cmd.Env = append(os.Environ(), "TOR_PT_EXIT_ON_STDIN_CLOSE=1")
+	cmd.StdinCloser, err = cmd.StdinPipe()
 	if err != nil {
 		return
 	}
@@ -320,7 +333,7 @@ func runMeekClient(helperAddr string, meekClientCommandLine []string) (cmd *exec
 // may have failed to start. If a process did not start, its corresponding
 // return value will be nil. The caller is responsible for terminating whatever
 // processes were started, whether or not err is nil.
-func startProcesses(sigChan <-chan os.Signal, meekClientCommandLine []string) (firefoxCmd *exec.Cmd, meekClientCmd *exec.Cmd, err error) {
+func startProcesses(sigChan <-chan os.Signal, meekClientCommandLine []string) (firefoxCmd *exec.Cmd, meekClientCmd *ptCmd, err error) {
 	// Start firefox.
 	var stdout io.Reader
 	firefoxCmd, stdout, err = runFirefox()
@@ -414,7 +427,6 @@ func main() {
 		// we are instructed to stop.
 		sig := <-sigChan
 		log.Printf("sig %s", sig)
-		logSignal(meekClientCmd.Process, sig)
 	} else {
 		// Otherwise don't wait, go ahead and terminate whatever
 		// processes were started.
@@ -425,6 +437,9 @@ func main() {
 		logKill(firefoxCmd.Process)
 	}
 	if meekClientCmd != nil {
-		logKill(firefoxCmd.Process)
+		err := terminatePTCmd(meekClientCmd)
+		if err != nil {
+			log.Printf("error terminating meek-client: %v", err)
+		}
 	}
 }
diff --git a/meek-client-torbrowser/terminate_other.go b/meek-client-torbrowser/terminate_other.go
new file mode 100644
index 0000000..d38e27b
--- /dev/null
+++ b/meek-client-torbrowser/terminate_other.go
@@ -0,0 +1,33 @@
+// +build !windows
+
+// Process termination code for platforms that have SIGTERM (i.e., not Windows).
+
+package main
+
+import (
+	"syscall"
+	"time"
+)
+
+// Terminate a PT subprocess: first close its stdin and send it SIGTERM; then
+// kill it if that doesn't work.
+func terminatePTCmd(cmd *ptCmd) error {
+	err := cmd.StdinCloser.Close()
+	err2 := cmd.Process.Signal(syscall.SIGTERM)
+	if err == nil {
+		err = err2
+	}
+	ch := make(chan error, 1)
+	go func() {
+		ch <- cmd.Wait()
+	}()
+	select {
+	case <-time.After(terminateTimeout):
+		err2 = cmd.Process.Kill()
+	case err2 = <-ch:
+	}
+	if err == nil {
+		err = err2
+	}
+	return err
+}
diff --git a/meek-client-torbrowser/terminate_windows.go b/meek-client-torbrowser/terminate_windows.go
new file mode 100644
index 0000000..c00c44f
--- /dev/null
+++ b/meek-client-torbrowser/terminate_windows.go
@@ -0,0 +1,30 @@
+// +build windows
+
+// Process termination code for platforms that don't have SIGTERM (i.e.,
+// Windows).
+
+package main
+
+import (
+	"time"
+)
+
+// Terminate a PT subprocess: first close its stdin; then kill it if that
+// doesn't work.
+func terminatePTCmd(cmd *ptCmd) error {
+	err := cmd.StdinCloser.Close()
+	ch := make(chan error, 1)
+	go func() {
+		ch <- cmd.Wait()
+	}()
+	var err2 error
+	select {
+	case <-time.After(terminateTimeout):
+		err2 = cmd.Process.Kill()
+	case err2 = <-ch:
+	}
+	if err == nil {
+		err = err2
+	}
+	return err
+}





More information about the tor-commits mailing list