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 @@ -836,8 +836,9 @@ hook_dirs = [_hook_dir] # also search hooks in /opt, when program is from there opt_path = None - if self.get('ExecutablePath', '').startswith(_opt_dir): - opt_path = self.get('ExecutablePath', '') + exec_path = os.path.realpath(self.get('ExecutablePath', '')) + if exec_path.startswith(_opt_dir): + opt_path = exec_path elif package: # check package contents try: diff -u apport-2.14.1/debian/apport.install apport-2.14.1/debian/apport.install --- apport-2.14.1/debian/apport.install +++ apport-2.14.1/debian/apport.install @@ -17,7 +17,6 @@ usr/share/doc/apport usr/share/locale usr/share/icons -usr/share/mime usr/share/polkit-1 usr/share/apport/package-hooks usr/share/apport/general-hooks 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,16 @@ +apport (2.14.1-0ubuntu3.25) trusty-security; urgency=medium + + * SECURITY UPDATE: code execution through path traversal in + .crash files (LP: #1700573) + - apport/report.py, test/test_ui.py: fix traversal issue + and add a test for that. + - debian/apport.install, setup.py, xdg-mime/apport.xml: removes + apport as a file handler for .crash files. Thanks to Brian + Murray for the patch and Felix Wilhelm for discovering this. + - CVE-2017-10708 + + -- Leonidas S. Barbosa Mon, 17 Jul 2017 08:43:04 -0300 + apport (2.14.1-0ubuntu3.24) trusty; urgency=medium * data/general/ubuntu.py: Collect a minimal version of /proc/cpuinfo in diff -u apport-2.14.1/test/test_ui.py apport-2.14.1/test/test_ui.py --- apport-2.14.1/test/test_ui.py +++ apport-2.14.1/test/test_ui.py @@ -986,6 +986,27 @@ self.assertFalse(os.path.exists('/tmp/pwned')) self.assertIn('invalid Package:', self.ui.msg_text) + def test_run_crash_malicious_exec_path(self): + '''ExecutablePath: path traversal''' + + hook_dir = '/tmp/share/apport/package-hooks' + os.makedirs(hook_dir, exist_ok=True) + bad_hook = tempfile.NamedTemporaryFile(dir=hook_dir, suffix='.py') + bad_hook.write(b"def add_info(r, u):\n open('/tmp/pwned', 'w').close()") + bad_hook.flush() + + self.report['ExecutablePath'] = '/opt/../' + hook_dir + self.report['Package'] = os.path.splitext(bad_hook.name)[0].replace(hook_dir, '') + self.update_report_file() + self.ui.present_details_response = {'report': True, + 'blacklist': False, + 'examine': False, + 'restart': False} + + self.ui.run_crash(self.report_file.name) + + self.assertFalse(os.path.exists('/tmp/pwned')) + def test_run_crash_ignore(self): '''run_crash() on a crash with the Ignore field''' self.report['Ignore'] = 'True' only in patch2: unchanged: --- apport-2.14.1.orig/setup.py +++ apport-2.14.1/setup.py @@ -120,11 +120,10 @@ description='intercept, process, and report crashes and bug reports', version=__version__, - data_files=[('share/mime/packages', glob('xdg-mime/*')), + data_files=[('share/doc/apport', glob('doc/*.txt')), # these are not supposed to be called directly, use apport-bug instead ('share/apport', ['gtk/apport-gtk', 'kde/apport-kde']), ('share/apport/testsuite/', glob('test/*')), - ('share/doc/apport/', glob('doc/*.txt')), ('lib/pm-utils/sleep.d/', glob('pm-utils/sleep.d/*')), ('/lib/udev/rules.d', glob('udev/*.rules')), ] + optional_data_files,