V8
This is a collection of basic concepts, commands and everything else I could find on V8 and found noteworthy
as of January 2024 (V8 commit:
978989e7ec945824b293a8093238ceedb2b06d17
).
Tutorials ¶
Basic Concepts ¶
-
JSObject is the superclass of every JavaScript object on the heap. Its type is defined in the corresponding Map.
See also: Fast Properties
-
A Map (also called Shape or Hidden Class) contains information about a JSObject that resides in the JavaScript heap. Depending on the corresponding object's type the entries of the map can vary. A more detailled description of each entry can be found in a comment in the source code.
See also: Map Documentation
-
Because a lot of constructs revolve around small, short-lived integers (e.g., the index in a
for
loop), it would be wasteful to construct and dereference a full fledged heap object each time an integer is used. Instead, V8 uses pointer tagging to distinguish between a pointer and a small integer (SMI). Since objects are located in close proximity, pointer compression can be used to save additional memory.See also: How Small is a Small Integer?
-
Inline caching is one of the core concepts to improve performance. If property loads (e.g.,
o.x
) in a function are continuously done on objects of the same shape (i.e., the loads are monomorphic), the inline cache saves the memory offset of the property for the respective shape, so that it can be accessed directly next time.See also: Explaining JavaScript VMs in JavaScript - Inline Caches
- On-stack replacement (OSR)
- Static single-assignement form (SSA)
- Optimizing Prototypes Shapes and Inline Caches
- Sea of Nodes
Components ¶
- Ignition is the interpreter used in V8.
-
Sparkplug is a non-optimizing compiler in V8.
See also: Sparkplug, the new lightning-fast V8 baseline JavaScript compiler
- Maglev is the first tier optimizing compiler.
-
Turbofan is the top-tier optimizing compiler. The latest architecture of Turbofan is called Turboshaft which is located in src/compiler/turboshaft/. Turbolizer is used to analyze the internals of Turbofan.
See also: Introduction to Turbofan, An Introduction to Speculative Optimization in V8, Intro to Chrome's V8 from an exploit development angle and Turbofan Techtalk
- Liftoff is baseline compiler for WebAssembly.
-
Builtins (e.g., Array.splice()) provide essential functionality for the execution of JavaScript code and are optimized to run efficiently. Currently, they are implemented in seven different ways. CodeStubAssembler (CSA) is a portable assembly language built on top of TurboFan's backend. Torque is a TypeScript-like language.
- Oilpan
- Orinoco
- Turboprop (no longer used) was a midtier compiler proposal based on TurboFan.
- Crankshaft (no longer used) was the old optimizing compiler that has been superseded by Turbofan.
- Full-codegen (no longer used) was the old baseline compiler that has been superseded by Turbofan.
d8 Options ¶
--allow-natives-syntax
--trace-opt
--trace-deopt
--trace-turbo
--print-ast
--print-bytecode
--print-opt-code
d8 Debug ¶
d8 Analysis ¶
This section contains examples of how to analyse and navigate the representations of V8 objects in memory using a debugger. We will use lldb and so every example starts d8 with the command:
$ lldb -- ./d8 --allow-natives-syntax
String
The first entry points to a map that defines the string type INTERNALIZED_ONE_BYTE_STRING_TYPE
.
Note, the length of the string is not in SMI format (i.e., it is just a regular
integer).
d8> let a = "Hello World!"
d8> %DebugPrint(a)
DebugPrint: 0x296f000da7ad: [String] in OldSpace: #Hello World!
0x296f000003d5: [Map] in ReadOnlySpace
- map: 0x296f000004c5 <MetaMap (0x296f0000007d <null>)>
- type: INTERNALIZED_ONE_BYTE_STRING_TYPE
Ctrl^C
(lldb) x/wx 0x296f000da7ad-1+8 /* third entry */
0x296f000da7b4: 0x0000000c /* = a.length */
(lldb) x/s 0x296f000da7ad-1+12 /* fourth entry */
0x296f000da7b8: "Hello World!" /* = raw string */
JSPrimitiveWrapper (String)
This is a regular JSObject. The first entry point to a map that defines the string type as
FAST_STRING_WRAPPER_ELEMENTS
. The fourth entry (the first in-line property of the
JSObject) is used
to store the value which is a pointer to a String object.
d8> let a = new String("Hello World!")
d8> %DebugPrint(a)
DebugPrint: 0x3cd7001ca111: [JSPrimitiveWrapper]
- map: 0x3cd7000c8c31 <Map[16](FAST_STRING_WRAPPER_ELEMENTS)> [FastProperties]
- prototype: 0x3cd7000c8f0d <Object map = 0x3cd7000c8c59 value = 0x3cd700000099 <String[0]: #>>
- elements: 0x3cd7000006cd <FixedArray[0]> [FAST_STRING_WRAPPER_ELEMENTS]
- value: 0x3cd7000da7ad <String[11]: #Hello World>
...
Ctrl^C
(lldb) x/wx 0x3cd7000da7ad-1+8 /* third entry */
0x3cd7000da7b4: 0x0000000b /* = a.length */
(lldb) x/s 0x3cd7000da7ad-1+12 /* fourth entry */
0x3cd7000da7b8: "Hello World" /* = raw string */
JSArray
d8> let a = [1,2,3,4,5,6,7,8,9,0]
d8> %DebugPrint(a)
DebugPrint: 0x173d001ca10d: [JSArray]
- map: 0x173d000ce6c1 <Map[16](PACKED_SMI_ELEMENTS)> [FastProperties]
- prototype: 0x173d000ce935 <JSArray[0]>
- elements: 0x173d000da811 <FixedArray[10]> [PACKED_SMI_ELEMENTS (COW)]
- length: 10
- properties: 0x173d000006cd <FixedArray[0]>
- All own properties (excluding elements): {
0x173d00000d41: [String] in ReadOnlySpace: #length: 0x173d0030ed89 <AccessorInfo name= 0x173d00000d41 <String[6]: #length>, data= 0x173d00000061 <undefined>> (const accessor descriptor), location: descriptor
}
- elements: 0x173d000da811 <FixedArray[10]> {
0: 1
1: 2
2: 3
3: 4
4: 5
5: 6
6: 7
7: 8
8: 9
9: 0
}
...
Ctrl^C
(lldb) x/wx 0x173d001ca10d-1+8 /* third entry */
0x173d001ca114: 0x000da811 /* = pointer to elements */
(lldb) x/wx 0x173d001ca10d-1+12 /* fourth entry */
0x173d001ca118: 0x00000014 /* = (0x14 >> 1) == a.length */
- String
- FixedArray
-
JSArray
Memory Layout
Map Properties Elements Length -
JSObject
Memory Layout
Map Properties Elements In-Object Property #1 In-Object Property #2 ... - Map
-
JSPrimitiveWrapper
(String)
Memory Layout
Map Properties Elements Value
CVEs ¶
- CVE-2012-0464: [SM] Array toString Remote Code Execution
- CVE-2014-1514: [SM] vmtypedarrayobject.cpp dst ptr is checked the length is not checked ()
- CVE-2015-6764: Pwn2Own mobile case, out-of-bound access in json stringifier
- CVE-2016-4622: [JSC] A case study of JavaScriptCore (Youtube)
-
CVE-2018-17463: Exploiting Logic Bugs in JavaScript JIT Engines
Bug:
CreateObject
(marked askNoWrite
) may callOptimizeAsPrototype
which can change the object's prototype. - CVE-2018-17463: Issue 888923: Security: Chrome RCE
-
CVE-2019-13730
-
1Day-2019-09-09: Patch-gapping Google Chrome
Bug: Type confusion after invalid map transition on sealed objects without updating the backing store.
- CVE-2020-9802: [JSC] JITSploitation
- CVE-2020-16040
- CVE-2021-21225: A Bug's Life [exploit]
- CVE-2021-30551: Chrome Type Confusion in V8
- CVE-2021-37975: Chrome v8 garbage collector logic bug causing live objects to be collected
- CVE-2021-38001: TianfuCup RCE bug Type confusion in LoadIC::ComputeHandler
- CVE-2021-38003: Dota 2 Under Attack: How a V8 Bug Was Exploited in the Game
-
CVE-2021-38003: TheHole New World - how a small leak will sink a great browser
Bug:
SerializeArrayLikeSlow
attempts to fetch an exception frompending_exception
while no exception is set which leads to leakage of theTheHole
value. This can be used to corrupt the size of aJSMap
. - CVE-2022-1134: The Chromium super (inline cache) type confusion
- CVE-2022-1134: Issue 1308360: Type confusion when using simple api call accessors with SuperIC
-
CVE-2022-1364: From Leaking TheHole to Chrome Renderer RCE
Related to: CVE-2021-38003
- CVE-2023-3079 [exploit only]
- CVE-2023-2033
-
CVE-2023-3420: Getting RCE in Chrome with incorrect side effect in the JIT compiler
Bug:
StackCheck
(marked askNoWrite
) callsStackGuard::HandleInterrupts
which callsHandleInterrupts
(marked askAnyEffect
)
CTFs ¶
- Google CTF 2022 d8: From V8 Bytecode to Code Execution
- Exploit for the "roll a d8" challenge of PlaidCTF 2018 (GitHub gist)
- Exploiting Chrome V8: Krautflare (35C3 CTF 2018)
- Exploiting the Math.expm1 typing bug in V8 (35C3 CTF 2018)
- Exploiting TurboFan Through Bounds Check Elimination (2019)
- Exploiting v8: *CTF 2019 oob-v8
Unreviewed ¶
- Learn2Learn: V8 Exploitation
- Awesome Browser Exploits
-
Diary of a hacker
- A journey into IonMonkey: root-causing CVE-2019-9810.
- Circumventing Chrome's hardening of typer bugs
- Introduction to SpiderMonkey exploitation.
- CVE-2017-2446 or JSC::JSGlobalObject::isHavingABadTime.
- Debugger data model, Javascript & x64 exception handling
- Modern attacks on the Chrome browser : optimizations and deoptimizations