[scipy/el5] Add patch for CVE-2013-4251 (bug #1018353)

Orion Poplawski orion at fedoraproject.org
Tue Oct 15 04:12:10 UTC 2013


commit 23b903f2a3bb42a21da7faf721509a554c584cc8
Author: Orion Poplawski <orion at nwra.com>
Date:   Mon Oct 14 22:11:56 2013 -0600

    Add patch for CVE-2013-4251 (bug #1018353)

 scipy-CVE-2013-4251.patch |  294 +++++++++++++++++++++++++++++++++++++++++++++
 scipy.spec                |   13 ++-
 2 files changed, 306 insertions(+), 1 deletions(-)
---
diff --git a/scipy-CVE-2013-4251.patch b/scipy-CVE-2013-4251.patch
new file mode 100644
index 0000000..f0e012b
--- /dev/null
+++ b/scipy-CVE-2013-4251.patch
@@ -0,0 +1,294 @@
+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')
diff --git a/scipy.spec b/scipy.spec
index 95a7106..59c21f6 100644
--- a/scipy.spec
+++ b/scipy.spec
@@ -3,12 +3,13 @@
 Summary: Scipy: Scientific Tools for Python
 Name: scipy
 Version: 0.6.0
-Release: 6%{?dist}
+Release: 7%{?dist}
 
 Group: Development/Libraries
 License: BSD and LGPLv2+
 Url: http://www.scipy.org
 Source0: http://prdownloads.sourceforge.net/scipy/%{name}-%{version}.tar.gz
+Patch0: scipy-CVE-2013-4251.patch
 
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -32,6 +33,7 @@ leading scientists and engineers.
 
 %prep
 %setup -q
+%patch0 -p1 -b .CVE-2013-4251
 cat > site.cfg << EOF
 [amd]
 library_dirs = %{_libdir}
@@ -53,6 +55,12 @@ rm -rf $RPM_BUILD_ROOT
 env CFLAGS="$RPM_OPT_FLAGS" ATLAS=%{_libdir} FFTW=%{_libdir} BLAS=%{_libdir} LAPACK=%{_libdir} python setup.py install --root=$RPM_BUILD_ROOT
 
 
+%check
+mkdir test
+cd test
+PYTHONPATH=$RPM_BUILD_ROOT%{python_sitearch} python -c "import scipy; scipy.test('full')"
+
+
 %clean
 rm -rf $RPM_BUILD_ROOT
 
@@ -65,6 +73,9 @@ rm -rf $RPM_BUILD_ROOT
 
 
 %changelog
+* Mon Oct 14 2013 Orion Poplawski <orion at cora.nwra.com> -0.6.0-7
+- Add patch for CVE-2013-4251 (bug #1018353)
+
 * Wed May 7 2008 Jef Spaleta <jspaleta at fedoraproject.org> - 0.6.0-6
 - rebuild for EL-5
 


More information about the scm-commits mailing list