michael orlitzky

CVE-2019-20384: Portage insecure temporary location

Product
Gentoo portage package manager
Versions affected
2.3.93 and earlier
Published on
2020-01-21
Author
Michael Orlitzky
Fixed in
commit ef8c21e5, version 2.3.94
Bug report
https://bugs.gentoo.org/692492
MITRE
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-20384
OSS-security
https://www.openwall.com/lists/oss-security/2020/01/21/1

Summary

The Gentoo portage package manager builds packages in a temporary location. By default, that temporary location is accessible to unprivileged users even though the build essentially takes place as root. In some common situations (during reinstalls, for example), this leaves the source tree momentarily writable by an existing system user who can exploit the situation to gain root.

Details

Portage is the default package manager on Gentoo Linux, a source-based distribution. To install a package, portage runs through a series of configuration, compilation, and installation phases consisting of bash script. These all run with root privileges in a temporary subdirectory of the location specified by the PORTAGE_TMPDIR variable. The install phase performs a “mock” installation, in a self-contained directory, that can be tweaked before proceeding to the next step. When the build and mock-install are complete, the final result is merged onto the live filesystem, again using root privileges.

Gentoo developers and portage itself take some care to ensure that nothing objectionable reaches the live filesystem. Subdirectories of PORTAGE_TMPDIR, on the other hand, are the wild wild west. Much of PORTAGE_TMPDIR is world-traversable, and that lack of access control turns out to be exploitable by users who are granted ephemeral write access to the source tree of a package being installed. If an unprivileged user can write to the mock-installation image of a package, then in essence he can write to the live filesystem as well because everything in the mock image is merged onto the live filesystem eventually.

It is the nature of package maintenance that illicit things must take during the build and installation phases. For example, many upstream build systems set incorrect permissions on the files they produce, and those permissions must be corrected before the files are merged onto the system. But before problems are fixed in the mock-install, they exist in the mock-install. And many of them allow an unprivileged user to modify the source tree.

Exploitation

The nagioscore package is available in Gentoo as net-analyzer/nagios-core. By default its build system gives ownership of /usr/lib64/nagios/plugins to the nagios user, but this gets corrected to root:root to avoid surprises.

The two lines that accomplish that in the net-analyzer/nagios-core ebuild are,

1
2
emake DESTDIR="${D}" install-basic
fowners root:root /usr/lib64/nagios/plugins

The $D variable refers to the mock-installation path under PORTAGE_TMPDIR, and fowners implicitly acts there. But between the call to emake and the call to fowners, the plugin directory in the mock installation image is writable by the nagios user. Below we demonstrate how nagios can abuse this to install a malicious plugin.

  1. First, add a sleep call to the ebuild to make it easier to exploit interactively:

    1
    2
    3
    4
    emake DESTDIR="${D}" install-basic
    echo "I'm vulnerable, is it nap time?"
    sleep 15
    fowners root:root /usr/lib64/nagios/plugins

  2. Install acct-user/nagios once, so that the unprivileged nagios is created on the system (in real life, this happens automatically):

    root # emerge -1 acct-user/nagios

  3. Initiate an install of net-analyzer/nagios-core:

    root # emerge net-analyzer/nagios-core

  4. When the ebuild reaches the sleep call that we added, the plugin directory in the mock-install image is writable by the nagios user. Commandeer the nagios user with su, and place a malicious plugin there:

    root # su -s /bin/sh nagios

    nagios $ touch /var/tmp/portage/net-analyzer/nagios-core-*/image/usr/lib64/nagios/plugins/exploit.txt

  5. Wait for the sleep() to pass, and watch the nagios-owned exploit be installed to the live system:

    >>> /usr/lib64/nagios/cgi-bin/tac.cgi

    >>> /usr/lib64/nagios/cgi-bin/extinfo.cgi

    >>> /usr/lib64/nagios/cgi-bin/config.cgi

    --- /usr/lib64/nagios/plugins/

    >>> /usr/lib64/nagios/plugins/exploit.txt

Resolution

Version 2.3.94 of portage now applies the stricter PORTAGE_WORKDIR_MODE permissions to the PORTAGE_BUILDDIR subdirectory of PORTAGE_TMPDIR. This prevents unprivileged users from writing to the build directory.