From 985ba133b6f4bba9ddba39d6325d405c4a63f212 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Mon, 11 May 2015 16:00:10 +0200 Subject: [PATCH] SECURITY FIX: Prevent code execution through crafted pyc files When loading a template from an arbitrary file through the AddTemplate() D-Bus method call or DBusTestCase.spawn_server_template() Python method, don't create or use Python's *.pyc cached files.By tricking a user into loading a template from a world-writable directory like /tmp, an attacker could run arbitrary code with the user's privileges by putting a crafted .pyc file into that directory. Note that this is highly unlikely to actually appear in practice as custom dbusmock templates are usually shipped in project directories, not directly in world-writable directories. Thanks to Simon McVittie for discovering this! LP: #1453815 --- NEWS | 13 +++++++++++++ dbusmock/mockobject.py | 13 +++++-------- tests/test_api.py | 10 ++++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index ab654b5..338e154 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,16 @@ +0.15.1 (UNRELEASED) +------------------- + - SECURITY FIX: When loading a template from an arbitrary file through the + AddTemplate() D-Bus method call or DBusTestCase.spawn_server_template() + Python method, don't create or use Python's *.pyc cached files. By tricking + a user into loading a template from a world-writable directory like /tmp, an + attacker could run arbitrary code with the user's privileges by putting a + crafted .pyc file into that directory. Note that this is highly unlikely to + actually appear in practice as custom dbusmock templates are usually shipped + in project directories, not directly in world-writable directories. + Thanks to Simon McVittie for discovering this! + (LP: #1453815, CVE-????-????) + 0.15 (2015-05-08) ------------------- - NetworkManager template: Restore nm-specific PropertiesChanged signal diff --git a/dbusmock/mockobject.py b/dbusmock/mockobject.py index 29f790e..586dbad 100644 --- a/dbusmock/mockobject.py +++ b/dbusmock/mockobject.py @@ -17,6 +17,7 @@ import time import sys import types import importlib +import imp from xml.etree import ElementTree # we do not use this ourselves, but mock methods often want to use this @@ -40,14 +41,10 @@ if sys.version_info[0] >= 3: def load_module(name): if os.path.exists(name) and os.path.splitext(name)[1] == '.py': - sys.path.insert(0, os.path.dirname(os.path.abspath(name))) - try: - m = os.path.splitext(os.path.basename(name))[0] - module = importlib.import_module(m) - finally: - sys.path.pop(0) - - return module + mod = imp.new_module(os.path.splitext(os.path.basename(name))[0]) + with open(name) as f: + exec(f.read(), mod.__dict__, mod.__dict__) + return mod return importlib.import_module('dbusmock.templates.' + name) diff --git a/tests/test_api.py b/tests/test_api.py index b7b06f2..e346a6b 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -592,6 +592,16 @@ def load(mock, parameters): self.addCleanup(p_mock.terminate) self.addCleanup(p_mock.stdout.close) + # ensure that we don't use/write any .pyc files, they are dangerous + # in a world-writable directory like /tmp + self.assertFalse(os.path.exists(my_template.name + 'c')) + try: + from importlib.util import cache_from_source + self.assertFalse(os.path.exists(cache_from_source(my_template.name))) + except ImportError: + # python < 3.4 + pass + self.assertEqual(dbus_ultimate.Answer(), 42) # should appear in introspection -- 2.1.4