Bug 2373046 (CVE-2025-48945, GHSA-5qpg-rh4j-qp35)

Summary: CVE-2025-48945 pycares: pycares Channel Use-After-Free
Product: [Other] Security Response Reporter: OSIDB Bzimport <bzimport>
Component: vulnerabilityAssignee: Product Security DevOps Team <prodsec-dev>
Status: NEW --- QA Contact:
Severity: medium Docs Contact:
Priority: medium    
Version: unspecifiedCC: anthomas, dranck, ehelms, ggainey, haoli, hkataria, jajackso, jcammara, jmitchel, jneedle, jtanner, juwatts, kegrant, koliveir, kshier, lbrazdil, mabashia, mhulan, mminar, nmoumoul, osousa, pbraun, pcreech, rbiba, rchan, shvarugh, simaishi, smallamp, smcdonal, sskracic, stcannon, teagle, tfister, thavo, tpfromme, yguenane
Target Milestone: ---Keywords: Security
Target Release: ---   
Hardware: All   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: ---
Doc Text:
A flaw was found in pycares. A use-after-free condition arises when a Channel object is garbage collected while associated DNS queries remain pending, leading to a fatal Python error and interpreter crash. This vulnerability allows a local attacker to trigger the crash by initiating DNS queries and then manipulating the object lifetime. This condition causes a denial of service resulting from interpreter termination.
Story Points: ---
Clone Of: Environment:
Last Closed: Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On: 2373112    
Bug Blocks:    

Description OSIDB Bzimport 2025-06-16 18:02:39 UTC
## Summary

pycares is vulnerable to a use-after-free condition that occurs when a Channel object is garbage collected while DNS queries are still pending. This results in a fatal Python error and interpreter crash.

## Details

### Root Cause

The vulnerability stems from improper handling of callback references when the Channel object is destroyed:

1. When a DNS query is initiated, pycares stores a callback reference using `ffi.new_handle()`
2. If the Channel object is garbage collected while queries are pending, the callback references become invalid
3. When c-ares attempts to invoke the callback, it accesses freed memory, causing a fatal error

This issue was much more likely to occur when using `event_thread=True` but could happen without it under the right circumstances.

### Technical Details

The core issue is a race condition between Python's garbage collector and c-ares's callback execution:

1. When `__del__` is called from within a c-ares callback context, we cannot immediately call `ares_destroy()` because c-ares is still executing code after the callback returns
2. c-ares needs to execute cleanup code after our Python callback returns (specifically at lines 1422-1429 in ares_process.c)
3. If we destroy the channel too quickly, c-ares accesses freed memory

### Impact

Applications using `pycares` can be crashed remotely by triggering DNS queries that result in `Channel` objects being garbage collected before query completion. This is particularly problematic in scenarios where:

- Channel objects are created per-request
- Multiple failed DNS queries are processed rapidly
- The application doesn't properly manage Channel lifecycle

The error manifests as:
```
Fatal Python error: b_from_handle: ffi.from_handle() detected that the address passed points to garbage
```

## Fix

The vulnerability has been fixed in pycares 4.9.0 by implementing a safe channel destruction mechanism

## Mitigation

### For Application Developers

1. **Upgrade to pycares >= 4.9.0** - This version includes the fix and requires no code changes
2. **Best practices** (optional but recommended):
   ```python
   # Explicit cleanup
   channel.close()
   
   # Or use context manager
   with pycares.Channel() as channel:
       # ... use channel ...
   # Automatically closed
   ```
3. **Avoid creating Channel objects per-request** - Prefer long-lived instances for better performance and safety

The fix is completely transparent - no API changes or code modifications are required.

## Credit

This vulnerability was reported by @vEpiphyte through the aio-libs security program.