arbitrary code execution or file overwrite when templates are loaded from /tmp

Bug #1453815 reported by Simon McVittie
256
This bug affects 1 person
Affects Status Importance Assigned to Milestone
python-dbusmock
Fix Released
Medium
Martin Pitt
python-dbusmock (Debian)
Fix Released
Unknown
python-dbusmock (Fedora)
Confirmed
Medium
python-dbusmock (Ubuntu)
Fix Released
Medium
Martin Pitt
Trusty
Fix Released
Medium
Unassigned
Utopic
Fix Released
Medium
Unassigned
Vivid
Fix Released
Medium
Unassigned
Wily
Fix Released
Medium
Martin Pitt

Bug Description

While investigating a (perhaps transient) build failure in a Debian derivative, I accidentally found a class of security vulnerabilities in python-dbusmock.

In python-dbusmock's build-time test_api test, this:

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

    return importlib.import_module('dbusmock.templates.' + name)

is invoked with name being the name of a NamedTemporaryFile. That's probably in /tmp or /var/tmp, so I see several things that could go wrong there. We could have any of these attack modes, either in python-dbusmock's own tests or in any other code that also puts its template in /tmp or some other world-writeable directory:

* the attacker creates a large fraction of the approximately 3.5e12
  possible names matching /tmp/mymodule_[a-z0-9_]{8}.pyc (or .pyo as
  appropriate) as (symlinks to) their malicious code, and we execute
  one: arbitrary code execution
  (this is hard to do, since the complete set would be multiple
  terabytes)

* the attacker creates a large fraction of those names as symlinks
  to a file they want overwritten, and we overwrite it if Python
  doesn't use atomic overwrite for .pyc (which I haven't checked)
  (this is similarly hard to do)

* the attacker uses an inotify on /tmp for a more targeted version
  of the same attack, racing to create their payload .pyc before
  our Python interpreter loads it
  (this is perhaps a more realistic attack)

* the attacker creates /tmp/foo.py where foo is the name of a module
  that is imported (possibly by another thread!) while we are in
  the 'try' block, and we execute it
  (I don't know whether os.path and/or importlib guarantee not to
  import other modules, but other threads certainly don't have
  that guarantee)

Tags: patch

CVE References

Revision history for this message
Martin Pitt (pitti) wrote :

IMHO It's highly unrealistic that this actually gets exploited, as it requires a scenario where someone directly puts a module into /tmp/, not a subdir. Aside from dbusmock's own tests this is very unlikely as usually projects ship their own mocks in their source tree, and don't generate it on the fly. And then it can only happen when there are multiple and untrusted users on a machine (which isn't the case in CI systems either).

So, this does need to get fixed, but my gut feeling is that the severity is on the "low" side and doesn't warrant private
vendor-sec coordination with a coordinated release date. But I'll let our security team decide.

As discussed by mail already, this is the patch which I'll apply upstream. This includes a test case, too.

Changed in python-dbusmock:
status: New → In Progress
importance: Undecided → Medium
assignee: nobody → Martin Pitt (pitti)
Changed in python-dbusmock (Ubuntu Wily):
status: New → In Progress
assignee: nobody → Martin Pitt (pitti)
Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

Please use CVE-2015-1326 for this issue.

Revision history for this message
Martin Pitt (pitti) wrote :

I discussed this with Marc, and we both agree that this isn't severe enough for a CRD, so let's make this public.

information type: Private Security → Public Security
Revision history for this message
Martin Pitt (pitti) wrote :

Upstream commit which fixes this: https://github.com/martinpitt/python-dbusmock/commit/4e7d0df9093

This is included in the 0.15.1 upstream release: https://launchpad.net/python-dbusmock/trunk/0.15.1

Changed in python-dbusmock:
status: In Progress → Fix Released
Revision history for this message
In , Martin (martin-redhat-bugs) wrote :

Simon McVittie found a potentially exploitable bug with loading custom dbusmock templates: When a user is tricked 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. Hence we decided to immediately make this bug public and don't aim for a coordinated release date. So please make this bug public as well.

Details are on the linked Launchpad bug.

CVE-2015-1326
Upstream fix: https://github.com/martinpitt/python-dbusmock/commit/4e7d0df9093
This is included in the 0.15.1 upstream release: https://launchpad.net/python-dbusmock/trunk/0.15.1

Revision history for this message
In , Martin (martin-redhat-bugs) wrote :

I initially tried to report this as a security bug, but bugzilla would just error 500 on me. Can we subscribe the Fedora/RedHat security team to an existing bug?

Revision history for this message
Martin Pitt (pitti) wrote :

0.15.1-1 uploaded to sid, I'll sync into Wily once it gets imported into LP.

Changed in python-dbusmock (Ubuntu Wily):
status: In Progress → Fix Committed
Revision history for this message
Martin Pitt (pitti) wrote :

debdiff for vivid with backported patch.

Changed in python-dbusmock (Ubuntu Vivid):
status: New → In Progress
Revision history for this message
Martin Pitt (pitti) wrote :

debdiff for utopic

Changed in python-dbusmock (Ubuntu Utopic):
status: New → In Progress
Changed in python-dbusmock (Ubuntu Wily):
importance: Undecided → Medium
Changed in python-dbusmock (Ubuntu Vivid):
importance: Undecided → Medium
Changed in python-dbusmock (Ubuntu Utopic):
importance: Undecided → Medium
Changed in python-dbusmock (Ubuntu Trusty):
importance: Undecided → Medium
Revision history for this message
Martin Pitt (pitti) wrote :

debdiff for trusty

Changed in python-dbusmock (Ubuntu Trusty):
status: New → In Progress
tags: added: patch
Revision history for this message
In , Matěj (matj-redhat-bugs) wrote :

(In reply to Martin Pitt from comment #1)
> I initially tried to report this as a security bug, but bugzilla would just
> error 500 on me. Can we subscribe the Fedora/RedHat security team to an
> existing bug?

You probably have to have some higher level of mojo ;)

Revision history for this message
In , Matěj (matj-redhat-bugs) wrote :

Trying the update to 0.15.1 on Fedora Rawhide and the running of tests seems to end in the disaster ... https://kojipkgs.fedoraproject.org//work/tasks/3162/9713162/build.log ... any idea?

Revision history for this message
In , Matěj (matj-redhat-bugs) wrote :
Revision history for this message
In , Martin (martin-redhat-bugs) wrote :

The _dbus_class_table attribute comes from dbus-python. I haven't seen this error yet, we have version 1.2.0. According to https://kojipkgs.fedoraproject.org//work/tasks/3162/9713162/root.log that's the version you have as well..

Was that updated/patched recently in Fedora in a way which could explain this? When did the previous dbusmock build happen?

Revision history for this message
In , Matěj (matj-redhat-bugs) wrote :

(In reply to Martin Pitt from comment #5)
> Was that updated/patched recently in Fedora in a way which could explain
> this? When did the previous dbusmock build happen?

That’s the problem … it seems that the last updated version is python-dbusmock-0.11.1-1.fc22, so I am trying to make a huge leap to 0.15.1, I know.

See http://koji.fedoraproject.org/koji/packageinfo?packageID=14852 for the history of builds in Fedora.

Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package python-dbusmock - 0.15.1-1

---------------
python-dbusmock (0.15.1-1) unstable; urgency=medium

  * New upstream release.
    - 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.
      (LP: #1453815, CVE-2015-1326)

 -- Martin Pitt <email address hidden> Tue, 12 May 2015 12:49:53 +0200

Changed in python-dbusmock (Ubuntu Wily):
status: Fix Committed → Fix Released
Revision history for this message
In , Martin (martin-redhat-bugs) wrote :

OOI, does it build on F22 and/or F21 with an older dbus-python? You would probably just grab the single commit for those; but neither that commit nor the other recent changes in later versions don't change the Introspect() method (which accesses self._dbus_class_table), the last change there was in September 2012.

Revision history for this message
In , Vasyl (vasyl-redhat-bugs) wrote :

*** Bug 1220745 has been marked as a duplicate of this bug. ***

Revision history for this message
In , Vasyl (vasyl-redhat-bugs) wrote :

*** Bug 1220744 has been marked as a duplicate of this bug. ***

Revision history for this message
In , Vasyl (vasyl-redhat-bugs) wrote :

Created python-dbusmock tracking bugs for this issue:

Affects: fedora-all [bug 1223312]
Affects: epel-all [bug 1223313]

Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package python-dbusmock - 0.11.4-1ubuntu1

---------------
python-dbusmock (0.11.4-1ubuntu1) utopic-security; urgency=medium

  * 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.
    (LP: #1453815, CVE-2015-1326)

 -- Martin Pitt <email address hidden> Tue, 12 May 2015 13:23:38 +0200

Changed in python-dbusmock (Ubuntu Utopic):
status: In Progress → Fix Released
Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package python-dbusmock - 0.14-1ubuntu2

---------------
python-dbusmock (0.14-1ubuntu2) vivid-security; urgency=medium

  * 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.
    (LP: #1453815, CVE-2015-1326)

 -- Martin Pitt <email address hidden> Tue, 12 May 2015 13:20:03 +0200

Changed in python-dbusmock (Ubuntu Vivid):
status: In Progress → Fix Released
Revision history for this message
Launchpad Janitor (janitor) wrote :

This bug was fixed in the package python-dbusmock - 0.10.1-1ubuntu1

---------------
python-dbusmock (0.10.1-1ubuntu1) trusty-security; urgency=medium

  * 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.
    (LP: #1453815, CVE-2015-1326)

 -- Martin Pitt <email address hidden> Tue, 12 May 2015 13:26:28 +0200

Changed in python-dbusmock (Ubuntu Trusty):
status: In Progress → Fix Released
Changed in python-dbusmock (Debian):
status: Unknown → Fix Released
Revision history for this message
In , Martin (martin-redhat-bugs) wrote :

Wrt. the build failure: dbus-python's Introspect() does assume that self._dbus_class_table exists; if it wouldn't, the original method would fail as well:

  http://cgit.freedesktop.org/dbus/dbus-python/tree/dbus/service.py#n756

the koji test failure happens in the overridden def Introspect() which augments self._dbus_class_table with the mocked methods. So this looks like a bug in your dbus-python package somehow?

Indeed I can reproduce the failure on a F21 live system. It seems that your dbus-python package has a patch which removes self._dbus_class_table:

  http://pkgs.fedoraproject.org/cgit/dbus-python.git/tree/object_manager.patch

Revision history for this message
In , Martin (martin-redhat-bugs) wrote :

Created attachment 1029836
patch for building with Fedora-patched dbus-python

If you apply this patch to python-dbusmock, it will work correctly with the Fedora-patched dbus-python. I'm happy to apply this patch upstream once the dbus-python patch lands upstream as well.

Revision history for this message
In , Matěj (matj-redhat-bugs) wrote :

Created attachment 1304880
koji build log

Not sure what to think about this problem.

Revision history for this message
In , Matěj (matj-redhat-bugs) wrote :

And of course, I am sorry, that it took so long to get back to this bug.

Revision history for this message
In , Martin (martin-redhat-bugs) wrote :

@Matej: The four timedated test failures were due to output format changes in systemd 215/220, and got fixed in https://github.com/martinpitt/python-dbusmock/commit/f1e2b19bba12fc and https://github.com/martinpitt/python-dbusmock/commit/3d09f9fc27a.

The two test_logind failures were due to output format changes in systemd 209 and got fixed in https://github.com/martinpitt/python-dbusmock/commit/39a807c5 .

But I suppose this is all moot now in recent Fedoras, which have recent upstream versions?

Revision history for this message
In , Matěj (matj-redhat-bugs) wrote :

(In reply to Martin Pitt from comment #15)
> But I suppose this is all moot now in recent Fedoras, which have recent
> upstream versions?

Not in EPEL-7 and F25. With those patches, I have managed to built on both on these, so this bug will be finally closed eventually.

Changed in python-dbusmock (Fedora):
importance: Unknown → Medium
status: Unknown → Confirmed
To post a comment you must log in.
This report contains Public Security information  
Everyone can see this security related information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.