Bug 1258619 - Properly sandbox functions inside a template. r=chmanchester
authorMike Hommey <mh+mozilla@glandium.org>
Tue, 22 Mar 2016 15:31:37 +0900
changeset 289982 bbfbdaa25c6cc26f122a4eafbe84c61d381682d8
parent 289981 9056b43dc7b12acb9a1bf9178561f28b3ffccf51
child 289983 6fd69516a3213ec6bf4c3e57b82faa40201bb6f1
push id18337
push usercbook@mozilla.com
push dateWed, 23 Mar 2016 15:30:25 +0000
treeherderfx-team@67ac681f7e53 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerschmanchester
bugs1258619
milestone48.0a1
Bug 1258619 - Properly sandbox functions inside a template. r=chmanchester The way functions are being sandboxed in moz.configure land is that their global namespace is being replaced with a limited and identifiable dict. And we avoid re-wrapping a function that already received this treatment. The problem is that template functions have their global namespace replaced, and any function that is defined within the template inherits that global namespace. So when it comes time to wrap those functions defined in templates with e.g. depends, we detect that they're already wrapped although they are not, because we look if their global namespace is of the recognizable type we use when replacing it. So instead of looking at the global namespace type, keep track of all functions that are wrapped.
build/moz.configure/init.configure
python/mozbuild/mozbuild/configure/__init__.py
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -234,19 +234,19 @@ def command_line_helper():
     # it is a one off and because the required functionality doesn't need
     # to be exposed for other usecases.
     return depends.__self__._helper
 
 
 # All options defined above this point can't be injected in mozconfig_options
 # below, so collect them.
 @template
-@advanced
 def early_options():
     @depends('--help')
+    @advanced
     def early_options(help):
         return set(
             option.env
             for option in depends.__self__._options.itervalues()
             if option.env
         )
     return early_options
 
--- a/python/mozbuild/mozbuild/configure/__init__.py
+++ b/python/mozbuild/mozbuild/configure/__init__.py
@@ -128,16 +128,19 @@ class ConfigureSandbox(dict):
         # - raw option (as per command line or environment) for each value
         self._db = {}
 
         # Store options added with `imply_option`, and the reason they were
         # added (which can either have been given to `imply_option`, or
         # infered.
         self._implied_options = {}
 
+        # Store all results from _prepare_function
+        self._prepared_functions = set()
+
         self._helper = CommandLineHelper(environ, argv)
 
         self._config, self._stdout, self._stderr = config, stdout, stderr
 
         self._help = None
         self._help_option = self.option_impl('--help',
                                              help='print this message')
         self._seen.add(self._help_option)
@@ -420,25 +423,26 @@ class ConfigureSandbox(dict):
         return func
 
     def _prepare_function(self, func):
         '''Alter the given function global namespace with the common ground
         for @depends, @template and @advanced.
         '''
         if not inspect.isfunction(func):
             raise TypeError("Unexpected type: '%s'" % type(func))
-        if isinstance(func.func_globals, SandboxedGlobal):
+        if func in self._prepared_functions:
             return func, func.func_globals
 
         glob = SandboxedGlobal(func.func_globals)
         glob.update(
             __builtins__=self.BUILTINS,
             __file__=self._paths[-1],
             os=self.OS,
         )
         func = wraps(func)(types.FunctionType(
             func.func_code,
             glob,
             func.__name__,
             func.func_defaults,
             func.func_closure
         ))
+        self._prepared_functions.add(func)
         return func, glob