Location: src/install.c, function do_install_bundle(), lines 1022-1035 (v1.4)
Attack Vector: Local
Severity: Moderate
Impact: Signature verification bypass
Credit: Vdoo https://vdoo.com (VD-1880)
CVE: CVE-2020-25860
Timeline:
- 2020-08-17: initial notification by Vdoo (including description and proof of concept)
- 2020-08-17: confirmation by Pengutronix to Vdoo
- 2020-08-28: impact analysis and mitigation/solution plan reported to Vdoo
- 2020-08 - 2020-12: solution design, implementation and test
- 2020-12-21: advisory publication
Versions Affected: up to 1.4
Score: 8.8
A time-of-check-time-of-use vulnerability exists in the code that checks and installs a firmware bundle.
When running "rauc install bundle.raucb" or using the 'Install/InstallBundle' D-Bus methods, RAUC does the following:
- check_bundle() – verify the bundle signature via OpenSSL by opening it using the file name
- mount_bundle() – mount the bundle via a loopback device, re-opening it by file name
- install the content of the bundle, possibly executing hook scripts
If the attacker is able to replace the bundle file between steps 1. and 2., RAUC will mount and install the modified bundle. Also, if the attacker is able to modify the bundle file after step 2., they can modify the payload to be installed or cause arbitrary hooks to be executed during the installation.
This vulnerability requires the attacker to be able to replace or modify the bundle file on disk, while RAUC is installing it (required privileges depend on where the file is originally stored). If an attacker has no write access to the location where bundles are installed from and cannot trigger an installation, the vulnerability cannot be exploited.
Thus, if the rauc service is disabled (via the --disable-service option to configure) and bundles are only installed by root from a safe location, the vulnerability is not exploitable by other users.
If the system contains an update service accessible from the network and this service stores the bundle to always the same location and does not deny uploads while an installation is running, both vulnerabilities can be combined to a remote attack. Note that the CGI example included with RAUC denies uploads while an installation is running.
If the attack is applicable to your system, you should update to RAUC version 1.5.
As part of preparing the update, verify that the new version is still able to install further updates. More information on the migration process is available in the Integration chapter under Bundle Format Migration (docs/integration.rst in the source).
While the vulnerability to replacing the bundle file could be fixed through avoiding any re-opening of the bundle, this is not enough to protect against concurrent modification of the mounted bundle file.
RAUC's original bundle format consists of a payload (a squashfs filesystem) protected by a CMS signature. This means that the payload must be authenticated as a whole before accessing it and any subsequent modification cannot be detected.
As most systems using RAUC have little spare storage space, making a temporary private copy of the to-be-installed bundle is not feasible. This means that with the original bundle format the only possible mitigation is to ensure that no concurrent modification by an attacker is possible.
The solution implemented in RAUC version 1.5 consists of three parts: A: opening the bundle file only once B: protecting the bundle file against modification during installation C: introducing a new bundle format
Part A solves the issue of re-opening the bundle after signature verification. RAUC will now create the loop-back device directly from the open file descriptor without using the losetup tool.
Part B protects against concurrent modification of the open bundle after signature verification. This is done by taking ownership of the bundle file, restricting write permissions and then checking for pre-existing open file descriptors using the lease mechanism provided by the Linux kernel (fcntl with F_SETLEASE). Additionally, filesystems which could be provided by the attacker (such as FUSE or NFS) are rejected.
With A and B, installations of bundles using the original ("plain") bundle format are protected against the vulnerability.
As a longer-term solution, part C adds a new bundle format based on the dm-verity [1] device mapper target. With this format, the payload is not authenticated as a separate step, but directly by the kernel during every payload access. This way, even bundles located on untrusted storage can be safely installed. In the future, this will allow incrementally downloading a bundle over the network, even with an untrusted connection or server.
RAUC automatically detects the bundle format and can be configured to reject formats.
Until a fixed version is available in your build system, you may want to integrate it yourself. For OpenEmbedded/Yocto, PTXdist and Buildroot, we have prepared examples to help with the update to 1.5: https://github.com/rauc/rauc-1.5-integration
If your system uses an unsupported version of OpenSSL (<1.1.1), a backport patch is available in the rauc-1.5-integration repository above. Note that this patch does not have the same breadth of testing as the 1.5 release.
If you have any questions or comments about this advisory:
- Open an issue in https://github.com/rauc/rauc-1.5-integration
- Email us at security@pengutronix.de
[1] https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html#theory-of-operation