diff -u apport-2.14.1/apport/report.py apport-2.14.1/apport/report.py --- apport-2.14.1/apport/report.py +++ apport-2.14.1/apport/report.py @@ -10,7 +10,7 @@ # the full text of the license. import subprocess, tempfile, os.path, re, pwd, grp, os, time -import fnmatch, glob, traceback, errno, sys, atexit, locale +import fnmatch, glob, traceback, errno, sys, atexit, locale, imp import xml.dom, xml.dom.minidom from xml.parsers.expat import ExpatError @@ -451,22 +451,26 @@ def _python_module_path(klass, module): '''Determine path of given Python module''' - module = module.replace('/', '.') + module = module.replace('/', '.').split('.') + pathlist = sys.path - try: - m = __import__(module) - m - except: - return None + path = None + while module: + name = module.pop(0) - # chop off the first component, as it's already covered by m - submodule = module.split('.')[1:] - if submodule: - path = eval('m.%s.__file__' % '.'.join(submodule)) - else: - path = m.__file__ + try: + (fd, path, desc) = imp.find_module(name, pathlist) + except ImportError: + path = None + break + if fd: + fd.close() + pathlist = [path] - if path.endswith('.pyc'): + if not module and desc[2] == imp.PKG_DIRECTORY: + module = ['__init__'] + + if path and path.endswith('.pyc'): path = path[:-1] return path diff -u apport-2.14.1/debian/changelog apport-2.14.1/debian/changelog --- apport-2.14.1/debian/changelog +++ apport-2.14.1/debian/changelog @@ -1,3 +1,15 @@ +apport (2.14.1-0ubuntu3.17) trusty-security; urgency=medium + + * test_backend_apt_dpkg.py: Reset internal apt caches between tests. Avoids + random test failures due to leaking paths from previous test cases. + * SECURITY FIX: When determining the path of a Python module for a program + like "python -m module_name", avoid actually importing and running the + module; this could lead to local root privilege escalation. Thanks to + Gabriel Campana for discovering this and the fix! + (CVE-2015-1341, LP: #1507480) + + -- Martin Pitt Thu, 22 Oct 2015 15:15:37 +0200 + apport (2.14.1-0ubuntu3.16) trusty-proposed; urgency=medium * Add data/general-hooks/powerpc.py: Collect some PowerPC[64] information. diff -u apport-2.14.1/test/test_report.py apport-2.14.1/test/test_report.py --- apport-2.14.1/test/test_report.py +++ apport-2.14.1/test/test_report.py @@ -450,6 +450,25 @@ if restore_root: os.setresuid(0, 0, -1) + def test_check_interpreted_no_exec(self): + '''_check_interpreted() does not run module code''' + + # python script through -m, with dot separator; top-level module + pr = apport.report.Report() + pr['ExecutablePath'] = '/usr/bin/python' + pr['ProcStatus'] = 'Name:\tpython' + pr['ProcCmdline'] = 'python\0-m\0unittest.__main__' + orig_argv = sys.argv + try: + sys.argv = ['/usr/bin/python', '-m', 'unittest.__main__'] + pr._check_interpreted() + finally: + sys.argv = orig_argv + self.assertTrue(pr['ExecutablePath'].endswith('unittest/__main__.py'), + pr['ExecutablePath']) + self.assertEqual(pr['InterpreterPath'], '/usr/bin/python') + self.assertNotIn('UnreportableReason', pr) + def test_check_interpreted_twistd(self): '''_check_interpreted() for programs ran through twistd''' only in patch2: unchanged: --- apport-2.14.1.orig/test/test_backend_apt_dpkg.py +++ apport-2.14.1/test/test_backend_apt_dpkg.py @@ -34,6 +34,9 @@ # save and restore configuration file self.orig_conf = impl.configuration self.workdir = tempfile.mkdtemp() + # reset internal caches between tests + impl._apt_cache = None + impl._sandbox_apt_cache = None try: impl.get_available_version('coreutils-dbgsym')