From 095538dd104f245cc10e7b0339b81b561c0be77a Mon Sep 17 00:00:00 2001
From: Guido van Rossum <guido@python.org>
Date: Tue, 22 Oct 1996 01:11:19 +0000
Subject: Actual text submitted by AMK.

---
 Doc/lib/librexec.tex | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 Doc/librexec.tex     | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 392 insertions(+), 2 deletions(-)

diff --git a/Doc/lib/librexec.tex b/Doc/lib/librexec.tex
index 76e63fc..32a565f 100644
--- a/Doc/lib/librexec.tex
+++ b/Doc/lib/librexec.tex
@@ -2,4 +2,199 @@
 \stmodindex{rexec}
 \renewcommand{\indexsubitem}{(in module rexec)}
 
-XXX To be provided.
+This module contains the \code{RExec} class, which supports
+\code{r_exec()}, \code{r_eval()}, \code{r_execfile()}, and
+\code{r_import()} methods, which are restricted versions of the standard
+Python functions \code{exec()}, \code{eval()}, \code{execfile()}, and
+\code{import()}.  Code executed in this restricted environment will
+only have access to modules and functions that are deemed safe; you
+can subclass \code{RExec} to add or remove capabilities as desired.
+
+\emph{Note:} The \code{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.  
+% XXX is there any protection against this?
+
+\begin{funcdesc}{RExec}{\optional{hooks\, verbose} }
+Returns an instance of the \code{RExec} class.  
+
+% XXX is ihooks.py documented?  If yes, there should be a ref here
+
+\var{hooks} is an instance of the \code{RHooks} class or a subclass of it.
+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 actual
+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.
+
+% XXX does verbose actually do anything at the moment?
+If \var{verbose} is true, additional debugging output will be sent to
+standard output.
+\end{funcdesc}
+
+RExec instances have the following attributes, which are used by the
+\code{__init__} method.  Changing them on an existing instance won't
+have any effect; instead, create a subclass of \code{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.
+
+\renewcommand{\indexsubitem}{(RExec object attribute)}
+\begin{datadesc}{nok_builtin_names}
+Contains the names of built-in functions which will \emph{not} be
+ available to programs running in the restricted environment.  The
+ value for \code{RExec} is \code{('open',} \code{reload',}
+ \code{__import__')}.
+\end{datadesc}
+
+\begin{datadesc}{ok_builtin_modules}
+Contains the names of built-in modules which can be safely imported.
+The value for \code{RExec} is \code{('array',} \code{'binascii',} \code{'audioop',}
+\code{'imageop',} \code{'marshal',} \code{'math',} \code{'md5',} \code{'parser',} \code{'regex',} \code{'rotor',}
+\code{'select',} \code{'strop',} \code{'struct',} \code{'time')}.
+\end{datadesc}
+
+\begin{datadesc}{ok_path}
+Contains the directories which will be searched when an \code{import}
+is performed in the restricted environment.  
+The value for \code{RExec} is the same as \code{sys.path} for
+unrestricted code.
+\end{datadesc}
+
+\begin{datadesc}{ok_posix_names}
+% Should this be called ok_os_names?
+Contains the names of the functions in the \code{os} module which will be
+available to programs running in the restricted environment.  The
+value for \code{RExec} is \code{('error',} \code{'fstat',}
+\code{'listdir',} \code{'lstat',} \code{'readlink',} \code{'stat',}
+\code{'times',} \code{'uname',} \code{'getpid',} \code{'getppid',}
+\code{'getcwd',} \code{'getuid',} \code{'getgid',} \code{'geteuid',}
+\code{'getegid')}.
+\end{datadesc}
+
+\begin{datadesc}{ok_sys_names}
+Contains the names of the functions and variables in the \code{sys} module which will be
+available to programs running in the restricted environment.  The
+value for \code{RExec} is \code{('ps1',} \code{'ps2',}
+\code{'copyright',} \code{'version',} \code{'platform',} \code{'exit',}
+\code{'maxint')}.
+\end{datadesc}
+
+RExec instances support the following methods:
+\renewcommand{\indexsubitem}{(RExec object method)}
+
+\begin{funcdesc}{r_eval}{code}
+\var{code} must either be a string containing a Python expression, or a compiled code object, which will
+be evaluated in the restricted environment.  The value of the expression or code object will be returned.
+\end{funcdesc}
+
+\begin{funcdesc}{r_exec}{code}
+\var{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.  
+\end{funcdesc}
+
+\begin{funcdesc}{r_execfile}{filename}
+Execute the Python code contained in the file \var{filename} in the
+restricted environment.
+\end{funcdesc}
+
+Methods whose names begin with \code{s_} are similar to the functions
+beginning with \code{r_}, but the code will be granted access to
+restricted versions of \code{sys.stdin}, \code{sys.stderr}, and
+\code{sys.stdout}.  
+
+\begin{funcdesc}{s_eval}{code}
+\var{code} must be a string containing a Python expression, which will
+be evaluated in the restricted environment.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_exec}{code}
+\var{code} must be a string containing one or more lines of Python code,
+which will be executed in the restricted environment.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_execfile}{code}
+Execute the Python code contained in the file \var{filename} in the
+restricted environment.
+\end{funcdesc}
+
+\code{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.
+
+\begin{funcdesc}{r_import}{modulename\optional{\, globals, locals, fromlist}}
+Import the module \var{modulename}, raising an \code{ImportError} exception
+if the module is considered unsafe.  
+\end{funcdesc}
+
+\begin{funcdesc}{r_open}{filename\optional{\, mode\optional{\, bufsize}}}
+Method called when \code{open()} is called in the restricted
+environment.  The arguments are identical to those of \code{open()},
+and a file object (or a class instance compatible with file objects)
+should be returned.  \code{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 \code{r_open()}.
+\end{funcdesc}
+
+\begin{funcdesc}{r_reload}{module}
+Reload the module object \var{module}, re-parsing and re-initializing it.  
+\end{funcdesc}
+
+\begin{funcdesc}{r_unload}{module}
+Unload the module object \var{module}.   
+% XXX what are the semantics of this?  
+\end{funcdesc}
+
+\begin{funcdesc}{s_import}{modulename\optional{\, globals, locals, fromlist}}
+Import the module \var{modulename}, raising an \code{ImportError} exception
+if the module is considered unsafe.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_reload}{module}
+Reload the module object \var{module}, re-parsing and re-initializing it.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_unload}{module}
+Unload the module object \var{module}.   
+% XXX what are the semantics of this?  
+\end{funcdesc}
+
+\subsection{An example}
+
+Let us say that we want a slightly more relaxed policy than the
+standard RExec class.  For example, if we're willing to allow files in
+\file{/tmp} to be written, we can subclass the \code{RExec} class:
+
+\bcode\begin{verbatim}
+class TmpWriterRExec(rexec.RExec):
+    def r_open(self, file, mode='r', buf=-1):
+        if mode in ('r', 'rb'): pass 
+	elif mode in ('w', 'wb'):
+	    # check filename : must begin with /tmp/
+	    if file[0:5]!='/tmp/': 
+		raise IOError, "can't open files for writing outside of /tmp"
+	    elif string.find(file, '/../')!=-1:
+		raise IOError, "'..' in filename; open for writing forbidden"
+        return open(file, mode, buf)
+\end{verbatim}\ecode
+
+Notice that the above code will occasionally forbid a perfectly valid
+filename; for example, code in the restricted environment won't be
+able to open a file called \file{/tmp/foo/../bar}.  To fix this, the
+\code{r_open} method would have to simplify the filename to
+\file{/tmp/bar}, which would require splitting apart the filename and
+performing various operations on it.  In cases where security is at
+stake, it may be preferable to write simple code which is sometimes
+overly restrictive, instead of more general code that is also more
+complex and may harbor a subtle security hole.
diff --git a/Doc/librexec.tex b/Doc/librexec.tex
index 76e63fc..32a565f 100644
--- a/Doc/librexec.tex
+++ b/Doc/librexec.tex
@@ -2,4 +2,199 @@
 \stmodindex{rexec}
 \renewcommand{\indexsubitem}{(in module rexec)}
 
-XXX To be provided.
+This module contains the \code{RExec} class, which supports
+\code{r_exec()}, \code{r_eval()}, \code{r_execfile()}, and
+\code{r_import()} methods, which are restricted versions of the standard
+Python functions \code{exec()}, \code{eval()}, \code{execfile()}, and
+\code{import()}.  Code executed in this restricted environment will
+only have access to modules and functions that are deemed safe; you
+can subclass \code{RExec} to add or remove capabilities as desired.
+
+\emph{Note:} The \code{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.  
+% XXX is there any protection against this?
+
+\begin{funcdesc}{RExec}{\optional{hooks\, verbose} }
+Returns an instance of the \code{RExec} class.  
+
+% XXX is ihooks.py documented?  If yes, there should be a ref here
+
+\var{hooks} is an instance of the \code{RHooks} class or a subclass of it.
+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 actual
+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.
+
+% XXX does verbose actually do anything at the moment?
+If \var{verbose} is true, additional debugging output will be sent to
+standard output.
+\end{funcdesc}
+
+RExec instances have the following attributes, which are used by the
+\code{__init__} method.  Changing them on an existing instance won't
+have any effect; instead, create a subclass of \code{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.
+
+\renewcommand{\indexsubitem}{(RExec object attribute)}
+\begin{datadesc}{nok_builtin_names}
+Contains the names of built-in functions which will \emph{not} be
+ available to programs running in the restricted environment.  The
+ value for \code{RExec} is \code{('open',} \code{reload',}
+ \code{__import__')}.
+\end{datadesc}
+
+\begin{datadesc}{ok_builtin_modules}
+Contains the names of built-in modules which can be safely imported.
+The value for \code{RExec} is \code{('array',} \code{'binascii',} \code{'audioop',}
+\code{'imageop',} \code{'marshal',} \code{'math',} \code{'md5',} \code{'parser',} \code{'regex',} \code{'rotor',}
+\code{'select',} \code{'strop',} \code{'struct',} \code{'time')}.
+\end{datadesc}
+
+\begin{datadesc}{ok_path}
+Contains the directories which will be searched when an \code{import}
+is performed in the restricted environment.  
+The value for \code{RExec} is the same as \code{sys.path} for
+unrestricted code.
+\end{datadesc}
+
+\begin{datadesc}{ok_posix_names}
+% Should this be called ok_os_names?
+Contains the names of the functions in the \code{os} module which will be
+available to programs running in the restricted environment.  The
+value for \code{RExec} is \code{('error',} \code{'fstat',}
+\code{'listdir',} \code{'lstat',} \code{'readlink',} \code{'stat',}
+\code{'times',} \code{'uname',} \code{'getpid',} \code{'getppid',}
+\code{'getcwd',} \code{'getuid',} \code{'getgid',} \code{'geteuid',}
+\code{'getegid')}.
+\end{datadesc}
+
+\begin{datadesc}{ok_sys_names}
+Contains the names of the functions and variables in the \code{sys} module which will be
+available to programs running in the restricted environment.  The
+value for \code{RExec} is \code{('ps1',} \code{'ps2',}
+\code{'copyright',} \code{'version',} \code{'platform',} \code{'exit',}
+\code{'maxint')}.
+\end{datadesc}
+
+RExec instances support the following methods:
+\renewcommand{\indexsubitem}{(RExec object method)}
+
+\begin{funcdesc}{r_eval}{code}
+\var{code} must either be a string containing a Python expression, or a compiled code object, which will
+be evaluated in the restricted environment.  The value of the expression or code object will be returned.
+\end{funcdesc}
+
+\begin{funcdesc}{r_exec}{code}
+\var{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.  
+\end{funcdesc}
+
+\begin{funcdesc}{r_execfile}{filename}
+Execute the Python code contained in the file \var{filename} in the
+restricted environment.
+\end{funcdesc}
+
+Methods whose names begin with \code{s_} are similar to the functions
+beginning with \code{r_}, but the code will be granted access to
+restricted versions of \code{sys.stdin}, \code{sys.stderr}, and
+\code{sys.stdout}.  
+
+\begin{funcdesc}{s_eval}{code}
+\var{code} must be a string containing a Python expression, which will
+be evaluated in the restricted environment.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_exec}{code}
+\var{code} must be a string containing one or more lines of Python code,
+which will be executed in the restricted environment.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_execfile}{code}
+Execute the Python code contained in the file \var{filename} in the
+restricted environment.
+\end{funcdesc}
+
+\code{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.
+
+\begin{funcdesc}{r_import}{modulename\optional{\, globals, locals, fromlist}}
+Import the module \var{modulename}, raising an \code{ImportError} exception
+if the module is considered unsafe.  
+\end{funcdesc}
+
+\begin{funcdesc}{r_open}{filename\optional{\, mode\optional{\, bufsize}}}
+Method called when \code{open()} is called in the restricted
+environment.  The arguments are identical to those of \code{open()},
+and a file object (or a class instance compatible with file objects)
+should be returned.  \code{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 \code{r_open()}.
+\end{funcdesc}
+
+\begin{funcdesc}{r_reload}{module}
+Reload the module object \var{module}, re-parsing and re-initializing it.  
+\end{funcdesc}
+
+\begin{funcdesc}{r_unload}{module}
+Unload the module object \var{module}.   
+% XXX what are the semantics of this?  
+\end{funcdesc}
+
+\begin{funcdesc}{s_import}{modulename\optional{\, globals, locals, fromlist}}
+Import the module \var{modulename}, raising an \code{ImportError} exception
+if the module is considered unsafe.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_reload}{module}
+Reload the module object \var{module}, re-parsing and re-initializing it.  
+\end{funcdesc}
+
+\begin{funcdesc}{s_unload}{module}
+Unload the module object \var{module}.   
+% XXX what are the semantics of this?  
+\end{funcdesc}
+
+\subsection{An example}
+
+Let us say that we want a slightly more relaxed policy than the
+standard RExec class.  For example, if we're willing to allow files in
+\file{/tmp} to be written, we can subclass the \code{RExec} class:
+
+\bcode\begin{verbatim}
+class TmpWriterRExec(rexec.RExec):
+    def r_open(self, file, mode='r', buf=-1):
+        if mode in ('r', 'rb'): pass 
+	elif mode in ('w', 'wb'):
+	    # check filename : must begin with /tmp/
+	    if file[0:5]!='/tmp/': 
+		raise IOError, "can't open files for writing outside of /tmp"
+	    elif string.find(file, '/../')!=-1:
+		raise IOError, "'..' in filename; open for writing forbidden"
+        return open(file, mode, buf)
+\end{verbatim}\ecode
+
+Notice that the above code will occasionally forbid a perfectly valid
+filename; for example, code in the restricted environment won't be
+able to open a file called \file{/tmp/foo/../bar}.  To fix this, the
+\code{r_open} method would have to simplify the filename to
+\file{/tmp/bar}, which would require splitting apart the filename and
+performing various operations on it.  In cases where security is at
+stake, it may be preferable to write simple code which is sometimes
+overly restrictive, instead of more general code that is also more
+complex and may harbor a subtle security hole.
-- 
cgit v0.12

