Talos Vulnerability Report

TALOS-2021-1345

Mozilla Firefox MediaCacheStream::NotifyDataReceived use-after-free vulnerability

August 10, 2021
CVE Number

CVE-2021-29985

Summary

A potential remote code execution vulnerability exists in the MediaCacheStream::NotifyDataReceived method of Mozilla Firefox 89.0.3 x64. A specially-crafted web page can cause a use-after-free vulnerability potentially resulting in a code execution. A victim needs to visit a malicious webpage to trigger this vulnerability.

Tested Versions

Mozilla Firefox Mozilla Firefox 89.0.3 x64

Product URLs

https://www.mozilla.org/en-US/firefox/new

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-416 - Use After Free

Details

Mozilla Firefox is one of the most popular web browsers in the world, available for a variety of different platforms : Windows, Linux, OSX, Android and more. Its active development ensures support for the newest web technologies like HTML5 or CSS3.

This vulnerability is related to the nsBufferedStream component, which is part of the Stream buffering functionality. A malicious web page can lead to a race condition situation, which can cause a use-after-free vulnerability and potential remote code execution.

Tracking an nsBufferedStream object life cycle, we can see that there is an allocation made :

previously allocated by thread T0 (Web Content) here:
	#0 0x55eb6b69ca7d in malloc /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
	#1 0x7f031b4f9e2e in operator new[] /builds/worker/workspace/obj-build/dist/include/mozilla/cxxalloc.h:47:10
	#2 0x7f031b4f9e2e in nsBufferedStream::Init(nsISupports*, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:73:13
	#3 0x7f031b4fc05c in nsBufferedInputStream::Init(nsIInputStream*, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:335:35
	#4 0x7f031b5303ba in NS_NewBufferedInputStream(nsIInputStream**, already_AddRefed<nsIInputStream>, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsNetUtil.cpp:1330:14
	#5 0x7f031b52c483 in nsInputStreamPump::CreateBufferedStreamIfNeeded() /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:672:17
	#6 0x7f031b52c0c8 in nsInputStreamPump::PeekStream(void (*)(void*, unsigned char const*, unsigned int), void*) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:94:17
	#7 0x7f031b4ed088 in nsBaseChannel::OnStartRequest(nsIRequest*) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp:827:14
	#8 0x7f031b52ec0e in nsInputStreamPump::OnStateStart() /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:481:21
	#9 0x7f031b52e337 in nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:390:21
	#10 0x7f03208e4d63 in mozilla::dom::BlobURLInputStream::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/dom/file/uri/BlobURLInputStream.cpp:271:20
	#11 0x7f03208d8f84 in mozilla::(anonymous namespace)::InputStreamCallbackRunnable::Run() /builds/worker/checkouts/gecko/dom/file/ipc/RemoteLazyInputStream.cpp:54:16
	#12 0x7f031b2439cc in mozilla::SchedulerGroup::Runnable::Run() /builds/worker/checkouts/gecko/xpcom/threads/SchedulerGroup.cpp:143:20
	#13 0x7f031b24d16a in mozilla::RunnableTask::Run() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:473:16
	#14 0x7f031b24a4f8 in mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:757:26
	#15 0x7f031b248837 in mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:612:15
	#16 0x7f031b248c8d in mozilla::TaskController::ProcessPendingMTTask(bool) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:396:36
	#17 0x7f031b253471 in operator() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:135:37
	#18 0x7f031b253471 in mozilla::detail::RunnableFunction<mozilla::TaskController::InitializeInternal()::$_3>::Run() /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.h:534:5
	#19 0x7f031b26cb31 in nsThread::ProcessNextEvent(bool, bool*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1155:16
	#20 0x7f031b27649c in NS_ProcessNextEvent(nsIThread*, bool) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:548:10
	#21 0x7f031c44968f in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:87:21

Which is caused by a call to URL.createObjectURL inside the MediaRecorder_onstop event handler:

Line 1	function MediaRecorder_onstop(e)
Line 2	{
Line 3		let blob = new Blob(chunks,{ 'type' : 'audio/ogg; codecs=opus' });
Line 4		audioElement.src = URL.createObjectURL(blob);
Line 5		audioElement.play(); 
Line 6	}	

Further this nsBufferedStream object gets deallocated:

0x62100323e900 is located 0 bytes inside of 4096-byte region [0x62100323e900,0x62100323f900)
freed by thread T0 (Web Content) here:
	#0 0x55eb6b69c7fd in free /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3
	#1 0x7f031b4f9bbd in operator delete[] /builds/worker/workspace/obj-build/dist/include/mozilla/cxxalloc.h:60:10
	#2 0x7f031b4f9bbd in nsBufferedStream::Close() /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:84:5
	#3 0x7f031b4fec52 in Close /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:391:21
	#4 0x7f031b4fec52 in CloseWithStatus /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:671:67
	#5 0x7f031b4fec52 in non-virtual thunk to nsBufferedInputStream::CloseWithStatus(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp
	#6 0x7f031b52d41d in nsInputStreamPump::Cancel(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:210:19
	#7 0x7f031b4e9618 in nsBaseChannel::Cancel(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp:399:15
	#8 0x7f031b4e968c in non-virtual thunk to nsBaseChannel::Cancel(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp
	#9 0x7f0320bec2bd in mozilla::ChannelMediaResource::CloseChannel() /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:631:15
	#10 0x7f0320befe92 in mozilla::ChannelMediaResource::Close() /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:575:5
	#11 0x7f0320be55ef in mozilla::ChannelMediaDecoder::Shutdown() /builds/worker/checkouts/gecko/dom/media/ChannelMediaDecoder.cpp:224:40
	#12 0x7f0320a2d7c0 in mozilla::dom::HTMLMediaElement::ShutdownDecoder() /builds/worker/checkouts/gecko/dom/html/HTMLMediaElement.cpp:2206:13
	#13 0x7f0320a4ba06 in mozilla::dom::HTMLMediaElement::~HTMLMediaElement() /builds/worker/checkouts/gecko/dom/html/HTMLMediaElement.cpp:4208:5
	#14 0x7f032097ca0d in mozilla::dom::HTMLAudioElement::~HTMLAudioElement() /builds/worker/checkouts/gecko/dom/html/HTMLAudioElement.cpp:58:1
	#15 0x7f031e5e92fd in nsIContent::Destroy() /builds/worker/checkouts/gecko/dom/base/FragmentOrElement.cpp:150:1
	#16 0x7f031b0bef72 in SnowWhiteKiller::~SnowWhiteKiller() /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:2417:7
	#17 0x7f031b0bd73b in nsPurpleBuffer::RemoveSkippable(nsCycleCollector*, js::SliceBudget&, bool, bool, void (*)()) /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:2585:1
	#18 0x7f031b0bf79f in nsCycleCollector::ForgetSkippable(js::SliceBudget&, bool, bool) /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:2653:14
	#19 0x7f031b0c7f6d in nsCycleCollector_forgetSkippable(js::SliceBudget&, bool, bool) /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:3865:21
	#20 0x7f031e816e79 in FireForgetSkippable(bool, mozilla::TimeStamp) /builds/worker/checkouts/gecko/dom/base/nsJSEnvironment.cpp:1141:3
	#21 0x7f031e81831c in CCRunnerFired(mozilla::TimeStamp) /builds/worker/checkouts/gecko/dom/base/nsJSEnvironment.cpp:1644:9
	#22 0x7f031b2364ea in operator() /builds/worker/fetches/clang/bin/../lib/gcc/x86_64-unknown-linux-gnu/7.4.0/../../../../include/c++/7.4.0/bits/std_function.h:706:14
	#23 0x7f031b2364ea in mozilla::IdleTaskRunner::Run() /builds/worker/checkouts/gecko/xpcom/threads/IdleTaskRunner.cpp:109:14

Notice that nsBufferedStream gets deallocated through the HTMLAudioElement element destruction (audioElement in our code), which might by triggered by one of our fuzzing fuctions or “page switch/reload”.

Because of bad referencing handling, the nsBufferedStream object gets reused during the mozilla::MediaCacheStream::NotifyDataReceived method call:

==54405==ERROR: AddressSanitizer: heap-use-after-free on address 0x62100323e900 at pc 0x55eb6b69bed7 bp 0x7f03072b6a70 sp 0x7f03072b6238
READ of size 4096 at 0x62100323e900 thread T22 (MediaCache)
	#0 0x55eb6b69bed6 in __asan_memcpy /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
	#1 0x7f0320c6d37c in mozilla::MediaCacheStream::NotifyDataReceived(unsigned int, unsigned int, unsigned char const*) /builds/worker/checkouts/gecko/dom/media/MediaCache.cpp:2027:7
	#2 0x7f0320bee366 in mozilla::ChannelMediaResource::CopySegmentToCache(nsIInputStream*, void*, char const*, unsigned int, unsigned int, unsigned int*) /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:409:18
	#3 0x7f031b4fd0ae in nsBufferedInputStream::ReadSegments(nsresult (*)(nsIInputStream*, void*, char const*, unsigned int, unsigned int, unsigned int*), void*, unsigned int, unsigned int*) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:453:12
	#4 0x7f0320bebad5 in OnDataAvailable /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:437:18
	#5 0x7f0320bebad5 in mozilla::ChannelMediaResource::Listener::OnDataAvailable(nsIRequest*, nsIInputStream*, unsigned long, unsigned int) /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:84:21
	#6 0x7f031b4ee028 in nsBaseChannel::OnDataAvailable(nsIRequest*, nsIInputStream*, unsigned long, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp:872:28
	#7 0x7f031b52f2fb in nsInputStreamPump::OnStateTransfer() /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:548:23
	#8 0x7f031b52e347 in nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:393:21
	#9 0x7f031b4ff23b in nsBufferedInputStream::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:724:20
	#10 0x7f03208e4d63 in mozilla::dom::BlobURLInputStream::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/dom/file/uri/BlobURLInputStream.cpp:271:20
	#11 0x7f03208d8f84 in mozilla::(anonymous namespace)::InputStreamCallbackRunnable::Run() /builds/worker/checkouts/gecko/dom/file/ipc/RemoteLazyInputStream.cpp:54:16
	#12 0x7f031b26d379 in nsThread::ProcessNextEvent(bool, bool*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1149:16
	#13 0x7f031b27649c in NS_ProcessNextEvent(nsIThread*, bool) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:548:10
	#14 0x7f031c44ac0a in mozilla::ipc::MessagePumpForNonMainThreads::Run(base::MessagePump::Delegate*) /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:302:20
	#15 0x7f031c35ff11 in RunInternal /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:335:10
	#16 0x7f031c35ff11 in RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:328:3
	#17 0x7f031c35ff11 in MessageLoop::Run() /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:310:3
	#18 0x7f031b267c59 in nsThread::ThreadFunc(void*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:391:10
	#19 0x7f03373bb28e in _pt_root /builds/worker/checkouts/gecko/nsprpub/pr/src/pthreads/ptthread.c:201:5
	#20 0x7f033acc158f in start_thread nptl/pthread_create.c:463:8
	#21 0x7f033a889222 in clone misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Proper heap grooming can give an attacker full control of this use-after-free vulnerability and as a result could allow it to be turned into arbitrary code execution.

Crash Information

[ 4:29:44 AM ] :: AudioBufferSourceNode_handler
[ 4:29:44 AM ] :: MediaStreamAudioDestinationNode_handler
[ 4:29:44 AM ] :: Before setTimeout
[ 4:29:44 AM ] :: SEED g_mainRandom: 2102332452
[ 4:29:45 AM ] :: Its fuzzing time!!!!
[ 4:29:45 AM ] :: SEED : g_fuzzRandom : 146570576
[ 4:29:45 AM ] :: [fuzz_nodes] :: Amount of mutation : 1
[ 4:29:45 AM ] :: Chosen function : fuzz_deleteHTMLElement
[ 4:29:45 AM ] :: ()=>{ document.querySelector(“audio”).src = document.querySelector(“audio”).src; }
[ 4:29:46 AM ] :: MediaRecorder_ondataavailable
[ 4:29:46 AM ] :: Its fuzzing time!!!!
[ 4:29:46 AM ] :: SEED : g_fuzzRandom : 650240019
[ 4:29:46 AM ] :: [fuzz_nodes] :: Amount of mutation : 1
[ 4:29:46 AM ] :: Chosen function : fuzz_spin
[ 4:29:46 AM ] :: MediaRecorder_ondataavailable
[ 4:29:46 AM ] :: Its fuzzing time!!!!
[ 4:29:46 AM ] :: SEED : g_fuzzRandom : 1849907680
[ 4:29:46 AM ] :: [fuzz_nodes] :: Amount of mutation : 1
[ 4:29:46 AM ] :: Chosen function : fuzz_deleteHTMLElement
[ 4:29:46 AM ] :: ()=>{ document.body.removeChild(document.querySelector(“audio”)) }
[ 4:29:46 AM ] :: MediaRecorder_onstop
[ 4:29:46 AM ] :: Its fuzzing time!!!!
[ 4:29:46 AM ] :: SEED : g_fuzzRandom : 1240099704
[ 4:29:46 AM ] :: [fuzz_nodes] :: Amount of mutation : 3
[ 4:29:46 AM ] :: Chosen function : fuzz_deleteRandomNode
[ 4:29:46 AM ] :: Deleting object : AudioBufferSourceNode
[ 4:29:46 AM ] :: Chosen function : fuzz_spin
[ 4:29:46 AM ] :: eventhandler5
[ 4:29:46 AM ] :: [5] Caller name : fuzz_spin
[ 4:29:46 AM ] :: [object Event]
[ 4:29:46 AM ] :: ended
[ 4:29:47 AM ] :: Chosen function : fuzz_deleteHTMLElement
[ 4:29:47 AM ] :: ()=>{ document.querySelector(“audio”).src = randStr(); }
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: [object AnimationPlaybackEvent]
[ 4:29:47 AM ] :: finish
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: [object AnimationPlaybackEvent]
[ 4:29:47 AM ] :: finish
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: [object AnimationPlaybackEvent]
[ 4:29:47 AM ] :: finish
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: [object AnimationPlaybackEvent]
[ 4:29:47 AM ] :: finish
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: [object AnimationPlaybackEvent]
[ 4:29:47 AM ] :: finish
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: [object AnimationPlaybackEvent]
[ 4:29:47 AM ] :: finish
[ 4:29:47 AM ] :: eventhandler5
[ 4:29:47 AM ] :: [object AnimationPlaybackEvent]
[ 4:29:47 AM ] :: finish
[ 4:29:47 AM ] :: eventhandler2
[ 4:29:47 AM ] :: [object IntersectionObserverEntry]
[ 4:29:47 AM ] :: undefined
[ 4:29:47 AM ] :: eventhandler2

(….)

==54405==ERROR: AddressSanitizer: heap-use-after-free on address 0x62100323e900 at pc 0x55eb6b69bed7    bp 0x7f03072b6a70 sp 0x7f03072b6238
READ of size 4096 at 0x62100323e900 thread T22 (MediaCache)
	#0 0x55eb6b69bed6 in __asan_memcpy /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3
	#1 0x7f0320c6d37c in mozilla::MediaCacheStream::NotifyDataReceived(unsigned int, unsigned int, unsigned char const*) /builds/worker/checkouts/gecko/dom/media/MediaCache.cpp:2027:7
	#2 0x7f0320bee366 in mozilla::ChannelMediaResource::CopySegmentToCache(nsIInputStream*, void*, char const*, unsigned int, unsigned int, unsigned int*) /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:409:18
	#3 0x7f031b4fd0ae in nsBufferedInputStream::ReadSegments(nsresult (*)(nsIInputStream*, void*, char const*, unsigned int, unsigned int, unsigned int*), void*, unsigned int, unsigned int*) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:453:12
	#4 0x7f0320bebad5 in OnDataAvailable /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:437:18
	#5 0x7f0320bebad5 in mozilla::ChannelMediaResource::Listener::OnDataAvailable(nsIRequest*, nsIInputStream*, unsigned long, unsigned int) /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:84:21
	#6 0x7f031b4ee028 in nsBaseChannel::OnDataAvailable(nsIRequest*, nsIInputStream*, unsigned long, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp:872:28
	#7 0x7f031b52f2fb in nsInputStreamPump::OnStateTransfer() /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:548:23
	#8 0x7f031b52e347 in nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:393:21
	#9 0x7f031b4ff23b in nsBufferedInputStream::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:724:20
	#10 0x7f03208e4d63 in mozilla::dom::BlobURLInputStream::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/dom/file/uri/BlobURLInputStream.cpp:271:20
	#11 0x7f03208d8f84 in mozilla::(anonymous namespace)::InputStreamCallbackRunnable::Run() /builds/worker/checkouts/gecko/dom/file/ipc/RemoteLazyInputStream.cpp:54:16
	#12 0x7f031b26d379 in nsThread::ProcessNextEvent(bool, bool*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1149:16
	#13 0x7f031b27649c in NS_ProcessNextEvent(nsIThread*, bool) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:548:10
	#14 0x7f031c44ac0a in mozilla::ipc::MessagePumpForNonMainThreads::Run(base::MessagePump::Delegate*) /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:302:20
	#15 0x7f031c35ff11 in RunInternal /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:335:10
	#16 0x7f031c35ff11 in RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:328:3
	#17 0x7f031c35ff11 in MessageLoop::Run() /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:310:3
	#18 0x7f031b267c59 in nsThread::ThreadFunc(void*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:391:10
	#19 0x7f03373bb28e in _pt_root /builds/worker/checkouts/gecko/nsprpub/pr/src/pthreads/ptthread.c:201:5
	#20 0x7f033acc158f in start_thread nptl/pthread_create.c:463:8
	#21 0x7f033a889222 in clone misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95

0x62100323e900 is located 0 bytes inside of 4096-byte region [0x62100323e900,0x62100323f900)
freed by thread T0 (Web Content) here:
	#0 0x55eb6b69c7fd in free /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3
	#1 0x7f031b4f9bbd in operator delete[] /builds/worker/workspace/obj-build/dist/include/mozilla/cxxalloc.h:60:10
	#2 0x7f031b4f9bbd in nsBufferedStream::Close() /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:84:5
	#3 0x7f031b4fec52 in Close /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:391:21
	#4 0x7f031b4fec52 in CloseWithStatus /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:671:67
	#5 0x7f031b4fec52 in non-virtual thunk to nsBufferedInputStream::CloseWithStatus(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp
	#6 0x7f031b52d41d in nsInputStreamPump::Cancel(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:210:19
	#7 0x7f031b4e9618 in nsBaseChannel::Cancel(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp:399:15
	#8 0x7f031b4e968c in non-virtual thunk to nsBaseChannel::Cancel(nsresult) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp
	#9 0x7f0320bec2bd in mozilla::ChannelMediaResource::CloseChannel() /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:631:15
	#10 0x7f0320befe92 in mozilla::ChannelMediaResource::Close() /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:575:5
	#11 0x7f0320be55ef in mozilla::ChannelMediaDecoder::Shutdown() /builds/worker/checkouts/gecko/dom/media/ChannelMediaDecoder.cpp:224:40
	#12 0x7f0320a2d7c0 in mozilla::dom::HTMLMediaElement::ShutdownDecoder() /builds/worker/checkouts/gecko/dom/html/HTMLMediaElement.cpp:2206:13
	#13 0x7f0320a4ba06 in mozilla::dom::HTMLMediaElement::~HTMLMediaElement() /builds/worker/checkouts/gecko/dom/html/HTMLMediaElement.cpp:4208:5
	#14 0x7f032097ca0d in mozilla::dom::HTMLAudioElement::~HTMLAudioElement() /builds/worker/checkouts/gecko/dom/html/HTMLAudioElement.cpp:58:1
	#15 0x7f031e5e92fd in nsIContent::Destroy() /builds/worker/checkouts/gecko/dom/base/FragmentOrElement.cpp:150:1
	#16 0x7f031b0bef72 in SnowWhiteKiller::~SnowWhiteKiller() /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:2417:7
	#17 0x7f031b0bd73b in nsPurpleBuffer::RemoveSkippable(nsCycleCollector*, js::SliceBudget&, bool, bool, void (*)()) /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:2585:1
	#18 0x7f031b0bf79f in nsCycleCollector::ForgetSkippable(js::SliceBudget&, bool, bool) /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:2653:14
	#19 0x7f031b0c7f6d in nsCycleCollector_forgetSkippable(js::SliceBudget&, bool, bool) /builds/worker/checkouts/gecko/xpcom/base/nsCycleCollector.cpp:3865:21
	#20 0x7f031e816e79 in FireForgetSkippable(bool, mozilla::TimeStamp) /builds/worker/checkouts/gecko/dom/base/nsJSEnvironment.cpp:1141:3
	#21 0x7f031e81831c in CCRunnerFired(mozilla::TimeStamp) /builds/worker/checkouts/gecko/dom/base/nsJSEnvironment.cpp:1644:9
	#22 0x7f031b2364ea in operator() /builds/worker/fetches/clang/bin/../lib/gcc/x86_64-unknown-linux-gnu/7.4.0/../../../../include/c++/7.4.0/bits/std_function.h:706:14
	#23 0x7f031b2364ea in mozilla::IdleTaskRunner::Run() /builds/worker/checkouts/gecko/xpcom/threads/IdleTaskRunner.cpp:109:14

previously allocated by thread T0 (Web Content) here:
	#0 0x55eb6b69ca7d in malloc /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
	#1 0x7f031b4f9e2e in operator new[] /builds/worker/workspace/obj-build/dist/include/mozilla/cxxalloc.h:47:10
	#2 0x7f031b4f9e2e in nsBufferedStream::Init(nsISupports*, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:73:13
	#3 0x7f031b4fc05c in nsBufferedInputStream::Init(nsIInputStream*, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsBufferedStreams.cpp:335:35
	#4 0x7f031b5303ba in NS_NewBufferedInputStream(nsIInputStream**, already_AddRefed<nsIInputStream>, unsigned int) /builds/worker/checkouts/gecko/netwerk/base/nsNetUtil.cpp:1330:14
	#5 0x7f031b52c483 in nsInputStreamPump::CreateBufferedStreamIfNeeded() /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:672:17
	#6 0x7f031b52c0c8 in nsInputStreamPump::PeekStream(void (*)(void*, unsigned char const*, unsigned int), void*) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:94:17
	#7 0x7f031b4ed088 in nsBaseChannel::OnStartRequest(nsIRequest*) /builds/worker/checkouts/gecko/netwerk/base/nsBaseChannel.cpp:827:14
	#8 0x7f031b52ec0e in nsInputStreamPump::OnStateStart() /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:481:21
	#9 0x7f031b52e337 in nsInputStreamPump::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/netwerk/base/nsInputStreamPump.cpp:390:21
	#10 0x7f03208e4d63 in mozilla::dom::BlobURLInputStream::OnInputStreamReady(nsIAsyncInputStream*) /builds/worker/checkouts/gecko/dom/file/uri/BlobURLInputStream.cpp:271:20
	#11 0x7f03208d8f84 in mozilla::(anonymous namespace)::InputStreamCallbackRunnable::Run() /builds/worker/checkouts/gecko/dom/file/ipc/RemoteLazyInputStream.cpp:54:16
	#12 0x7f031b2439cc in mozilla::SchedulerGroup::Runnable::Run() /builds/worker/checkouts/gecko/xpcom/threads/SchedulerGroup.cpp:143:20
	#13 0x7f031b24d16a in mozilla::RunnableTask::Run() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:473:16
	#14 0x7f031b24a4f8 in mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:757:26
	#15 0x7f031b248837 in mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:612:15
	#16 0x7f031b248c8d in mozilla::TaskController::ProcessPendingMTTask(bool) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:396:36
	#17 0x7f031b253471 in operator() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:135:37
	#18 0x7f031b253471 in mozilla::detail::RunnableFunction<mozilla::TaskController::InitializeInternal()::$_3>::Run() /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.h:534:5
	#19 0x7f031b26cb31 in nsThread::ProcessNextEvent(bool, bool*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1155:16
	#20 0x7f031b27649c in NS_ProcessNextEvent(nsIThread*, bool) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:548:10
	#21 0x7f031c44968f in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:87:21

Thread T22 (MediaCache) created by T0 (Web Content) here:
	#0 0x55eb6b6874ea in pthread_create /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_interceptors.cpp:214:3
	#1 0x7f03373ab5b4 in _PR_CreateThread /builds/worker/checkouts/gecko/nsprpub/pr/src/pthreads/ptthread.c:458:14
	#2 0x7f033739c66e in PR_CreateThread /builds/worker/checkouts/gecko/nsprpub/pr/src/pthreads/ptthread.c:533:12
	#3 0x7f031b26a09c in nsThread::Init(nsTSubstring<char> const&) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:609:18
	#4 0x7f031b2741b8 in nsThreadManager::NewNamedThread(nsTSubstring<char> const&, unsigned int, nsIThread**) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadManager.cpp:555:12
	#5 0x7f031b27e421 in NS_NewNamedThread(nsTSubstring<char> const&, nsIThread**, already_AddRefed<nsIRunnable>, unsigned int) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:169:57
	#6 0x7f0320c6181d in NS_NewNamedThread<11> /builds/worker/workspace/obj-build/dist/include/nsThreadUtils.h:85:10
	#7 0x7f0320c6181d in mozilla::MediaCache::GetMediaCache(long, bool) /builds/worker/checkouts/gecko/dom/media/MediaCache.cpp:761:19
	#8 0x7f0320c738a0 in mozilla::MediaCacheStream::Init(long) /builds/worker/checkouts/gecko/dom/media/MediaCache.cpp:2675:17
	#9 0x7f0320bef521 in mozilla::ChannelMediaResource::Open(nsIStreamListener**) /builds/worker/checkouts/gecko/dom/media/ChannelMediaResource.cpp:500:30
	#10 0x7f0320be5fac in mozilla::ChannelMediaDecoder::Load(nsIChannel*, bool, nsIStreamListener**) /builds/worker/checkouts/gecko/dom/media/ChannelMediaDecoder.cpp:260:19
	#11 0x7f0320a526cb in nsresult mozilla::dom::HTMLMediaElement::SetupDecoder<mozilla::ChannelMediaDecoder, nsIChannel*&, bool&, nsIStreamListener**&>(mozilla::ChannelMediaDecoder*, nsIChannel*&, bool&, nsIStreamListener**&) /builds/worker/checkouts/gecko/dom/html/HTMLMediaElement.cpp:4844:27
	#12 0x7f0320a264cd in mozilla::dom::HTMLMediaElement::InitializeDecoderForChannel(nsIChannel*, nsIStreamListener**) /builds/worker/checkouts/gecko/dom/html/HTMLMediaElement.cpp:4927:10
	#13 0x7f0320a249ab in mozilla::dom::HTMLMediaElement::MediaLoadListener::OnStartRequest(nsIRequest*) /builds/worker/checkouts/gecko/dom/html/HTMLMediaElement.cpp:1320:7
	#14 0x7f031be4e996 in mozilla::net::HttpChannelChild::DoOnStartRequest(nsIRequest*, nsISupports*) /builds/worker/checkouts/gecko/netwerk/protocol/http/HttpChannelChild.cpp:594:20
	#15 0x7f031be4d89f in mozilla::net::HttpChannelChild::OnStartRequest(mozilla::net::nsHttpResponseHead const&, bool const&, mozilla::net::nsHttpHeaderArray const&, mozilla::net::HttpChannelOnStartRequestArgs const&) /builds/worker/checkouts/gecko/netwerk/protocol/http/HttpChannelChild.cpp:525:3
	#16 0x7f031c136cd5 in mozilla::net::ChannelEventQueue::FlushQueue() /builds/worker/checkouts/gecko/netwerk/ipc/ChannelEventQueue.cpp:90:12
	#17 0x7f031c183537 in mozilla::net::ChannelEventQueue::ResumeInternal()::CompleteResumeRunnable::Run() /builds/worker/checkouts/gecko/netwerk/ipc/ChannelEventQueue.cpp:148:17
	#18 0x7f031b2439cc in mozilla::SchedulerGroup::Runnable::Run() /builds/worker/checkouts/gecko/xpcom/threads/SchedulerGroup.cpp:143:20
	#19 0x7f031b24d16a in mozilla::RunnableTask::Run() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:473:16
	#20 0x7f031b24a4f8 in mozilla::TaskController::DoExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:757:26
	#21 0x7f031b248837 in mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal(mozilla::detail::BaseAutoLock<mozilla::Mutex&> const&) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:612:15
	#22 0x7f031b248c8d in mozilla::TaskController::ProcessPendingMTTask(bool) /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:396:36
	#23 0x7f031b2534a4 in operator() /builds/worker/checkouts/gecko/xpcom/threads/TaskController.cpp:138:37
	#24 0x7f031b2534a4 in mozilla::detail::RunnableFunction<mozilla::TaskController::InitializeInternal()::$_4>::Run() /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.h:534:5
	#25 0x7f031b26cb31 in nsThread::ProcessNextEvent(bool, bool*) /builds/worker/checkouts/gecko/xpcom/threads/nsThread.cpp:1155:16
	#26 0x7f031b27649c in NS_ProcessNextEvent(nsIThread*, bool) /builds/worker/checkouts/gecko/xpcom/threads/nsThreadUtils.cpp:548:10
	#27 0x7f031c449684 in mozilla::ipc::MessagePump::Run(base::MessagePump::Delegate*) /builds/worker/checkouts/gecko/ipc/glue/MessagePump.cpp:109:5
	#28 0x7f031c35ff11 in RunInternal /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:335:10
	#29 0x7f031c35ff11 in RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:328:3
	#30 0x7f031c35ff11 in MessageLoop::Run() /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:310:3
	#31 0x7f0322781f37 in nsBaseAppShell::Run() /builds/worker/checkouts/gecko/widget/nsBaseAppShell.cpp:137:27
	#32 0x7f0326145f4f in XRE_RunAppShell() /builds/worker/checkouts/gecko/toolkit/xre/nsEmbedFunctions.cpp:906:20
	#33 0x7f031c35ff11 in RunInternal /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:335:10
	#34 0x7f031c35ff11 in RunHandler /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:328:3
	#35 0x7f031c35ff11 in MessageLoop::Run() /builds/worker/checkouts/gecko/ipc/chromium/src/base/message_loop.cc:310:3
	#36 0x7f0326145813 in XRE_InitChildProcess(int, char**, XREChildData const*) /builds/worker/checkouts/gecko/toolkit/xre/nsEmbedFunctions.cpp:738:34
	#37 0x55eb6b6cf24d in content_process_main(mozilla::Bootstrap*, int, char**) /builds/worker/checkouts/gecko/browser/app/../../ipc/contentproc/plugin-container.cpp:57:28
	#38 0x55eb6b6cf671 in main /builds/worker/checkouts/gecko/browser/app/nsBrowserApp.cpp:309:18
	#39 0x7f033a798cb1 in __libc_start_main csu/../csu/libc-start.c:314:16

SUMMARY: AddressSanitizer: heap-use-after-free /builds/worker/fetches/llvm-project/llvm/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:22:3 in __asan_memcpy
Shadow bytes around the buggy address:
  0x0c428063fcd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c428063fce0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c428063fcf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c428063fd00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c428063fd10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c428063fd20:[fd]fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c428063fd30: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c428063fd40: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c428063fd50: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c428063fd60: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c428063fd70: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==54405==ABORTING

Exploit Proof of Concept

Execute server.py script and navigate with Firefox to pointed url.

Timeline

2021-07-22 - Vendor Disclosure
2021-08-10 - Public Release

Credit

Discovered by Marcin 'Icewall' Noga of Cisco Talos.