# CVE-2020-6820: Firefox use-after-free in Cache
*Maddie Stone, Project Zero (Originally posted on [Project Zero blog](https://googleprojectzero.blogspot.com/p/rca.html) 2020-08-05)*

## The Basics

**Disclosure or Patch Date:** 03 April 2020

**Product:** Mozilla Firefox

**Advisory:** https://www.mozilla.org/en-US/security/advisories/mfsa2020-11/

**Affected Versions:** pre-74.0.1

**First Patched Version:** Firefox 74.0.1 and and Firefox ESR 68.6.1

**Issue/Bug Report:** https://bugzilla.mozilla.org/show_bug.cgi?id=1626728

**Patch CL:** https://hg.mozilla.org/mozilla-central/rev/6639deb894172375b05d6791f5f8c7d53ca79723

**Bug-Introducing CL:** Unknown

**Reporter(s):** Francisco Alonso [@revskills](https://twitter.com/revskills) working with Javier Marcos of [@JMPSec](https://twitter.com/JMPSec)

## The Code

**Proof-of-concept:** N/A

**Exploit sample:** N/A

**Did you have access to the exploit sample when doing the analysis?** No

## The Vulnerability

**Bug class:** use-after-free (UaF)

**Vulnerability details:**

There is a UaF of the `CacheStreamControlParent` when closing its last open read stream. The read stream is the response returned to the context process from a cache query. If the close or abort command is received while any read streams are still open, it triggers `StreamList::CloseAll`. If the `StreamControl` (must be Parent to get a UAF in browser process, the Child would only provide in renderer) still has `ReadStream`s when `StreamList::CloseAll` is called, then this will cause the `CacheStreamControlParent` to be freed. The `mId` member of the `CacheStreamControl` parent is then subsequently accessed, causing the use-after-free. The execution flow is shown below.

```
StreamList::CloseAll /* PATCHED FUNCTION */
  CacheStreamControlParent::CloseAll
    CacheStreamControlParent::NotifyCloseAll
      StreamControl::CloseAllReadStreams
        For each stream: 
          ReadStream::Inner::CloseStream
            ReadStream::Inner::Close
              ReadStream::Inner::NoteClosed
                …
                StreamControl::NoteClosed
                  StreamControl::ForgetReadStream		
                    CacheStreamControlParent/Child::NoteClosedAfterForget
                      CacheStreamControlParent::RecvNoteClosed
                        StreamList::NoteClosed
                          If StreamList is empty && mStreamControl:
                           CacheStreamControlParent::Shutdown
                             Send__delete(this) /* FREED HERE */
    PCacheStreamControlParent::SendCloseAll /* USED HERE IN CALL TO Id() */
```

I did not get a working trigger for this vulnerability that didn’t involve shutting down the process. The difficulty is getting there to still be a `ReadStream` when `StreamList::CloseAll` is closed. It seems that others, including Firefox engineers, also haven’t found a way to trigger this bug and similar bugs that require winning this race condition that doesn’t involve shut down ([here](https://bugzilla.mozilla.org/show_bug.cgi?id=1626728#c15), [here](https://bugzilla.mozilla.org/show_bug.cgi?id=1507180), and [here](https://bugzilla.mozilla.org/show_bug.cgi?id=1368273#c9)). If you have found a way to trigger without shutting down the process, please share. 

**Patch analysis:**

The patch fixes the vulnerability by setting `mStreamControl` to nullptr prior to calling `CacheStreamControlParent::CloseAll`. This then prevents the call to `CacheStreamControlParent::Shutdown` and the freeing of the `CacheStreamControlParent`.

**Thoughts on how this vuln might have been found _(fuzzing, code auditing, variant analysis, etc.)_:**

It seems likely that this vulnerability could have been found by:
1. Manual code auditing/variant analysis after seeing the patch for [Bug 1507180](https://bugzilla.mozilla.org/show_bug.cgi?id=1507180) which is a similar UaF in the same module, or
2. Fuzzing IPDL interfaces. Fuzzing may be slightly more likely due to the difficulty that even Firefox engineers have had in reproducing this bug.

**(Historical/present/future) context of bug:** 

* CVE-2020-6820 was used as a chain with CVE-2020-6819 ([bug report](https://bugzilla.mozilla.org/show_bug.cgi?id=1620818)), where 6819 is the renderer exploit and 6820 is the sandbox escape. According to [this comment](https://bugzilla.mozilla.org/show_bug.cgi?id=1620818#c6), these two vulnerabilities were found by visiting a URL known to be affiliated with a threat actor, (assumedly) using ASAN Firefox builds. 
* [Bug 1507180](https://bugzilla.mozilla.org/show_bug.cgi?id=1507180) is a very similar UaF to this vulnerability. It was patched in December 2019 with an explanatory comment. The bug with ASAN crash wasn’t derestricted until June 2020, but someone may have root caused the bug based on the patches and found this other variant. 
It’s interesting that engineers for both [this vulnerability](https://bugzilla.mozilla.org/show_bug.cgi?id=1626728#c15) and the previous [bug 1507180](https://bugzilla.mozilla.org/show_bug.cgi?id=1507180#c10) struggled to reproduce the crashes, this likely led to the “race condition” wording of the advisory. 

## The Exploit

**Is the exploit method known?** N/A

**Exploit method:** Unknown

## The Next Steps

### Variant analysis

**Areas/approach for variant analysis (and why):** The IPDL interface for the Cache subsystem is very complex. Since there have already been two very similar bugs found in the closing process involving streams, it would be worthwhile to look for other use-after-frees here too.

**Found variants:**

* [Bug 165115](https://bugzilla.mozilla.org/show_bug.cgi?id=1655115): UAF in `StreamControl::CloseReadStreams`, but the code is dead code. FF removed it.

### Structural improvements

Since the vulnerability was disclosed, Firefox has already begun reducing the use of raw pointers in the Cache module. https://bugzilla.mozilla.org/show_bug.cgi?id=1627892

### 0-day detection methods

Firefox has crash logs for common crashes [here](https://crash-stats.mozilla.org/topcrashers/?product=Firefox&version=79.0). We could potentially find failed exploitation attempts in these crash logs.  

## Other References 
