diff options
Diffstat (limited to 'Lib/rexec.py')
-rw-r--r-- | Lib/rexec.py | 161 |
1 files changed, 160 insertions, 1 deletions
diff --git a/Lib/rexec.py b/Lib/rexec.py index 411fcc5..6dc1585a 100644 --- a/Lib/rexec.py +++ b/Lib/rexec.py @@ -114,8 +114,18 @@ RModuleImporter = ihooks.ModuleImporter class RExec(ihooks._Verbose): + """Basic restricted execution framework. - """Restricted Execution environment.""" + 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. + + 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 + processor time. + + """ ok_path = tuple(sys.path) # That's a policy decision @@ -135,6 +145,33 @@ class RExec(ihooks._Verbose): nok_builtin_names = ('open', 'file', 'reload', '__import__') def __init__(self, hooks = None, verbose = 0): + """Returns an instance of the RExec class. + + The hooks parameter 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, which can be useful when changing the mechanics of + import within the restricted environment.) + + 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 the verbose parameter is true, additional debugging output may be + sent to standard output. + + """ ihooks._Verbose.__init__(self, verbose) # XXX There's a circular reference here: self.hooks = hooks or RHooks(verbose) @@ -250,24 +287,67 @@ class RExec(ihooks._Verbose): # The r* methods are public interfaces def r_exec(self, code): + """Execute code within a restricted environment. + + The code parameter 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. + + """ m = self.add_module('__main__') exec code in m.__dict__ def r_eval(self, code): + """Evaluate code within a restricted environment. + + The code parameter 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. + + """ m = self.add_module('__main__') return eval(code, m.__dict__) def r_execfile(self, file): + """Execute the Python code in the file in the restricted + environment's __main__ module. + + """ m = self.add_module('__main__') execfile(file, m.__dict__) def r_import(self, mname, globals={}, locals={}, fromlist=[]): + """Import a module, raising an ImportError exception if the module + is considered unsafe. + + This method is implicitly called by code executing in the + restricted environment. Overriding this method in a subclass is + used to change the policies enforced by a restricted environment. + + """ return self.importer.import_module(mname, globals, locals, fromlist) def r_reload(self, m): + """Reload the module object, re-parsing and re-initializing it. + + This method is implicitly called by code executing in the + restricted environment. Overriding this method in a subclass is + used to change the policies enforced by a restricted environment. + + """ return self.importer.reload(m) def r_unload(self, m): + """Unload the module. + + Removes it from the restricted environment's sys.modules dictionary. + + This method is implicitly called by code executing in the + restricted environment. Overriding this method in a subclass is + used to change the policies enforced by a restricted environment. + + """ return self.importer.unload(m) # The s_* methods are similar but also swap std{in,out,err} @@ -325,26 +405,105 @@ class RExec(ihooks._Verbose): return r def s_exec(self, *args): + """Execute code within a restricted environment. + + Similar to the r_exec() method, but the code will be granted access + to restricted versions of the standard I/O streams sys.stdin, + sys.stderr, and sys.stdout. + + The code parameter 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. + + """ return self.s_apply(self.r_exec, args) def s_eval(self, *args): + """Evaluate code within a restricted environment. + + Similar to the r_eval() method, but the code will be granted access + to restricted versions of the standard I/O streams sys.stdin, + sys.stderr, and sys.stdout. + + The code parameter 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. return self.s_apply(self.r_eval, args) + """ + def s_execfile(self, *args): + """Execute the Python code in the file in the restricted + environment's __main__ module. + + Similar to the r_execfile() method, but the code will be granted + access to restricted versions of the standard I/O streams sys.stdin, + sys.stderr, and sys.stdout. + + """ return self.s_apply(self.r_execfile, args) def s_import(self, *args): + """Import a module, raising an ImportError exception if the module + is considered unsafe. + + This method is implicitly called by code executing in the + restricted environment. Overriding this method in a subclass is + used to change the policies enforced by a restricted environment. + + Similar to the r_import() method, but has access to restricted + versions of the standard I/O streams sys.stdin, sys.stderr, and + sys.stdout. + + """ return self.s_apply(self.r_import, args) def s_reload(self, *args): + """Reload the module object, re-parsing and re-initializing it. + + This method is implicitly called by code executing in the + restricted environment. Overriding this method in a subclass is + used to change the policies enforced by a restricted environment. + + Similar to the r_reload() method, but has access to restricted + versions of the standard I/O streams sys.stdin, sys.stderr, and + sys.stdout. + + """ return self.s_apply(self.r_reload, args) def s_unload(self, *args): + """Unload the module. + + Removes it from the restricted environment's sys.modules dictionary. + + This method is implicitly called by code executing in the + restricted environment. Overriding this method in a subclass is + used to change the policies enforced by a restricted environment. + + Similar to the r_unload() method, but has access to restricted + versions of the standard I/O streams sys.stdin, sys.stderr, and + sys.stdout. + + """ return self.s_apply(self.r_unload, args) # Restricted open(...) def r_open(self, file, mode='r', buf=-1): + """Method called when open() is called in the restricted environment. + + The arguments are identical to those of the open() function, 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. + + This method is implicitly called by code executing in the + restricted environment. Overriding this method in a subclass is + used to change the policies enforced by a restricted environment. + + """ if mode not in ('r', 'rb'): raise IOError, "can't open files for writing in restricted mode" return open(file, mode, buf) |