Commit 59b2a74c authored by Guido van Rossum's avatar Guido van Rossum

SF bug 533625 (Armin Rigo). rexec: potential security hole

If a rexec instance allows writing in the current directory (a common
thing to do), there's a way to execute bogus bytecode.  Fix this by
not allowing imports from .pyc files (in a way that allows a site to
configure things so that .pyc files *are* allowed, if writing is not
allowed).

I'll apply this to 2.2 and 2.1 too.
parent 9788384d
...@@ -211,6 +211,18 @@ environment. The value for \class{RExec} is \code{('ps1', 'ps2', ...@@ -211,6 +211,18 @@ environment. The value for \class{RExec} is \code{('ps1', 'ps2',
'copyright', 'version', 'platform', 'exit', 'maxint')}. 'copyright', 'version', 'platform', 'exit', 'maxint')}.
\end{memberdesc} \end{memberdesc}
\begin{memberdesc}{ok_file_types}
Contains the file types from which modules are allowed to be loaded.
Each file type is an integer constant defined in the \refmodule{imp} module.
The meaningful values are \constant{PY_SOURCE}, \constant{PY_COMPILED}, and
\constant{C_EXTENSION}. The value for \class{RExec} is \code{(C_EXTENSION,
PY_SOURCE)}. Adding \constant{PY_COMPILED} in subclasses is not recommended;
an attacker could exit the restricted execution mode by putting a forged
byte-compiled file (\file{.pyc}) anywhere in your file system, for example
by writing it to \file{/tmp} or uploading it to the \file{/incoming}
directory of your public FTP server.
\end{memberdesc}
\subsection{An example} \subsection{An example}
......
...@@ -22,6 +22,7 @@ import sys ...@@ -22,6 +22,7 @@ import sys
import __builtin__ import __builtin__
import os import os
import ihooks import ihooks
import imp
__all__ = ["RExec"] __all__ = ["RExec"]
...@@ -83,6 +84,9 @@ class RHooks(ihooks.Hooks): ...@@ -83,6 +84,9 @@ class RHooks(ihooks.Hooks):
# Called by RExec instance to complete initialization # Called by RExec instance to complete initialization
self.rexec = rexec self.rexec = rexec
def get_suffixes(self):
return self.rexec.get_suffixes()
def is_builtin(self, name): def is_builtin(self, name):
return self.rexec.is_builtin(name) return self.rexec.is_builtin(name)
...@@ -144,6 +148,8 @@ class RExec(ihooks._Verbose): ...@@ -144,6 +148,8 @@ class RExec(ihooks._Verbose):
nok_builtin_names = ('open', 'file', 'reload', '__import__') nok_builtin_names = ('open', 'file', 'reload', '__import__')
ok_file_types = (imp.C_EXTENSION, imp.PY_SOURCE)
def __init__(self, hooks = None, verbose = 0): def __init__(self, hooks = None, verbose = 0):
"""Returns an instance of the RExec class. """Returns an instance of the RExec class.
...@@ -203,7 +209,6 @@ class RExec(ihooks._Verbose): ...@@ -203,7 +209,6 @@ class RExec(ihooks._Verbose):
if sys.modules.has_key(name): if sys.modules.has_key(name):
src = sys.modules[name] src = sys.modules[name]
else: else:
import imp
src = imp.load_dynamic(name, filename, file) src = imp.load_dynamic(name, filename, file)
dst = self.copy_except(src, []) dst = self.copy_except(src, [])
return dst return dst
...@@ -214,6 +219,11 @@ class RExec(ihooks._Verbose): ...@@ -214,6 +219,11 @@ class RExec(ihooks._Verbose):
# Helpers for RHooks # Helpers for RHooks
def get_suffixes(self):
return [item # (suff, mode, type)
for item in imp.get_suffixes()
if item[2] in self.ok_file_types]
def is_builtin(self, mname): def is_builtin(self, mname):
return mname in self.ok_builtin_modules return mname in self.ok_builtin_modules
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment