Coordinated Disclosure Timeline

Summary

Type confusion in v8 that can lead to remote code execution in the Chrome renderer.

Product

Chromium

Tested Version

master branch build 76ae53f

Details

Issue 1: Type confusion in handling of accessor in ReduceNamedAccess (GHSL-2022-043)

In ReduceNamedAccess, map is passed to GetPropertyAccessInfo to create PropertyAccessInfo [1]:

      PropertyAccessInfo access_info = broker()->GetPropertyAccessInfo(
          map, feedback.name(), access_mode, dependencies());
      access_infos_for_feedback.push_back(access_info);
    }

In the case of super property access, this map comes from the feedback collected for the lookup_start_object [2]:

  if (!InferMaps(lookup_start_object, effect, &inferred_maps)) {
    for (const MapRef& map : feedback.maps()) {
      inferred_maps.push_back(map);
    }
  }

In the case of an accessor that is a simple api call, this map is then used in AccessorAccessInfoHelper to check for compatibility between the api call and the map [3]:

PropertyAccessInfo AccessorAccessInfoHelper(...) {
  ...

    CallOptimization::HolderLookup lookup;
    Handle<JSObject> holder_handle = broker->CanonicalPersistentHandle(
        optimization.LookupHolderOfExpectedType(
            broker->local_isolate_or_isolate(), receiver_map.object(),   //<------- receiver_map here is the map for `lookup_start_object` from `ReduceNamedAccess`
            &lookup));

ReducedNameAccess will then carry on to try inlining the getter call [4]:

base::Optional<JSNativeContextSpecialization::ValueEffectControl>
JSNativeContextSpecialization::BuildPropertyLoad(
    Node* lookup_start_object, Node* receiver, Node* context, Node* frame_state,
    Node* effect, Node* control, NameRef const& name,
    ZoneVector<Node*>* if_exceptions, PropertyAccessInfo const& access_info) {
  ...
  if (access_info.IsNotFound()) {
    ...
  } else if (access_info.IsFastAccessorConstant() ||
             access_info.IsDictionaryProtoAccessorConstant()) {
    ConvertReceiverMode receiver_mode =
        receiver == lookup_start_object
            ? ConvertReceiverMode::kNotNullOrUndefined
            : ConvertReceiverMode::kAny;
    value =
        InlinePropertyGetterCall(receiver, receiver_mode, context, frame_state,
                                 &effect, &control, if_exceptions, access_info);  //<------- receiver here is used for the inlined call

This will inline the simple api call with receiver, instead of lookup_start_object. By providing a lookup_start_object that passes the LookupHolderOfExpectedType test above and a receiver of a different type, a type confusion occurs.

Impact

This issue can be exploited to gain RCE in the Chrome renderer sandbox by visiting a malicious website.

Resources

  1. https://source.chromium.org/chromium/chromium/src/+/75c36c7712bea160e69de6b87b864dfcebab239e:v8/src/compiler/js-native-context-specialization.cc;l=1125
  2. https://source.chromium.org/chromium/chromium/src/+/75c36c7712bea160e69de6b87b864dfcebab239e:v8/src/compiler/js-native-context-specialization.cc;l=1084
  3. https://source.chromium.org/chromium/chromium/src/+/75c36c7712bea160e69de6b87b864dfcebab239e:v8/src/compiler/access-info.cc;l=573
  4. https://source.chromium.org/chromium/chromium/src/+/75c36c7712bea160e69de6b87b864dfcebab239e:v8/src/compiler/js-native-context-specialization.cc;l=2293
  5. https://chromium.googlesource.com/v8/v8/+/9c3d4b3556b2797fa9d9f4bee915e8502608312f

CVE

Credit

This issue was discovered and reported by GHSL team member @m-y-mo (Man Yue Mo).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2022-043 in any communication regarding this issue.