Skip to content

Instantly share code, notes, and snippets.

@MaxBWMinRTT
Last active November 3, 2023 08:44
Show Gist options
  • Save MaxBWMinRTT/bd47b17cac9eef20efe3040b5a50e043 to your computer and use it in GitHub Desktop.
Save MaxBWMinRTT/bd47b17cac9eef20efe3040b5a50e043 to your computer and use it in GitHub Desktop.
Some quick notes about the CVE-2023-3079(V8 type confusion), no PoC yet.

Some quick notes about the CVE-2023-3079(V8 type confusion), no PoC yet.

Official patch: https://chromium-review.googlesource.com/c/v8/v8/+/4584248

image

Patch come from KeyedStoreIC::StoreElementHandler(), it returns fast path code(Turbofan builtin) for keyed store depends on "receiver_map" and "store_mode". Based on the content of this function is all about element STORE, I personally believe that this is an OOB writes vulnerability.

If we divide the PoC exploration into two parts based on this func, they are:

  1. how to reach it
  2. how to achieve OOB write through it

This writeup is about the latter.

KeyedStoreIC::StoreElementHandler() in ic.cc

Comments from v8 devs:

Allow fast behaviour for in-bounds stores while making it miss and properly handle the out of bounds store case.

From the patched if branch we may assume the buggy receiver has some traits:

  • IsJSArgumentsObject
  • fast packed elements

And according to the code above, there are some more some limitations:

  • NOT has_sloppy_arguments_elements, so it MUST be strict arguments

Also we had STANDARD_STORE as a hard coded access mode, so we may assume the PoC needs:

  • store_mode ≠ STANDARD_STORE

Conclusion:

  1. strict arguments object
  2. non STANDARD_STORE store mode

EmitElementStore() in code-stub-assembler.cc

It was not patched which indicates that its logic does not have any issues, since it’s called by other funcs, if other callsites use a packed arguments object with the non-standard store mode parameter, an OOB write can still occur (which indicates that this parameter combination cannot appear in other callsites).

In EmitElementStore, if our goal is to achieve an OOB write, it means:

  • intptr_key ≥ length, in order to write data to unallocated memory
  • The elements array does not expand, cause what we need is out-of-bound write. Moreover, it is difficult to accurately control the written memory range after expansion(harder to find the addr of the newly allocated elements array in the bump allocation heap?)

If the function does not enter bailout at the end, it will call StoreElement() to write the target value into addr elements + intptr_key * element_size.

The peculiarity of strict mode JSStrictArgumentsObject

JSStrictArgumentsObject is a JSArray-alike object, but it’s not a JSArray. It inherits from JSObject and has a length property/descriptor inside, just like JSArray.

extern class JSArgumentsObject extends JSObject {}
extern shape JSStrictArgumentsObject extends JSArgumentsObject {
  length: JSAny;
}

extern class JSArray extends JSObject {
  macro IsEmpty(): bool {
    return this.length == 0;
  }
  length: Number;
}

So what makes JSStrictArgumentsObject special compared to an ordinary JSObject or JSArray? Some thoughts but no answer:

  • the length descriptor
    • strict arguments’s length is readonly constant and does not change if we add new element into its elements array
    • ISSUE: we may got a SMALLER length, not a LARGER one for oob writes
  • packed elements
    • strict arguments’s elements are packed kind by default, compared to a JSObject. You can’t create a JSObject with packed elements(not sure…)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment