Browse Source

torrc: Allow the user to disable the tor Sandbox

* Set the default for Sandbox based on the platform:
  1 for Linux, 0 for everything else.
* Allow the user to override it with --sandbox or CHUTNEY_TOR_SANDBOX

This feature can be used when tor's sandbox doesn't work with the local
glibc version.

Closes ticket 32721.
teor 4 years ago
parent
commit
f21ca5534f
4 changed files with 94 additions and 20 deletions
  1. 17 2
      README
  2. 56 12
      lib/chutney/TorNet.py
  3. 9 0
      tools/test-network.sh
  4. 12 6
      torrc_templates/common.i

+ 17 - 2
README

@@ -70,6 +70,10 @@ Address/DNS Options:
   # Use tor's compile-time default for ServerDNSResolvConfFile
   --dns-conf-default CHUTNEY_DNS_CONF=""
 
+Sandbox Options:
+
+  --sandbox          CHUTNEY_TOR_SANDBOX=N (0 or 1)
+
 Warning Options:
   --all-warnings     CHUTNEY_WARNINGS_IGNORE_EXPECTED=false
                      CHUTNEY_WARNINGS_SUMMARY=false
@@ -214,15 +218,26 @@ Using DNS:
    provides a local resolv.conf file containing IPv4, IPv6, and "localhost".
    Use --dns-conf resolv.conf (relative paths work).
 
+The tor sandbox:
+
+   Chutney can run with the tor seccomp sandbox enabled. But if tor's sandbox
+   is broken on your local version of glibc, you can set CHUTNEY_TOR_SANDBOX=0
+   to disable the sandbox. If CHUTNEY_TOR_SANDBOX is unset, Sandbox defaults
+   to 1 on Linux, and 0 on other platforms.
+
 The configuration files:
 
   networks/basic holds the configuration for the network you're configuring
   above.  It refers to some torrc template files in torrc_templates/.
 
+  Chutney uses a templating system to produce torrc files from the templates.
+  These torrc files can be modified using various chutney options.
+
 The working files:
 
-  chutney sticks its working files, including all data directories, log
-  files, etc, in ./net/.  Each tor instance gets a subdirectory of net/nodes.
+  chutney sticks its working files, including all generated torrc files,
+  data directories, log files, etc, in ./net/.  Each tor instance gets a
+  subdirectory of net/nodes.
 
   You can override the directory "./net" with the CHUTNEY_DATA_DIR
   environment variable.

+ 56 - 12
lib/chutney/TorNet.py

@@ -11,15 +11,16 @@ from __future__ import print_function
 from __future__ import with_statement
 
 import cgitb
+import errno
+import importlib
 import os
+import platform
+import re
 import signal
+import shutil
 import subprocess
 import sys
-import re
-import errno
 import time
-import shutil
-import importlib
 
 from chutney.Debug import debug_flag, debug
 
@@ -42,22 +43,55 @@ cgitb.enable(format="plain")
 class MissingBinaryException(Exception):
     pass
 
-def getenv_int(envvar, default):
+def getenv_type(env_var, default, type_, type_name=None):
     """
-       Return the value of the environment variable 'envar' as an integer,
+       Return the value of the environment variable 'envar' as type_,
        or 'default' if no such variable exists.
 
-       Raise ValueError if the environment variable is set, but not to
-       an integer.
+       Raise ValueError using type_name if the environment variable is set,
+       but type_() raises a ValueError on its value. (If type_name is None
+       or empty, the ValueError uses type_'s string representation instead.)
     """
-    # TODO: Use this function in more places.
-    strval = os.environ.get(envvar)
+    strval = os.environ.get(env_var)
     if strval is None:
         return default
     try:
-        return int(strval)
+        return type_(strval)
+    except ValueError:
+        if not type_name:
+            type_name = str(type_)
+        raise ValueError(("Invalid value for environment variable '{}': "
+                          "expected {}, but got '{}'")
+                         .format(env_var, typename, strval))
+
+def getenv_int(env_var, default):
+    """
+       Return the value of the environment variable 'envar' as an int,
+       or 'default' if no such variable exists.
+
+       Raise ValueError if the environment variable is set, but is not an int.
+    """
+    return getenv_type(env_var, default, int, type_name='an int')
+
+def getenv_bool(env_var, default):
+    """
+       Return the value of the environment variable 'envar' as a bool,
+       or 'default' if no such variable exists.
+
+       Unlike bool(), converts 0, "False", and "No" to False.
+
+       Raise ValueError if the environment variable is set, but is not a bool.
+    """
+    try:
+        # Handle integer values
+        return bool(getenv_int(env_var, default))
     except ValueError:
-        raise ValueError("Invalid value for environment variable %s: expected an integer, but got %r"%(envvar,strval))
+        # Handle values that the user probably expects to be False
+        strval = os.environ.get(env_var)
+        if strval.lower() in ['false', 'no']:
+            return False
+        else:
+            return getenv_type(env_var, default, bool, type_name='a bool')
 
 def mkdir_p(d, mode=448):
     """Create directory 'd' and all of its parents as needed.  Unlike
@@ -1032,6 +1066,11 @@ DEFAULTS = {
 
     'CUR_CONFIG_PHASE': getenv_int('CHUTNEY_CONFIG_PHASE', 1),
     'CUR_LAUNCH_PHASE': getenv_int('CHUTNEY_LAUNCH_PHASE', 1),
+
+    # the Sandbox torrc option value
+    # defaults to 1 on Linux, and 0 otherwise
+    'sandbox': int(getenv_bool('CHUTNEY_TOR_SANDBOX',
+                               platform.system() == 'Linux')),
 }
 
 
@@ -1055,6 +1094,11 @@ class TorEnviron(chutney.Templating.Environ):
              disabled if tor should use the default DNS conf.
              If the dns_conf file is missing, this option is also disabled:
              otherwise, exits would not work due to tor bug #21900.
+          sandbox: Sets Sandbox to the value of CHUTNEY_TOR_SANDBOX.
+             The default is 1 on Linux, and 0 on other platforms.
+             Chutney users can disable the sandbox using:
+                export CHUTNEY_TOR_SANDBOX=0
+             if it doesn't work on their version of glibc.
 
        Environment fields used:
           nodenum: chutney's internal node number for the node

+ 9 - 0
tools/test-network.sh

@@ -22,6 +22,10 @@ export CHUTNEY_ALLOW_FAILURES=${CHUTNEY_ALLOW_FAILURES:-0}
 # If a custom test expects DNS, it needs to set CHUTNEY_DNS_CONF
 export CHUTNEY_DNS_CONF=${CHUTNEY_DNS_CONF:-/dev/null}
 
+# Chutney changes the sandbox default, based on the platform. It's set to 1 on
+# Linux, which is the only tor platform with a supported sandbox.
+#export CHUTNEY_TOR_SANDBOX=1
+
 # what we say when we fail
 UPDATE_YOUR_CHUTNEY="Please update your chutney using 'git pull'."
 
@@ -131,6 +135,11 @@ do
         --dns-conf-default)
             export CHUTNEY_DNS_CONF=""
             ;;
+        # Enable or disable tor's sandbox, overriding the default
+        --sandbox)
+            export CHUTNEY_TOR_SANDBOX="$2"
+            shift
+            ;;
         # Warning Options
         # we summarise unexpected warnings by default
         # this shows all warnings per-node

+ 12 - 6
torrc_templates/common.i

@@ -23,8 +23,6 @@ TestingMinExitFlagThreshold 0
 #Default VoteOnHidServDirectoriesV2 1
 
 ## Options that we always want to test ##
-Sandbox 1
-
 DataDirectory $dir
 RunAsDaemon 1
 ConnLimit $connlimit
@@ -38,10 +36,6 @@ ControlPort $controlport
 ControlSocket ${dir}/control
 CookieAuthentication 1
 PidFile ${dir}/pid
-# Ask all child tor processes to exit when chutney's test-network.sh exits
-# (if the CHUTNEY_*_TIME options leave the network running, this option is
-# disabled)
-${owning_controller_process}
 
 Log notice file ${dir}/notice.log
 Log info file ${dir}/info.log
@@ -51,4 +45,16 @@ ProtocolWarnings 1
 SafeLogging 0
 LogTimeGranularity 1
 
+# Options that we can disable at runtime, based on env vars
+
+# Use tor's sandbox. Defaults to 1 on Linux, and 0 on other platforms.
+# Use CHUTNEY_TOR_SANDBOX=0 to disable, if tor's sandbox doesn't work with
+# your glibc.
+Sandbox ${sandbox}
+
+# Ask all child tor processes to exit when chutney's test-network.sh exits
+# (if the CHUTNEY_*_TIME options leave the network running, this option is
+# disabled)
+${owning_controller_process}
+
 ${authorities}