-
Notifications
You must be signed in to change notification settings - Fork 35
Description
SBOM Deletion Concurrency Race Condition Analysis
Overview
This document analyzes a potential race condition that can occur when deleting SBOMs concurrently in a multi-threaded environment. The issue involves orphaned PURL (Package URL) records being left behind when two or more SBOMs referencing the same qualified PURL are deleted simultaneously.
Problem Description
Scenario
Consider the following scenario:
- SBOM1 and SBOM2 both reference the same
qualified_purl A - Two concurrent transactions attempt to delete both SBOMs
- Each transaction executes in a separate thread/connection
Expected Behavior
When both SBOMs are deleted, the qualified_purl A should be cleaned up since it's no longer referenced by any SBOM.
Actual Behavior
Due to a race condition, qualified_purl A may become orphaned data (garbage) even though all its references have been removed.
Timeline Analysis
The following timeline demonstrates how the race condition occurs:
Time | Transaction 1 (Delete SBOM1) | Transaction 2 (Delete SBOM2)
-----|------------------------------------------|------------------------------------------
T1 | Capture qualified_purl_ids = [A] |
T2 | | Capture qualified_purl_ids = [A]
T3 | Delete SBOM1 (CASCADE removes refs) |
T4 | | Delete SBOM2 (CASCADE removes refs)
T5 | Execute GC query - sees SBOM2's ref |
| (not yet committed, still visible) |
T6 | | Execute GC query - sees SBOM1's ref
| | (not yet committed, still visible)
T7 | Commit |
T8 | | Commit
Detailed Analysis
Step 1: Capture Qualified PURL IDs
Both transactions capture the qualified PURL IDs before deletion:
// Line 112-119 in sbom.rs
let qualified_purl_ids: Vec<Uuid> = sbom_package_purl_ref::Entity::find()
.select_only()
.column(sbom_package_purl_ref::Column::QualifiedPurlId)
.filter(sbom_package_purl_ref::Column::SbomId.eq(id))
.into_tuple()
.all(connection)
.await?;- T1: Transaction 1 captures
qualified_purl_ids = [A] - T2: Transaction 2 captures
qualified_purl_ids = [A]
Step 2: Delete SBOM with CASCADE
Both transactions delete their respective SBOMs:
-- Line 126-128 in sbom.rs
DELETE FROM sbom WHERE sbom_id=$1 RETURNING source_document_idThe CASCADE constraint automatically deletes related records:
-
sbom_packageentries -
sbom_package_purl_refentries (references to qualified PURLs) -
T3: Transaction 1 deletes SBOM1, removing its reference to PURL A
-
T4: Transaction 2 deletes SBOM2, removing its reference to PURL A
Step 3: Execute Garbage Collection Query
Both transactions execute the GC query to clean up orphaned PURLs:
-- From gc_purls_after_sbom_deletion.sql
WHERE NOT EXISTS (
-- Check if still referenced by other SBOMs
SELECT 1 FROM sbom_package_purl_ref sppr
WHERE sppr.qualified_purl_id = sq.id
)At T5 (Transaction 1's GC query):
- SBOM1's reference to A has been deleted (T3)
- But SBOM2's deletion is not yet committed (T4)
- Under READ COMMITTED isolation, Transaction 1 still sees SBOM2's reference to A
- Conclusion: A still has references → Do not delete A
At T6 (Transaction 2's GC query):
- SBOM2's reference to A has been deleted (T4)
- But SBOM1's deletion is not yet committed (T7)
- Under READ COMMITTED isolation, Transaction 2 still sees SBOM1's reference to A
- Conclusion: A still has references → Do not delete A
Step 4: Commit Transactions
- T7: Transaction 1 commits
- T8: Transaction 2 commits
Final Result
After both transactions commit:
- All references to
qualified_purl Ainsbom_package_purl_reftable are deleted qualified_purl Aitself still exists- A becomes orphaned data (garbage)
Probability of Occurrence
The likelihood of this race condition occurring depends on:
-
Frequency of Concurrent Deletions
- Higher if the system frequently processes multiple SBOM deletion requests simultaneously
- More likely in high-traffic environments
-
Number of Shared Qualified PURLs
- Higher if multiple SBOMs frequently reference the same packages
- Common in software supply chains where the same dependencies appear across multiple SBOMs
-
Timing of Requests
- Requires two deletion requests to arrive within a narrow time window
- More likely with high concurrency and slow database operations
Metadata
Metadata
Assignees
Labels
Type
Projects
Status