Closed Bug 1848833 Opened 2 years ago Closed 2 years ago

Use-after-free crash in [@ nsTArray_Impl<T>::AppendElementInternal<T> | nsTArray<T>::AppendElement | mozilla::net::nsHttpChannel::OnCacheEntryCheck]

Categories

(Core :: Networking: Cache, defect, P2)

Unspecified
Windows 11
defect

Tracking

()

RESOLVED FIXED
120 Branch
Tracking Status
firefox-esr102 --- wontfix
firefox-esr115 119+ fixed
firefox117 --- wontfix
firefox118 --- wontfix
firefox119 + fixed
firefox120 --- fixed

People

(Reporter: mccr8, Assigned: jesup)

Details

(Keywords: crash, csectype-uaf, sec-high, Whiteboard: [necko-triaged][necko-priority-queue][adv-main119+r][adv-ESR115.4+r])

Crash Data

Attachments

(1 file)

Crash report: https://crash-stats.mozilla.org/report/index/5c96af1c-f48c-419d-8e0c-c00ac0230809

Reason: EXCEPTION_ACCESS_VIOLATION_READ

Top 10 frames of crashing thread:

0  xul.dll  nsTArray_Impl<nsTString<char>, nsTArrayInfallibleAllocator>::AppendElementInternal<nsTArrayInfallibleAllocator, const nsTString<char>&>  xpcom/ds/nsTArray.h:2693
1  xul.dll  nsTArray<nsTString<char> >::AppendElement  xpcom/ds/nsTArray.h:2829
1  xul.dll  mozilla::net::nsHttpChannel::OnCacheEntryCheck  netwerk/protocol/http/nsHttpChannel.cpp:3978
2  xul.dll  mozilla::net::CacheEntry::InvokeCallback  netwerk/cache2/CacheEntry.cpp:746
3  xul.dll  mozilla::net::CacheEntry::InvokeCallbacks  netwerk/cache2/CacheEntry.cpp:674
4  xul.dll  mozilla::net::CacheEntry::InvokeCallbacks  netwerk/cache2/CacheEntry.cpp:616
5  xul.dll  mozilla::net::CacheEntry::OnFileReady  netwerk/cache2/CacheEntry.cpp:501
6  xul.dll  mozilla::net::CacheFile::OnMetadataRead  netwerk/cache2/CacheFile.cpp:645
7  xul.dll  mozilla::net::CacheFileMetadata::OnDataRead::<lambda_6>::operator const  netwerk/cache2/CacheFileMetadata.cpp:618
7  xul.dll  mozilla::ScopeExit<`lambda at /builds/worker/checkouts/gecko/netwerk/cache2/CacheFileMetadata.cpp:616:59'>::~ScopeExit  mfbt/ScopeExit.h:106

17 crashes like this in the last 6 months. They look like they are on the cache thread. Maybe there's a missing mutex, or this callback needs a stronger reference? I haven't looked at the code at all. It seems a bit suspicious that in this gigantic function the UAFs are happening on the access to this specific field mRedirectedCachekeys.

Much lower volume, but the stack looks similar for this signature [@ nsTArray_base<T>::Length | nsTArray_Impl<T>::AppendElementInternal<T> | nsTArray<T>::AppendElement | mozilla::net::nsHttpChannel::OnCacheEntryCheck ]: bp-6624433a-01ed-47ba-aec6-8e3680230803

Crash Signature: [@ nsTArray_Impl<T>::AppendElementInternal<T> | nsTArray<T>::AppendElement | mozilla::net::nsHttpChannel::OnCacheEntryCheck] → [@ nsTArray_Impl<T>::AppendElementInternal<T> | nsTArray<T>::AppendElement | mozilla::net::nsHttpChannel::OnCacheEntryCheck] [@ nsTArray_base<T>::Length | nsTArray_Impl<T>::AppendElementInternal<T> | nsTArray<T>::AppendElement | mozilla::net::nsHttpChanne…

Another rarer variation [@ nsTArray_Impl<T>::AppendElementInternal<T> | nsTArray<T>::AppendElement<T> | mozilla::net::nsHttpChannel::OnCacheEntryCheck ]: bp-e903b4ce-d7e7-41db-8972-9870b0230810

Crash Signature: mozilla::net::nsHttpChannel::OnCacheEntryCheck ] → mozilla::net::nsHttpChannel::OnCacheEntryCheck ] [@ nsTArray_Impl<T>::AppendElementInternal<T> | nsTArray<T>::AppendElement<T> | mozilla::net::nsHttpChannel::OnCacheEntryCheck ]
Severity: -- → S2
Priority: -- → P2
Whiteboard: [necko-triaged][necko-priority-queue]

Given:

    if (!mRedirectedCachekeys) {
      mRedirectedCachekeys = MakeUnique<nsTArray<nsCString>>();
    } else if (mRedirectedCachekeys->Contains(cacheKey)) {
      doValidation = true;
    }

    // Append cacheKey if not in the chain already
    if (!doValidation) {
      mRedirectedCachekeys->AppendElement(cacheKey); *** crash address

We must have had an mRedirectedCachekeys, and it didn't contain the new cacheKey. However, mRedirectedCachekeys is a UniquePtr<>, and so far as I can tell it can only get created modified in this code (which seems good), or when we do SetupReplacementChannel, which transfers the chain over from another HttpChannel:

      rv = httpInternal->SetCacheKeysRedirectChain(
          mRedirectedCachekeys.release());

and we can clear it:

  inline void CleanRedirectCacheChainIfNecessary() {
    mRedirectedCachekeys = nullptr;
  }

So how does it end up pointing to a released nsTArray? I don't see any obvious multithread access here. If something were to delete the entire HttpChannel while we're in it (from another thread presumably) maybe it's possible. Maybe. But I would expect a lot of failures in lots of different places in that case, not just here

If mRedirectedCachekeys does get released by SetupReplacementChannel, the only way I see us calling OnCacheEntryCheck after that point is via Race-Cache-With-Network. But if that's the case, I would have expected us to exit early here.

Assignee: nobody → rjesup

mRedirectedCachekeys can only be set from MakeUnique<>, or from SetCacheKeysRedirectChain(), which is only called via SetCacheKeysRedirectChain(mRedirectedCacheKeys.release()). So there should be no reference to the mRedirectedCacheKeys floating around to let it be deleted.

So, the problem is almost certainly that we're accessing mRedirectedCacheKeys on both the Cache2 IO thread and on MainThread (for the call to SetCacheKeysRedirectChain()). I'll add a mutex

Comment on attachment 9354169 [details]
Bug 1848833: Clean up mRedirectedCacheKeys r=valentin!

Security Approval Request

  • How easily could an exploit be constructed based on the patch?: Hard, but probably not impossible
  • Do comments in the patch, the check-in comment, or tests included in the patch paint a bulls-eye on the security problem?: Yes
  • Which older supported branches are affected by this flaw?: all
  • If not all supported branches, which bug introduced the flaw?: None
  • Do you have backports for the affected branches?: No
  • If not, how different, hard to create, and risky will they be?: Trivial
  • How likely is this patch to cause regressions; how much testing does it need?: Extremely unlikely
  • Is Android affected?: Yes

Beta/Release Uplift Approval Request

  • User impact if declined: Security risk
  • Is this code covered by automated tests?: Yes
  • Has the fix been verified in Nightly?: No
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: None
  • Risk to taking this patch: Low
  • Why is the change risky/not risky? (and alternatives if risky): DataMutex locking of a var like this is safe; no possible deadlocks.
  • String changes made/needed: none
  • Is Android affected?: Yes
Attachment #9354169 - Flags: sec-approval?
Attachment #9354169 - Flags: approval-mozilla-beta?
Attachment #9354169 - Flags: approval-mozilla-esr115?

Comment on attachment 9354169 [details]
Bug 1848833: Clean up mRedirectedCacheKeys r=valentin!

Approved to land and uplift

Attachment #9354169 - Flags: sec-approval?
Attachment #9354169 - Flags: sec-approval+
Attachment #9354169 - Flags: approval-mozilla-esr115?
Attachment #9354169 - Flags: approval-mozilla-esr115+
Attachment #9354169 - Flags: approval-mozilla-beta?
Attachment #9354169 - Flags: approval-mozilla-beta+
Pushed by rvandermeulen@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/97dc7be3b93c Clean up mRedirectedCacheKeys r=valentin,necko-reviewers
Group: network-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 2 years ago
Resolution: --- → FIXED
Target Milestone: --- → 120 Branch
QA Whiteboard: [post-critsmash-triage]
Flags: qe-verify-
Whiteboard: [necko-triaged][necko-priority-queue] → [necko-triaged][necko-priority-queue][adv-main119+r]
Whiteboard: [necko-triaged][necko-priority-queue][adv-main119+r] → [necko-triaged][necko-priority-queue][adv-main119+r][adv-ESR115.4+r]

Bulk-unhiding security bugs fixed in Firefox 119-121 (Fall 2023). Use "moo-doctrine-subsidy" to filter

Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: