def test_restricted_path_function_allowed(self): fake_function = self.mox.CreateMockAnything() fake_function('foo', bar='baz').AndReturn(1) stubs.FakeFile.is_file_accessible('foo').AndReturn(True) self.mox.ReplayAll() restricted_path_fake_function = stubs.RestrictedPathFunction(fake_function) self.assertEqual(1, restricted_path_fake_function('foo', bar='baz')) self.mox.VerifyAll()
def _install_open_hooks(): """Install open hooks for sandbox.""" if _open_hooks: for install_open_hook in _open_hooks: install_open_hook() # Assume installed open hooks don't enforce the sandbox path restrictions # and install a final hook to do that (the goal of hooks is to allow # alternate open techniques, not to circumvent the sandbox). It does mean # that open requests that make it to FakeFile have their path checked # twice but that doesn't break anything. __builtin__.open = stubs.RestrictedPathFunction(__builtin__.open, IOError)
def test_restricted_path_function_not_allowed(self): fake_function = self.mox.CreateMockAnything() stubs.FakeFile.is_file_accessible('foo').AndReturn(False) self.mox.ReplayAll() restricted_path_fake_function = stubs.RestrictedPathFunction(fake_function) with self.assertRaises(OSError) as cm: restricted_path_fake_function('foo', bar='baz') self.mox.VerifyAll() e = cm.exception self.assertEqual(errno.EACCES, e.errno) self.assertEqual('path not accessible', e.strerror) self.assertEqual('foo', e.filename)
del module_dict[symbol] _MODULE_OVERRIDE_POLICIES = { 'os': ModuleOverridePolicy( default_stub=stubs.os_error_not_implemented, whitelist=[ 'altsep', 'curdir', 'defpath', 'devnull', 'environ', 'error', 'fstat', 'getcwd', 'getcwdu', 'getenv', '_get_exports_list', 'name', 'open', 'pardir', 'path', 'pathsep', 'sep', 'stat_float_times', 'stat_result', 'strerror', 'sys', 'walk' ], overrides={ 'access': stubs.fake_access, 'listdir': stubs.RestrictedPathFunction(os.listdir), # Alias lstat() to stat() to match the behavior in production. 'lstat': stubs.RestrictedPathFunction(os.stat), 'open': stubs.fake_open, 'stat': stubs.RestrictedPathFunction(os.stat), 'uname': stubs.fake_uname, 'getpid': stubs.return_minus_one, 'getppid': stubs.return_minus_one, 'getpgrp': stubs.return_minus_one, 'getgid': stubs.return_minus_one, 'getegid': stubs.return_minus_one, 'geteuid': stubs.return_minus_one, 'getuid': stubs.return_minus_one, 'urandom': stubs.fake_urandom, 'system': stubs.return_minus_one, },
def enable_sandbox(config): """Enable the sandbox based on the configuration. This includes installing import hooks to restrict access to C modules and stub out functions that are not implemented in production, replacing the file builtins with read-only versions and add enabled libraries to the path. Args: config: The runtime_config_pb2.Config to use to configure the sandbox. """ devnull = open(os.path.devnull) modules = [os, traceback, google] c_module = _find_shared_object_c_module() if c_module: modules.append(c_module) module_paths = [module.__file__ for module in modules] module_paths.extend([os.path.realpath(module.__file__) for module in modules]) python_lib_paths = [config.application_root] for path in sys.path: if any(module_path.startswith(path) for module_path in module_paths): python_lib_paths.append(path) python_lib_paths.extend(_enable_libraries(config.libraries)) for name in list(sys.modules): if not _should_keep_module(name): _removed_modules.append(sys.modules[name]) del sys.modules[name] path_override_hook = PathOverrideImportHook( set(_THIRD_PARTY_LIBRARY_NAME_OVERRIDES.get(lib.name, lib.name) for lib in config.libraries).intersection(_C_MODULES)) python_lib_paths.extend(path_override_hook.extra_sys_paths) stubs.FakeFile.set_allowed_paths(config.application_root, python_lib_paths[1:] + path_override_hook.extra_accessible_paths) stubs.FakeFile.set_skip_files(config.skip_files) stubs.FakeFile.set_static_files(config.static_files) __builtin__.file = stubs.FakeFile __builtin__.open = stubs.FakeFile types.FileType = stubs.FakeFile if _open_hooks: for install_open_hook in _open_hooks: install_open_hook() # Assume installed open hooks don't enforce the sandbox path restrictions # and install a final hook to do that (the goal of hooks is to allow # alternate open techniques, not to circumvent the sandbox). It does mean # that open requests that make it to FakeFile have their path checked # twice but that doesn't break anything. __builtin__.open = stubs.RestrictedPathFunction(__builtin__.open, IOError) sys.platform = 'linux3' enabled_library_regexes = [ NAME_TO_CMODULE_WHITELIST_REGEX[lib.name] for lib in config.libraries if lib.name in NAME_TO_CMODULE_WHITELIST_REGEX] sys.meta_path = [ StubModuleImportHook(), ModuleOverrideImportHook(_MODULE_OVERRIDE_POLICIES), CModuleImportHook(enabled_library_regexes), path_override_hook, PyCryptoRandomImportHook, PathRestrictingImportHook(enabled_library_regexes) ] sys.path_importer_cache = {} sys.path = python_lib_paths[:] thread = __import__('thread') __import__('%s.threading' % dist27.__name__) threading = sys.modules['%s.threading' % dist27.__name__] thread.start_new_thread = _make_request_id_aware_start_new_thread( thread.start_new_thread) # This import needs to be after enabling the sandbox so it imports the # sandboxed version of the logging module. from google.appengine.runtime import runtime runtime.PatchStartNewThread(thread) threading._start_new_thread = thread.start_new_thread os.chdir(config.application_root) sandboxed_os = __import__('os') request_environment.PatchOsEnviron(sandboxed_os) os.__dict__.update(sandboxed_os.__dict__) _init_logging(config.stderr_log_level) pdb_sandbox.install(config) sys.stdin = devnull sys.stdout = sys.stderr