16.1 rexec -- Restricted execution framework
Keywords: lib

# 16.1 `rexec` -- Restricted execution framework

This module contains the `RExec` class, which supports `r_eval()`, `r_execfile()`, `r_exec()`, and `r_import()` methods, which are restricted versions of the standard Python functions `eval()`, `execfile()` and the `exec` and `import` statements. Code executed in this restricted environment will only have access to modules and functions that are deemed safe; you can subclass `RExec` to add or remove capabilities as desired.

Note: The `RExec` class can prevent code from performing unsafe operations like reading or writing disk files, or using TCP/IP sockets. However, it does not protect against code using extremely large amounts of memory or CPU time.

`RExec` ([hooks[, verbose]])
  Returns an instance of the `RExec` class.

  hooks is an instance of the `RHooks` class or a subclass of it. If it is omitted or `None`, the default `RHooks` class is instantiated. Whenever the `rexec` module searches for a module (even a built-in one) or reads a module's code, it doesn't actually go out to the file system itself. Rather, it calls methods of an `RHooks` instance that was passed to or created by its constructor. (Actually, the `RExec` object doesn't make these calls -- they are made by a module loader object that's part of the `RExec` object. This allows another level of flexibility, e.g. using packages.)

  By providing an alternate `RHooks` object, we can control the file system accesses made to import a module, without changing the actual algorithm that controls the order in which those accesses are made. For instance, we could substitute an `RHooks` object that passes all filesystem requests to a file server elsewhere, via some RPC mechanism such as ILU. Grail's applet loader uses this to support importing applets from a URL for a directory.

  If verbose is true, additional debugging output may be sent to standard output.

The `RExec` class has the following class attributes, which are used by the `__init__()` method. Changing them on an existing instance won't have any effect; instead, create a subclass of `RExec` and assign them new values in the class definition. Instances of the new class will then use those new values. All these attributes are tuples of strings.

`nok_builtin_names`
  Contains the names of built-in functions which will not be available to programs running in the restricted environment. The value for `RExec` is `('open',` `'reload',` `'__import__')`. (This gives the exceptions, because by far the majority of built-in functions are harmless. A subclass that wants to override this variable should probably start with the value from the base class and concatenate additional forbidden functions -- when new dangerous built-in functions are added to Python, they will also be added to this module.)

`ok_builtin_modules`
  Contains the names of built-in modules which can be safely imported. The value for `RExec` is `('audioop',` `'array',` `'binascii',` `'cmath',` `'errno',` `'imageop',` `'marshal',` `'math',` `'md5',` `'operator',` `'parser',` `'regex',` `'rotor',` `'select',` `'strop',` `'struct',` `'time')`. A similar remark about overriding this variable applies -- use the value from the base class as a starting point.

`ok_path`
  Contains the directories which will be searched when an `import` is performed in the restricted environment. The value for `RExec` is the same as `sys.path` (at the time the module is loaded) for unrestricted code.

`ok_posix_names`
  Contains the names of the functions in the `os` module which will be available to programs running in the restricted environment. The value for `RExec` is `('error',` `'fstat',` `'listdir',` `'lstat',` `'readlink',` `'stat',` `'times',` `'uname',` `'getpid',` `'getppid',` `'getcwd',` `'getuid',` `'getgid',` `'geteuid',` `'getegid')`.

`ok_sys_names`
  Contains the names of the functions and variables in the `sys` module which will be available to programs running in the restricted environment. The value for `RExec` is `('ps1',` `'ps2',` `'copyright',` `'version',` `'platform',` `'exit',` `'maxint')`.

`RExec` instances support the following methods:

`r_eval` (code)
  code must either be a string containing a Python expression, or a compiled code object, which will be evaluated in the restricted environment's `__main__` module. The value of the expression or code object will be returned.

`r_exec` (code)
  code must either be a string containing one or more lines of Python code, or a compiled code object, which will be executed in the restricted environment's `__main__` module.

`r_execfile` (filename)
  Execute the Python code contained in the file filename in the restricted environment's `__main__` module.

Methods whose names begin with "`s_`" are similar to the functions beginning with "`r_`", but the code will be granted access to restricted versions of the standard I/O streams `sys.stdin`, `sys.stderr`, and `sys.stdout`.

`s_eval` (code)
  code must be a string containing a Python expression, which will be evaluated in the restricted environment.

`s_exec` (code)
  code must be a string containing one or more lines of Python code, which will be executed in the restricted environment.

`s_execfile` (code)
  Execute the Python code contained in the file filename in the restricted environment.

`RExec` objects must also support various methods which will be implicitly called by code executing in the restricted environment. Overriding these methods in a subclass is used to change the policies enforced by a restricted environment.

`r_import` (modulename[, globals[, locals[, fromlist]]])
  Import the module modulename, raising an `ImportError` exception if the module is considered unsafe.

`r_open` (filename[, mode[, bufsize]])
  Method called when `open()` is called in the restricted environment. The arguments are identical to those of `open()`, and a file object (or a class instance compatible with file objects) should be returned. `RExec`'s default behaviour is allow opening any file for reading, but forbidding any attempt to write a file. See the example below for an implementation of a less restrictive `r_open()`.

`r_reload` (module)
  Reload the module object module, re-parsing and re-initializing it.

`r_unload` (module)
  Unload the module object module (i.e., remove it from the restricted environment's `sys.modules` dictionary).

And their equivalents with access to restricted standard I/O streams:

`s_import` (modulename[, globals[, locals[, fromlist]]])
  Import the module modulename, raising an `ImportError` exception if the module is considered unsafe.

`s_reload` (module)
  Reload the module object module, re-parsing and re-initializing it.

`s_unload` (module)
  Unload the module object module.

Subsections

- 16.1.1 An example