Problem Summary
RPM packages with OS release-specific suffixes (e.g., el7eap, el8eap, el9eap) are incorrectly matched across different OS release lines because the version comparison function treats them as a linear version progression rather than distinct product lines.
Current Behavior
When querying for vulnerabilities affecting a PURL like:
pkg:rpm/redhat/eap7-bouncycastle@1.76.0-4.redhat_00001.1.el8eap?arch=noarch
The system incorrectly matches it against purl_status records that have version ranges targeting different OS releases:
| Version Range |
Status |
Expected Match |
Actual Match |
[el8eap, el8eap] |
fixed |
Yes |
Yes |
(null, el9eap) |
affected |
No |
Yes |
The el8eap purl incorrectly matches the range < el9eap because rpmver_cmp() compares the release suffixes as 8 < 9.
Root Cause
The rpmver_cmp() function correctly implements RPM version comparison per the RPM spec:
-- Splits version into segments: 1.76.0-4.redhat_00001.1.el8eap
-- becomes: [1, 76, 0, 4, redhat, 00001, 1, el, 8, eap]
a_segments := array(select (regexp_matches(a, '(\d+|[a-zA-Z]+|[~^])', 'g'))[1]);
When comparing el8eap vs el9eap:
- Both split into segments:
[el, 8, eap] vs [el, 9, eap]
el = el (equal)
8 < 9 (numeric comparison)
- Result:
el8eap < el9eap
This is technically correct per RPM ordering, but semantically wrong for vulnerability correlation:
el7, el8, el9 represent different RHEL major versions
- They are parallel product lines, not version progressions
- A vulnerability fixed in
el9eap packages does NOT mean el8eap packages are affected
Affected Endpoints
| Endpoint |
Method |
Impact |
/api/v2/vulnerability/analyze |
POST |
Returns incorrect vulnerabilities for el8/el9 RPMs |
/api/v3/vulnerability/analyze |
POST |
Same as above, plus incorrect remediations |
/api/v3/purl/recommend |
POST |
May recommend wrong versions |
/api/v2/purl/{key} |
GET |
Shows incorrect vulnerability status |
/api/v2/sbom/{id}/advisory |
GET |
Lists wrong advisories for SBOM packages |
/api/v2/vulnerability/{id} |
GET |
Shows incorrect affected packages |
Reproduction Steps
-
Ingest a Red Hat CSAF advisory that contains products for multiple RHEL versions:
curl -X POST http://localhost:8080/api/v2/advisory \
-H "Content-Type: application/json" \
-d @etc/test-data/csaf/cve-2023-33201.json
-
Query for an el8eap package:
curl -X POST http://localhost:8080/api/v3/vulnerability/analyze \
-H "Content-Type: application/json" \
-d '{"purls": ["pkg:rpm/redhat/eap7-bouncycastle@1.76.0-4.redhat_00001.1.el8eap?arch=noarch"]}'
-
Observe that the response includes vulnerability status and remediations from el9eap products.
Test Cases
Tests documenting this issue:
Branch: test/rpm-os-release-suffix-matching
Test file: modules/ingestor/tests/version/rpmver.rs
| Test Name |
Purpose |
test_rpmver_cmp_release_suffix_different_os |
Documents that el7 < el8 < el9 per RPM spec |
test_rpmver_version_matches_cross_os_release_bug |
Documents the bug: el8eap matches range < el9eap |
test_rpmver_same_version_different_os_releases |
Shows all OS suffixes are treated as linear progression |
test_rpmver_version_matches_exact_with_os_suffix |
Verifies exact matching works correctly |
test_rpmver_version_matches_same_os_release |
Verifies matching within same OS release works |
Run the tests with:
cargo test -p trustify-module-ingestor --test ingestor test_rpmver
Potential Solutions
Option 1: Enhanced Version Range Matching
Modify rpmver_version_matches to detect and handle OS release suffixes:
CREATE FUNCTION extract_rpm_os_release(version text) RETURNS text AS $$
BEGIN
RETURN (regexp_match(version, '\.el(\d+)'))[1];
END;
$$ LANGUAGE plpgsql IMMUTABLE;
-- In rpmver_version_matches, add check:
IF extract_rpm_os_release(version_p) != extract_rpm_os_release(range_p.high_version) THEN
RETURN false;
END IF;
Pros: Targeted fix, minimal changes
Cons: RPM-specific, may miss edge cases
Option 2: Normalize OS Release in Base PURL
Extract OS release into PURL namespace during ingestion.
Option 3: Add OS Release Qualifier
Store OS release as a qualifier and include it in matching.
Option 4: Separate Version and Release Fields
Store RPM version and release separately in the database.
Related
References
Problem Summary
RPM packages with OS release-specific suffixes (e.g.,
el7eap,el8eap,el9eap) are incorrectly matched across different OS release lines because the version comparison function treats them as a linear version progression rather than distinct product lines.Current Behavior
When querying for vulnerabilities affecting a PURL like:
The system incorrectly matches it against
purl_statusrecords that have version ranges targeting different OS releases:[el8eap, el8eap](null, el9eap)The
el8eappurl incorrectly matches the range< el9eapbecauserpmver_cmp()compares the release suffixes as8 < 9.Root Cause
The
rpmver_cmp()function correctly implements RPM version comparison per the RPM spec:When comparing
el8eapvsel9eap:[el, 8, eap]vs[el, 9, eap]el=el(equal)8<9(numeric comparison)el8eap < el9eapThis is technically correct per RPM ordering, but semantically wrong for vulnerability correlation:
el7,el8,el9represent different RHEL major versionsel9eappackages does NOT meanel8eappackages are affectedAffected Endpoints
/api/v2/vulnerability/analyze/api/v3/vulnerability/analyze/api/v3/purl/recommend/api/v2/purl/{key}/api/v2/sbom/{id}/advisory/api/v2/vulnerability/{id}Reproduction Steps
Ingest a Red Hat CSAF advisory that contains products for multiple RHEL versions:
curl -X POST http://localhost:8080/api/v2/advisory \ -H "Content-Type: application/json" \ -d @etc/test-data/csaf/cve-2023-33201.jsonQuery for an
el8eappackage:Observe that the response includes vulnerability status and remediations from
el9eapproducts.Test Cases
Tests documenting this issue:
Branch:
test/rpm-os-release-suffix-matchingTest file:
modules/ingestor/tests/version/rpmver.rstest_rpmver_cmp_release_suffix_different_osel7 < el8 < el9per RPM spectest_rpmver_version_matches_cross_os_release_bug< el9eaptest_rpmver_same_version_different_os_releasestest_rpmver_version_matches_exact_with_os_suffixtest_rpmver_version_matches_same_os_releaseRun the tests with:
cargo test -p trustify-module-ingestor --test ingestor test_rpmverPotential Solutions
Option 1: Enhanced Version Range Matching
Modify
rpmver_version_matchesto detect and handle OS release suffixes:Pros: Targeted fix, minimal changes
Cons: RPM-specific, may miss edge cases
Option 2: Normalize OS Release in Base PURL
Extract OS release into PURL namespace during ingestion.
Option 3: Add OS Release Qualifier
Store OS release as a qualifier and include it in matching.
Option 4: Separate Version and Release Fields
Store RPM version and release separately in the database.
Related
References
etc/test-data/csaf/cve-2023-33201.json