Skip to content

CVE-2024-2307: A race condition in repository handling can cause manifest generation with omitted signature verification of packages

Moderate
thozza published GHSA-v78q-xrpc-w24m Mar 22, 2024

Package

osbuild-composer

Affected versions

< 94

Patched versions

94

Description

Summary

osbuild-composer most of the time generates an osbuild manifest that skips gpg checking on RPMs from a payload repository, i.e. a repo added as a source like composer-cli sources add epel.toml, if there is another payload repository with check_gpg = false configured.

Details

I ran the same (tar) build over and over in a loop overnight. It uses RPMs from the following custom repo I configured (settings copied from epel.repo)

[root@f9c3a85f2ed5 builds]# composer-cli sources info epel 
check_gpg = true
check_repogpg = false
check_ssl = true
gpgkeys = ["-----BEGIN PGP PUBLIC KEY BLOCK-----\n\nmQINBFz3zvsBEADJOIIWllGudxnpvJnkxQz2CtoWI7godVnoclrdl83kVjqSQp+2\ndgxuG5mUiADUfYHaRQzxKw8efuQnwxzU9kZ70ngCxtmbQWGmUmfSThiapOz00018\n+eo5MFabd2vdiGo1y+51m2sRDpN8qdCaqXko65cyMuLXrojJHIuvRA/x7iqOrRfy\na8x3OxC4PEgl5pgDnP8pVK0lLYncDEQCN76D9ubhZQWhISF/zJI+e806V71hzfyL\n/Mt3mQm/li+lRKU25Usk9dWaf4NH/wZHMIPAkVJ4uD4H/uS49wqWnyiTYGT7hUbi\necF7crhLCmlRzvJR8mkRP6/4T/F3tNDPWZeDNEDVFUkTFHNU6/h2+O398MNY/fOh\nyKaNK3nnE0g6QJ1dOH31lXHARlpFOtWt3VmZU0JnWLeYdvap4Eff9qTWZJhI7Cq0\nWm8DgLUpXgNlkmquvE7P2W5EAr2E5AqKQoDbfw/GiWdRvHWKeNGMRLnGI3QuoX3U\npAlXD7v13VdZxNydvpeypbf/AfRyrHRKhkUj3cU1pYkM3DNZE77C5JUe6/0nxbt4\nETUZBTgLgYJGP8c7PbkVnO6I/KgL1jw+7MW6Az8Ox+RXZLyGMVmbW/TMc8haJfKL\nMoUo3TVk8nPiUhoOC0/kI7j9ilFrBxBU5dUtF4ITAWc8xnG6jJs/IsvRpQARAQAB\ntChGZWRvcmEgRVBFTCAoOCkgPGVwZWxAZmVkb3JhcHJvamVjdC5vcmc+iQI4BBMB\nAgAiBQJc9877AhsPBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAh6kWrL4bW\noWagD/4xnLWws34GByVDQkjprk0fX7Iyhpm/U7BsIHKspHLL+Y46vAAGY/9vMvdE\n0fcr9Ek2Zp7zE1RWmSCzzzUgTG6BFoTG1H4Fho/7Z8BXK/jybowXSZfqXnTOfhSF\nalwDdwlSJvfYNV9MbyvbxN8qZRU1z7PEWZrIzFDDToFRk0R71zHpnPTNIJ5/YXTw\nNqU9OxII8hMQj4ufF11040AJQZ7br3rzerlyBOB+Jd1zSPVrAPpeMyJppWFHSDAI\nWK6x+am13VIInXtqB/Cz4GBHLFK5d2/IYspVw47Solj8jiFEtnAq6+1Aq5WH3iB4\nbE2e6z00DSF93frwOyWN7WmPIoc2QsNRJhgfJC+isGQAwwq8xAbHEBeuyMG8GZjz\nxohg0H4bOSEujVLTjH1xbAG4DnhWO/1VXLX+LXELycO8ZQTcjj/4AQKuo4wvMPrv\n9A169oETG+VwQlNd74VBPGCvhnzwGXNbTK/KH1+WRH0YSb+41flB3NKhMSU6dGI0\nSGtIxDSHhVVNmx2/6XiT9U/znrZsG5Kw8nIbbFz+9MGUUWgJMsd1Zl9R8gz7V9fp\nn7L7y5LhJ8HOCMsY/Z7/7HUs+t/A1MI4g7Q5g5UuSZdgi0zxukiWuCkLeAiAP4y7\nzKK4OjJ644NDcWCHa36znwVmkz3ixL8Q0auR15Oqq2BjR/fyog==\n=84m8\n-----END PGP PUBLIC KEY BLOCK-----\n"]
id = "epel"
name = "Extra Packages for Enterprise Linux 8 - $basearch"
rhsm = false
system = false
type = "yum-metalink"
url = "https://mirrors.fedoraproject.org/metalink?repo=epel-8&arch=$basearch&infra=$infra&content=$contentdir"

and here is the config for the non-gpg checked repository

[root@f9c3a85f2ed5 builds]# composer-cli sources info local
id = "local"         
name = "Local RPMS"  
type = "yum-baseurl" 
url = "file:///rpms/"

The next day I downloaded the manifests from all 55 builds, and in 48 of the builds the RPMs from EPEL were inputs in the os pipeline org.osbuild.rpm stage WITHOUT options set (i.e. no gpgcheck set). In the remaining 7 builds the gpgcheck was enabled on these same RPMs.

Example from "good" build:

<                 {                                                                                 
<                   "id": "sha256:b69491a8aee0dffbd532deff530ac69691389ac0c9dfa88a169d818a25ad31b9",
<                   "options": {                                                                    
<                     "metadata": {                                                                 
<                       "rpm.check_gpg": true                                                       
<                     }                                                                             
<                   }                                                                               
<                 },                                                                                

Example from "bad" build:

>                 }                                                                            
>                   "id": "sha256:b69491a8aee0dffbd532deff530ac69691389ac0c9dfa88a169d818a25ad31b9"
>                 },                                                                               

I noticed this issue when I was testing the build with check_gpg = true in the epel.toml file but without the EPEL gpgkey provided. With this configuration, the build would fail every 10-20% of the time. I discovered these manifest differences while investigating these build failures. It turned out that the build would fail with checksig errors only when the manifest was correctly generated with the check_gpg option for the EPEL rpms. All the other builds succeeded because of the bad manifest. I added the EPEL gpg key to make my builds succeed 100% of the time, but gpg checks are still skipped the majority of the time as evidenced above. Without these checks there is no guarantee that the RPM in the build is the same RPM packaged by EPEL, thus a security risk. I don't think that this is EPEL specific either. I think any payload repo would have this same problem. In every build either all 12 EPEL RPMs were verified or all 12 were unverified. This leads me to believe that the check_gpg setting on the repo itself is the culprit. Interestingly, when I remove the "local" repo the build does not fail anymore.

PoC

EDIT: The steps I provide below are simplified versions of how I reproduced, but I oversimplified and the build appears to be behaving correctly. I am currently working on fixing the below steps.

I reproduced this in a docker container based on registry.access.redhat.com/ubi8/ubi-init:8.9-3, redhat's universal base image for RHEL 8.9. I have no evidence to suggest that that is a repro prerequisite, unless this has been fixed in newer versions of osbuild-composer. The version that get's installed in that container is from the rhel 8 appstream repo, version 88-1.el8.

Once osbuild-composer is set up, add the custom repo from above

composer-cli sources add epel.toml

and add the local repo from above

composer-cli sources add local.toml

Then generate a manifest from the following blueprint

name = "build"   
version = "0.0.1"
distro = "rhel-8"
                 
[[packages]]     
name = "htop"    
version = "*"    

I used rhel-8 distro but I don't think that is important. I use the htop package here, but I expect any EPEL package to be just as good.

Once the build manifest is available you can inspect it check if the EPEL rpms are going to be verified or not. If they are unverified then you have reproduced the problem. If they are verified, then you should try another build in the exact same way. It shouldn't take more than 2 tries.

I did a bunch of builds overnight and checked them at once using the following command

# cat *.json | jq -s 'map(.pipelines[] | select(.name == "os") | .stages[] | select(.type == "org.osbuild.rpm") | select(.options.gpgkeys | length == 3) | .inputs.packages.references | map(select(.options == null)) | length > 0) | {"unverified_builds":map(select(.)) | length, "verified_builds": map(select(. | not)) | length}'
{
  "unverified_builds": 48,
  "verified_builds": 7
}

Impact

I'm not a security researcher, I just wanted my builds to be less flaky and I ended up discovering this, so I don't know how to classify this vulnerability. But I do know that if without gpg signature verification the RPM that is downloaded and installed by osbuild could be corrupted or replaced with a bad version, which could then result is a compromised base image. This seems like a security vulnerability to me, but even if you disagree with that I think this is definitely a bug.

Severity

Moderate

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
High
User interaction
Required
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
Low

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:H/A:L

CVE ID

No known CVE

Credits