| 1 | \section{\module{rexec} ---
|
|---|
| 2 | Restricted execution framework}
|
|---|
| 3 |
|
|---|
| 4 | \declaremodule{standard}{rexec}
|
|---|
| 5 | \modulesynopsis{Basic restricted execution framework.}
|
|---|
| 6 | \versionchanged[Disabled module]{2.3}
|
|---|
| 7 |
|
|---|
| 8 | \begin{notice}[warning]
|
|---|
| 9 | The documentation has been left in place to help in reading old code
|
|---|
| 10 | that uses the module.
|
|---|
| 11 | \end{notice}
|
|---|
| 12 |
|
|---|
| 13 | This module contains the \class{RExec} class, which supports
|
|---|
| 14 | \method{r_eval()}, \method{r_execfile()}, \method{r_exec()}, and
|
|---|
| 15 | \method{r_import()} methods, which are restricted versions of the standard
|
|---|
| 16 | Python functions \method{eval()}, \method{execfile()} and
|
|---|
| 17 | the \keyword{exec} and \keyword{import} statements.
|
|---|
| 18 | Code executed in this restricted environment will
|
|---|
| 19 | only have access to modules and functions that are deemed safe; you
|
|---|
| 20 | can subclass \class{RExec} to add or remove capabilities as desired.
|
|---|
| 21 |
|
|---|
| 22 | \begin{notice}[warning]
|
|---|
| 23 | While the \module{rexec} module is designed to perform as described
|
|---|
| 24 | below, it does have a few known vulnerabilities which could be
|
|---|
| 25 | exploited by carefully written code. Thus it should not be relied
|
|---|
| 26 | upon in situations requiring ``production ready'' security. In such
|
|---|
| 27 | situations, execution via sub-processes or very careful
|
|---|
| 28 | ``cleansing'' of both code and data to be processed may be
|
|---|
| 29 | necessary. Alternatively, help in patching known \module{rexec}
|
|---|
| 30 | vulnerabilities would be welcomed.
|
|---|
| 31 | \end{notice}
|
|---|
| 32 |
|
|---|
| 33 | \begin{notice}
|
|---|
| 34 | The \class{RExec} class can prevent code from performing unsafe
|
|---|
| 35 | operations like reading or writing disk files, or using TCP/IP
|
|---|
| 36 | sockets. However, it does not protect against code using extremely
|
|---|
| 37 | large amounts of memory or processor time.
|
|---|
| 38 | \end{notice}
|
|---|
| 39 |
|
|---|
| 40 | \begin{classdesc}{RExec}{\optional{hooks\optional{, verbose}}}
|
|---|
| 41 | Returns an instance of the \class{RExec} class.
|
|---|
| 42 |
|
|---|
| 43 | \var{hooks} is an instance of the \class{RHooks} class or a subclass of it.
|
|---|
| 44 | If it is omitted or \code{None}, the default \class{RHooks} class is
|
|---|
| 45 | instantiated.
|
|---|
| 46 | Whenever the \module{rexec} module searches for a module (even a
|
|---|
| 47 | built-in one) or reads a module's code, it doesn't actually go out to
|
|---|
| 48 | the file system itself. Rather, it calls methods of an \class{RHooks}
|
|---|
| 49 | instance that was passed to or created by its constructor. (Actually,
|
|---|
| 50 | the \class{RExec} object doesn't make these calls --- they are made by
|
|---|
| 51 | a module loader object that's part of the \class{RExec} object. This
|
|---|
| 52 | allows another level of flexibility, which can be useful when changing
|
|---|
| 53 | the mechanics of \keyword{import} within the restricted environment.)
|
|---|
| 54 |
|
|---|
| 55 | By providing an alternate \class{RHooks} object, we can control the
|
|---|
| 56 | file system accesses made to import a module, without changing the
|
|---|
| 57 | actual algorithm that controls the order in which those accesses are
|
|---|
| 58 | made. For instance, we could substitute an \class{RHooks} object that
|
|---|
| 59 | passes all filesystem requests to a file server elsewhere, via some
|
|---|
| 60 | RPC mechanism such as ILU. Grail's applet loader uses this to support
|
|---|
| 61 | importing applets from a URL for a directory.
|
|---|
| 62 |
|
|---|
| 63 | If \var{verbose} is true, additional debugging output may be sent to
|
|---|
| 64 | standard output.
|
|---|
| 65 | \end{classdesc}
|
|---|
| 66 |
|
|---|
| 67 | It is important to be aware that code running in a restricted
|
|---|
| 68 | environment can still call the \function{sys.exit()} function. To
|
|---|
| 69 | disallow restricted code from exiting the interpreter, always protect
|
|---|
| 70 | calls that cause restricted code to run with a
|
|---|
| 71 | \keyword{try}/\keyword{except} statement that catches the
|
|---|
| 72 | \exception{SystemExit} exception. Removing the \function{sys.exit()}
|
|---|
| 73 | function from the restricted environment is not sufficient --- the
|
|---|
| 74 | restricted code could still use \code{raise SystemExit}. Removing
|
|---|
| 75 | \exception{SystemExit} is not a reasonable option; some library code
|
|---|
| 76 | makes use of this and would break were it not available.
|
|---|
| 77 |
|
|---|
| 78 |
|
|---|
| 79 | \begin{seealso}
|
|---|
| 80 | \seetitle[http://grail.sourceforge.net/]{Grail Home Page}{Grail is a
|
|---|
| 81 | Web browser written entirely in Python. It uses the
|
|---|
| 82 | \module{rexec} module as a foundation for supporting
|
|---|
| 83 | Python applets, and can be used as an example usage of
|
|---|
| 84 | this module.}
|
|---|
| 85 | \end{seealso}
|
|---|
| 86 |
|
|---|
| 87 |
|
|---|
| 88 | \subsection{RExec Objects \label{rexec-objects}}
|
|---|
| 89 |
|
|---|
| 90 | \class{RExec} instances support the following methods:
|
|---|
| 91 |
|
|---|
| 92 | \begin{methoddesc}{r_eval}{code}
|
|---|
| 93 | \var{code} must either be a string containing a Python expression, or
|
|---|
| 94 | a compiled code object, which will be evaluated in the restricted
|
|---|
| 95 | environment's \module{__main__} module. The value of the expression or
|
|---|
| 96 | code object will be returned.
|
|---|
| 97 | \end{methoddesc}
|
|---|
| 98 |
|
|---|
| 99 | \begin{methoddesc}{r_exec}{code}
|
|---|
| 100 | \var{code} must either be a string containing one or more lines of
|
|---|
| 101 | Python code, or a compiled code object, which will be executed in the
|
|---|
| 102 | restricted environment's \module{__main__} module.
|
|---|
| 103 | \end{methoddesc}
|
|---|
| 104 |
|
|---|
| 105 | \begin{methoddesc}{r_execfile}{filename}
|
|---|
| 106 | Execute the Python code contained in the file \var{filename} in the
|
|---|
| 107 | restricted environment's \module{__main__} module.
|
|---|
| 108 | \end{methoddesc}
|
|---|
| 109 |
|
|---|
| 110 | Methods whose names begin with \samp{s_} are similar to the functions
|
|---|
| 111 | beginning with \samp{r_}, but the code will be granted access to
|
|---|
| 112 | restricted versions of the standard I/O streams \code{sys.stdin},
|
|---|
| 113 | \code{sys.stderr}, and \code{sys.stdout}.
|
|---|
| 114 |
|
|---|
| 115 | \begin{methoddesc}{s_eval}{code}
|
|---|
| 116 | \var{code} must be a string containing a Python expression, which will
|
|---|
| 117 | be evaluated in the restricted environment.
|
|---|
| 118 | \end{methoddesc}
|
|---|
| 119 |
|
|---|
| 120 | \begin{methoddesc}{s_exec}{code}
|
|---|
| 121 | \var{code} must be a string containing one or more lines of Python code,
|
|---|
| 122 | which will be executed in the restricted environment.
|
|---|
| 123 | \end{methoddesc}
|
|---|
| 124 |
|
|---|
| 125 | \begin{methoddesc}{s_execfile}{code}
|
|---|
| 126 | Execute the Python code contained in the file \var{filename} in the
|
|---|
| 127 | restricted environment.
|
|---|
| 128 | \end{methoddesc}
|
|---|
| 129 |
|
|---|
| 130 | \class{RExec} objects must also support various methods which will be
|
|---|
| 131 | implicitly called by code executing in the restricted environment.
|
|---|
| 132 | Overriding these methods in a subclass is used to change the policies
|
|---|
| 133 | enforced by a restricted environment.
|
|---|
| 134 |
|
|---|
| 135 | \begin{methoddesc}{r_import}{modulename\optional{, globals\optional{,
|
|---|
| 136 | locals\optional{, fromlist}}}}
|
|---|
| 137 | Import the module \var{modulename}, raising an \exception{ImportError}
|
|---|
| 138 | exception if the module is considered unsafe.
|
|---|
| 139 | \end{methoddesc}
|
|---|
| 140 |
|
|---|
| 141 | \begin{methoddesc}{r_open}{filename\optional{, mode\optional{, bufsize}}}
|
|---|
| 142 | Method called when \function{open()} is called in the restricted
|
|---|
| 143 | environment. The arguments are identical to those of \function{open()},
|
|---|
| 144 | and a file object (or a class instance compatible with file objects)
|
|---|
| 145 | should be returned. \class{RExec}'s default behaviour is allow opening
|
|---|
| 146 | any file for reading, but forbidding any attempt to write a file. See
|
|---|
| 147 | the example below for an implementation of a less restrictive
|
|---|
| 148 | \method{r_open()}.
|
|---|
| 149 | \end{methoddesc}
|
|---|
| 150 |
|
|---|
| 151 | \begin{methoddesc}{r_reload}{module}
|
|---|
| 152 | Reload the module object \var{module}, re-parsing and re-initializing it.
|
|---|
| 153 | \end{methoddesc}
|
|---|
| 154 |
|
|---|
| 155 | \begin{methoddesc}{r_unload}{module}
|
|---|
| 156 | Unload the module object \var{module} (remove it from the
|
|---|
| 157 | restricted environment's \code{sys.modules} dictionary).
|
|---|
| 158 | \end{methoddesc}
|
|---|
| 159 |
|
|---|
| 160 | And their equivalents with access to restricted standard I/O streams:
|
|---|
| 161 |
|
|---|
| 162 | \begin{methoddesc}{s_import}{modulename\optional{, globals\optional{,
|
|---|
| 163 | locals\optional{, fromlist}}}}
|
|---|
| 164 | Import the module \var{modulename}, raising an \exception{ImportError}
|
|---|
| 165 | exception if the module is considered unsafe.
|
|---|
| 166 | \end{methoddesc}
|
|---|
| 167 |
|
|---|
| 168 | \begin{methoddesc}{s_reload}{module}
|
|---|
| 169 | Reload the module object \var{module}, re-parsing and re-initializing it.
|
|---|
| 170 | \end{methoddesc}
|
|---|
| 171 |
|
|---|
| 172 | \begin{methoddesc}{s_unload}{module}
|
|---|
| 173 | Unload the module object \var{module}.
|
|---|
| 174 | % XXX what are the semantics of this?
|
|---|
| 175 | \end{methoddesc}
|
|---|
| 176 |
|
|---|
| 177 |
|
|---|
| 178 | \subsection{Defining restricted environments \label{rexec-extension}}
|
|---|
| 179 |
|
|---|
| 180 | The \class{RExec} class has the following class attributes, which are
|
|---|
| 181 | used by the \method{__init__()} method. Changing them on an existing
|
|---|
| 182 | instance won't have any effect; instead, create a subclass of
|
|---|
| 183 | \class{RExec} and assign them new values in the class definition.
|
|---|
| 184 | Instances of the new class will then use those new values. All these
|
|---|
| 185 | attributes are tuples of strings.
|
|---|
| 186 |
|
|---|
| 187 | \begin{memberdesc}{nok_builtin_names}
|
|---|
| 188 | Contains the names of built-in functions which will \emph{not} be
|
|---|
| 189 | available to programs running in the restricted environment. The
|
|---|
| 190 | value for \class{RExec} is \code{('open', 'reload', '__import__')}.
|
|---|
| 191 | (This gives the exceptions, because by far the majority of built-in
|
|---|
| 192 | functions are harmless. A subclass that wants to override this
|
|---|
| 193 | variable should probably start with the value from the base class and
|
|---|
| 194 | concatenate additional forbidden functions --- when new dangerous
|
|---|
| 195 | built-in functions are added to Python, they will also be added to
|
|---|
| 196 | this module.)
|
|---|
| 197 | \end{memberdesc}
|
|---|
| 198 |
|
|---|
| 199 | \begin{memberdesc}{ok_builtin_modules}
|
|---|
| 200 | Contains the names of built-in modules which can be safely imported.
|
|---|
| 201 | The value for \class{RExec} is \code{('audioop', 'array', 'binascii',
|
|---|
| 202 | 'cmath', 'errno', 'imageop', 'marshal', 'math', 'md5', 'operator',
|
|---|
| 203 | 'parser', 'regex', 'select', 'sha', '_sre', 'strop',
|
|---|
| 204 | 'struct', 'time')}. A similar remark about overriding this variable
|
|---|
| 205 | applies --- use the value from the base class as a starting point.
|
|---|
| 206 | \end{memberdesc}
|
|---|
| 207 |
|
|---|
| 208 | \begin{memberdesc}{ok_path}
|
|---|
| 209 | Contains the directories which will be searched when an \keyword{import}
|
|---|
| 210 | is performed in the restricted environment.
|
|---|
| 211 | The value for \class{RExec} is the same as \code{sys.path} (at the time
|
|---|
| 212 | the module is loaded) for unrestricted code.
|
|---|
| 213 | \end{memberdesc}
|
|---|
| 214 |
|
|---|
| 215 | \begin{memberdesc}{ok_posix_names}
|
|---|
| 216 | % Should this be called ok_os_names?
|
|---|
| 217 | Contains the names of the functions in the \refmodule{os} module which will be
|
|---|
| 218 | available to programs running in the restricted environment. The
|
|---|
| 219 | value for \class{RExec} is \code{('error', 'fstat', 'listdir',
|
|---|
| 220 | 'lstat', 'readlink', 'stat', 'times', 'uname', 'getpid', 'getppid',
|
|---|
| 221 | 'getcwd', 'getuid', 'getgid', 'geteuid', 'getegid')}.
|
|---|
| 222 | \end{memberdesc}
|
|---|
| 223 |
|
|---|
| 224 | \begin{memberdesc}{ok_sys_names}
|
|---|
| 225 | Contains the names of the functions and variables in the \refmodule{sys}
|
|---|
| 226 | module which will be available to programs running in the restricted
|
|---|
| 227 | environment. The value for \class{RExec} is \code{('ps1', 'ps2',
|
|---|
| 228 | 'copyright', 'version', 'platform', 'exit', 'maxint')}.
|
|---|
| 229 | \end{memberdesc}
|
|---|
| 230 |
|
|---|
| 231 | \begin{memberdesc}{ok_file_types}
|
|---|
| 232 | Contains the file types from which modules are allowed to be loaded.
|
|---|
| 233 | Each file type is an integer constant defined in the \refmodule{imp} module.
|
|---|
| 234 | The meaningful values are \constant{PY_SOURCE}, \constant{PY_COMPILED}, and
|
|---|
| 235 | \constant{C_EXTENSION}. The value for \class{RExec} is \code{(C_EXTENSION,
|
|---|
| 236 | PY_SOURCE)}. Adding \constant{PY_COMPILED} in subclasses is not recommended;
|
|---|
| 237 | an attacker could exit the restricted execution mode by putting a forged
|
|---|
| 238 | byte-compiled file (\file{.pyc}) anywhere in your file system, for example
|
|---|
| 239 | by writing it to \file{/tmp} or uploading it to the \file{/incoming}
|
|---|
| 240 | directory of your public FTP server.
|
|---|
| 241 | \end{memberdesc}
|
|---|
| 242 |
|
|---|
| 243 |
|
|---|
| 244 | \subsection{An example}
|
|---|
| 245 |
|
|---|
| 246 | Let us say that we want a slightly more relaxed policy than the
|
|---|
| 247 | standard \class{RExec} class. For example, if we're willing to allow
|
|---|
| 248 | files in \file{/tmp} to be written, we can subclass the \class{RExec}
|
|---|
| 249 | class:
|
|---|
| 250 |
|
|---|
| 251 | \begin{verbatim}
|
|---|
| 252 | class TmpWriterRExec(rexec.RExec):
|
|---|
| 253 | def r_open(self, file, mode='r', buf=-1):
|
|---|
| 254 | if mode in ('r', 'rb'):
|
|---|
| 255 | pass
|
|---|
| 256 | elif mode in ('w', 'wb', 'a', 'ab'):
|
|---|
| 257 | # check filename : must begin with /tmp/
|
|---|
| 258 | if file[:5]!='/tmp/':
|
|---|
| 259 | raise IOError, "can't write outside /tmp"
|
|---|
| 260 | elif (string.find(file, '/../') >= 0 or
|
|---|
| 261 | file[:3] == '../' or file[-3:] == '/..'):
|
|---|
| 262 | raise IOError, "'..' in filename forbidden"
|
|---|
| 263 | else: raise IOError, "Illegal open() mode"
|
|---|
| 264 | return open(file, mode, buf)
|
|---|
| 265 | \end{verbatim}
|
|---|
| 266 | %
|
|---|
| 267 | Notice that the above code will occasionally forbid a perfectly valid
|
|---|
| 268 | filename; for example, code in the restricted environment won't be
|
|---|
| 269 | able to open a file called \file{/tmp/foo/../bar}. To fix this, the
|
|---|
| 270 | \method{r_open()} method would have to simplify the filename to
|
|---|
| 271 | \file{/tmp/bar}, which would require splitting apart the filename and
|
|---|
| 272 | performing various operations on it. In cases where security is at
|
|---|
| 273 | stake, it may be preferable to write simple code which is sometimes
|
|---|
| 274 | overly restrictive, instead of more general code that is also more
|
|---|
| 275 | complex and may harbor a subtle security hole.
|
|---|