Red Hat Bugzilla – Bug 1287883
gpgcheck performed by yum does not actually validate rpm contents against GPG signature
Last modified: 2017-10-13 02:56:13 EDT
Description of problem:
The gpgcheck option is not equivalent to rpm -K, which would seem to be the implied claim. The root of the problem is that yum implementation for this feature eventually goes into rpmutils.py which checks the rpm headers and it checks for the presence of a GPG signature. It never actually checks that the signature is still valid. It does check for corrupt headers, so modifying the header information will result in a bad DSA and SHA1 error. A simple of an rpm can be performed (echo "0" >> <rpmpackage>) and yum will happily install the package. A clumsy hacking can be performed (modifying a byte within the package binary data) and yum will not complain but cpio fails on extraction. I surmise that a splicing of a modified cpio package into a signed rpm would allow someone to install a modified rpm that passed the yum gpgcheck even though that rpm would fail the rpm -K check.
Version-Release number of selected component (if applicable):
This was tested in 6.3, but likely impacts all releases.
Steps to Reproduce:
1. In yum repository perform 'echo "0" >> <rpmpackage>'
2. execute rpm -K <rpmpackage> and observe that signature is no longer valid.
2. rebuild yum database
3. on remote system ensure repo is set to gpgcheck=1
4. on remote system perform yum install <rpmpackage>
rpm installs without issues
rpm should fail gpg check and fail to install
yum should execute rpm -K on downloaded rpm prior to beginning installation.
(In reply to Alex Smith from comment #0)
> A clumsy hacking can be performed (modifying a
> byte within the package binary data) and yum will not complain but cpio
> fails on extraction. I surmise that a splicing of a modified cpio package
> into a signed rpm would allow someone to install a modified rpm that passed
> the yum gpgcheck even though that rpm would fail the rpm -K check.
Appending data to an rpm file doesn't modify its payload (cpio archive after the header). When rpm reads the payload, it will only read as many bytes as the header (which is signed) advertises.
Tampering with the payload (including slicing it off completely and attaching your own) is not possible without rpm noticing, either. If rpm didn't fail while unpacking the archive in the first place, it would detect the tamper before installing the unpacked files to the system because it compares their hashes to the ones recorded in the header. rpm would abort the transaction if that comparison fails (not doing any cleanup of the already installed files and executed scriptlets), so while no unsigned files would be installed, the package might be left in a partly installed state, which has its own risks (e.g. due to scriptlets not designed to work properly in such cases).
Normally, when installing packages, yum (and rpm) only verifies the signed header, so payload tamper is not detected at this stage. What "rpm -K" does is that it also verifies the payload signature, so we thought that doing this in yum would prevent such hypothetical partial installations, as the check would be done before the rpm transaction even starts. In the end, we reused this BZ to add this exact functionality to yum in RHEL-7.4 (which still allows for RFEs) via the new option payload_gpgcheck (bug 1343690).
Anyway, in most cases, yum is used to install packages from repositories, which are often consumed (at least when using subscription-manager) via SSL. That pretty much eliminates man-in-the-middle attacks for such repos. In addition to that, yum checksums every package after downloading it and compares the result with the repodata which carries the expected package checksums. So the risk of installing a broken payload can be narrowed down to installing local rpm files, which is where using payload_gpgcheck makes the most sense.