scipy/scipy-CVE-2013-4251.patch
2013-10-14 22:11:56 -06:00

295 lines
9.9 KiB
Diff

diff -up scipy-0.6.0/scipy/weave/catalog.py.CVE-2013-4251 scipy-0.6.0/scipy/weave/catalog.py
--- scipy-0.6.0/scipy/weave/catalog.py.CVE-2013-4251 2007-09-22 01:56:36.000000000 -0600
+++ scipy-0.6.0/scipy/weave/catalog.py 2013-10-14 21:51:14.759104170 -0600
@@ -32,6 +32,7 @@
"""
import os,sys,string
+import stat
import pickle
import socket
import tempfile
@@ -140,7 +141,7 @@ def is_writable(dir):
# Do NOT use a hardcoded name here due to the danger from race conditions
# on NFS when multiple processes are accessing the same base directory in
- # parallel. We use both hostname and pocess id for the prefix in an
+ # parallel. We use both hostname and process id for the prefix in an
# attempt to ensure that there can really be no name collisions (tempfile
# appends 6 random chars to this prefix).
prefix = 'dummy_%s_%s_' % (socket.gethostname(),os.getpid())
@@ -157,6 +158,88 @@ def whoami():
"""return a string identifying the user."""
return os.environ.get("USER") or os.environ.get("USERNAME") or "unknown"
+
+def _create_dirs(path):
+ """ create provided path, ignore errors """
+ try:
+ os.makedirs(path, mode=0700)
+ except OSError:
+ pass
+
+
+def default_dir_posix(tmp_dir=None):
+ """
+ Create or find default catalog store for posix systems
+
+ purpose of 'tmp_dir' is to enable way how to test this function easily
+ """
+ path_candidates = []
+ python_name = "python%d%d_compiled" % tuple(sys.version_info[:2])
+
+ if tmp_dir:
+ home_dir = tmp_dir
+ else:
+ home_dir = os.path.expanduser('~')
+ tmp_dir = tmp_dir or tempfile.gettempdir()
+
+ home_temp_dir_name = '.' + python_name
+ home_temp_dir = os.path.join(home_dir, home_temp_dir_name)
+ path_candidates.append(home_temp_dir)
+
+ temp_dir_name = repr(os.getuid()) + '_' + python_name
+ temp_dir_path = os.path.join(tmp_dir, temp_dir_name)
+ path_candidates.append(temp_dir_path)
+
+ for path in path_candidates:
+ _create_dirs(path)
+ if check_dir(path):
+ return path
+
+ # since we got here, both dirs are not useful
+ tmp_dir_path = find_valid_temp_dir(temp_dir_name, tmp_dir)
+ if not tmp_dir_path:
+ tmp_dir_path = create_temp_dir(temp_dir_name, tmp_dir=tmp_dir)
+ return tmp_dir_path
+
+
+def default_dir_win(tmp_dir=None):
+ """
+ Create or find default catalog store for Windows systems
+
+ purpose of 'tmp_dir' is to enable way how to test this function easily
+ """
+ def create_win_temp_dir(prefix, inner_dir=None, tmp_dir=None):
+ """
+ create temp dir starting with 'prefix' in 'tmp_dir' or
+ 'tempfile.gettempdir'; if 'inner_dir' is specified, it should be
+ created inside
+ """
+ tmp_dir_path = find_valid_temp_dir(prefix, tmp_dir)
+ if tmp_dir_path:
+ if inner_dir:
+ tmp_dir_path = os.path.join(tmp_dir_path, inner_dir)
+ if not os.path.isdir(tmp_dir_path):
+ os.mkdir(tmp_dir_path, 0700)
+ else:
+ tmp_dir_path = create_temp_dir(prefix, inner_dir, tmp_dir)
+ return tmp_dir_path
+
+ python_name = "python%d%d_compiled" % tuple(sys.version_info[:2])
+ tmp_dir = tmp_dir or tempfile.gettempdir()
+
+ temp_dir_name = "%s" % whoami()
+ temp_root_dir = os.path.join(tmp_dir, temp_dir_name)
+ temp_dir_path = os.path.join(temp_root_dir, python_name)
+ _create_dirs(temp_dir_path)
+ if check_dir(temp_dir_path) and check_dir(temp_root_dir):
+ return temp_dir_path
+ else:
+ if check_dir(temp_root_dir):
+ return create_win_temp_dir(python_name, tmp_dir=temp_root_dir)
+ else:
+ return create_win_temp_dir(temp_dir_name, python_name, tmp_dir)
+
+
def default_dir():
""" Return a default location to store compiled files and catalogs.
@@ -171,36 +254,19 @@ def default_dir():
in the user's home, /tmp/<uid>_pythonXX_compiled is used. If it
doesn't exist, it is created. The directory is marked rwx------
to try and keep people from being able to sneak a bad module
- in on you.
+ in on you. If the directory already exists in /tmp/ and is not
+ secure, new one is created.
"""
-
# Use a cached value for fast return if possible
- if hasattr(default_dir,"cached_path") and \
- os.path.exists(default_dir.cached_path):
+ if hasattr(default_dir, "cached_path") and \
+ check_dir(default_dir.cached_path):
return default_dir.cached_path
- python_name = "python%d%d_compiled" % tuple(sys.version_info[:2])
- if sys.platform != 'win32':
- try:
- path = os.path.join(os.environ['HOME'],'.' + python_name)
- except KeyError:
- temp_dir = `os.getuid()` + '_' + python_name
- path = os.path.join(tempfile.gettempdir(),temp_dir)
-
- # add a subdirectory for the OS.
- # It might be better to do this at a different location so that
- # it wasn't only the default directory that gets this behavior.
- #path = os.path.join(path,sys.platform)
+ if sys.platform == 'win32':
+ path = default_dir_win()
else:
- path = os.path.join(tempfile.gettempdir(),"%s"%whoami(),python_name)
-
- if not os.path.exists(path):
- create_dir(path)
- os.chmod(path,0700) # make it only accessible by this user.
- if not is_writable(path):
- print 'warning: default directory is not write accessible.'
- print 'default:', path
+ path = default_dir_posix()
# Cache the default dir path so that this function returns quickly after
# being called once (nothing in it should change after the first call)
@@ -208,15 +274,131 @@ def default_dir():
return path
-def intermediate_dir():
- """ Location in temp dir for storing .cpp and .o files during
- builds.
- """
- python_name = "python%d%d_intermediate" % tuple(sys.version_info[:2])
- path = os.path.join(tempfile.gettempdir(),"%s"%whoami(),python_name)
- if not os.path.exists(path):
- create_dir(path)
- return path
+def check_dir(im_dir):
+ """
+ Check if dir is safe; if it is, return True.
+ These checks make sense only on posix:
+ * directory has correct owner
+ * directory has correct permissions (0700)
+ * directory is not a symlink
+ """
+ def check_is_dir():
+ return os.path.isdir(im_dir)
+
+ def check_permissions():
+ """ If on posix, permissions should be 0700. """
+ writable = is_writable(im_dir)
+ if sys.platform != 'win32':
+ try:
+ im_dir_stat = os.stat(im_dir)
+ except OSError:
+ return False
+ writable &= stat.S_IMODE(im_dir_stat.st_mode) == 00700
+ return writable
+
+ def check_ownership():
+ """ Intermediate dir owner should be same as owner of process. """
+ if sys.platform != 'win32':
+ try:
+ im_dir_stat = os.stat(im_dir)
+ except OSError:
+ return False
+ proc_uid = os.getuid()
+ return proc_uid == im_dir_stat.st_uid
+ return True
+
+ def check_is_symlink():
+ """ Check if intermediate dir is symlink. """
+ try:
+ return not os.path.islink(im_dir)
+ except OSError:
+ return False
+
+ checks = [check_is_dir, check_permissions,
+ check_ownership, check_is_symlink]
+
+ for check in checks:
+ if not check():
+ return False
+
+ return True
+
+
+def create_temp_dir(prefix, inner_dir=None, tmp_dir=None):
+ """
+ Create intermediate dirs <tmp>/<prefix+random suffix>/<inner_dir>/
+
+ argument 'tmp_dir' is used in unit tests
+ """
+ if not tmp_dir:
+ tmp_dir_path = tempfile.mkdtemp(prefix=prefix)
+ else:
+ tmp_dir_path = tempfile.mkdtemp(prefix=prefix, dir=tmp_dir)
+ if inner_dir:
+ tmp_dir_path = os.path.join(tmp_dir_path, inner_dir)
+ os.mkdir(tmp_dir_path, 0700)
+ return tmp_dir_path
+
+
+def intermediate_dir_prefix():
+ """ Prefix of root intermediate dir (<tmp>/<root_im_dir>). """
+ return "%s-%s-" % ("scipy", whoami())
+
+
+def find_temp_dir(prefix, tmp_dir=None):
+ """ Find temp dirs in 'tmp_dir' starting with 'prefix'"""
+ matches = []
+ tmp_dir = tmp_dir or tempfile.gettempdir()
+ for tmp_file in os.listdir(tmp_dir):
+ if tmp_file.startswith(prefix):
+ matches.append(os.path.join(tmp_dir, tmp_file))
+ return matches
+
+
+def find_valid_temp_dir(prefix, tmp_dir=None):
+ """
+ Try to look for existing temp dirs.
+ If there is one suitable found, return it, otherwise return None.
+ """
+ matches = find_temp_dir(prefix, tmp_dir)
+ for match in matches:
+ if check_dir(match):
+ # as soon as we find correct dir, we can stop searching
+ return match
+
+
+def py_intermediate_dir():
+ """
+ Name of intermediate dir for current python interpreter:
+ <temp dir>/<name>/pythonXY_intermediate/
+ """
+ name = "python%d%d_intermediate" % tuple(sys.version_info[:2])
+ return name
+
+
+def create_intermediate_dir(tmp_dir=None):
+ py_im_dir = py_intermediate_dir()
+ return create_temp_dir(intermediate_dir_prefix(), py_im_dir, tmp_dir)
+
+
+def intermediate_dir(tmp_dir=None):
+ """
+ Temporary directory for storing .cpp and .o files during builds.
+
+ First, try to find the dir and if it exists, verify it is safe.
+ Otherwise, create it.
+ """
+ im_dir = find_valid_temp_dir(intermediate_dir_prefix(), tmp_dir)
+ py_im_dir = py_intermediate_dir()
+ if im_dir is None:
+ py_im_dir = py_intermediate_dir()
+ im_dir = create_intermediate_dir(tmp_dir)
+ else:
+ im_dir = os.path.join(im_dir, py_im_dir)
+ if not os.path.isdir(im_dir):
+ os.mkdir(im_dir, 0700)
+ return im_dir
+
def default_temp_dir():
path = os.path.join(default_dir(),'temp')