Coordinated Disclosure Timeline

Summary

Opening a malicious website in affected versions of Chrome can lead to object corruption in the Chrome renderer.

Project

Chromium

Tested Version

Chromium version 123.0.6312.58

Details

Insufficient fix for CVE-2021-30561 (GHSL-2024-071)

The mechanisms that were introduced to prevent issues like 40056206 (CVE-2021-30561) are insufficient. In InstallConditionalFeatures, a check was introduced to check that the webassembly object does not have the relevant property before adding it to the object:

void WasmJs::InstallConditionalFeatures(Isolate* isolate,
                                        Handle<NativeContext> context) {
  ...
  MaybeHandle<Object> maybe_wasm =
      JSReceiver::GetProperty(isolate, global, "WebAssembly");    //<-------- 1.
  ...
  if (isolate->IsWasmJSPIEnabled(context)) {
    isolate->WasmInitJSPIFeature();

    Handle<String> suspender_string = v8_str(isolate, "Suspender");
    if (!JSObject::HasRealNamedProperty(isolate, webassembly, suspender_string)   //<----- 2.
             .FromMaybe(true)) {
      InstallSuspenderConstructor(isolate, context);
    }

    // Install Wasm type reflection features (if not already done).
    Handle<String> function_string = v8_str(isolate, "Function");
    if (!JSObject::HasRealNamedProperty(isolate, webassembly, function_string)
             .FromMaybe(true)) {
      InstallTypeReflection(isolate, context);
    }
  }
}

In the above, the object that is used in the check is the global property WebAssembly (1. and 2.) However, when the property is installed using InstallSuspenderConstructor, the object that is used is context->wasm_webassembly_object() (3.), which may not be the same as the WebAssembly global property.

void WasmJs::InstallSuspenderConstructor(Isolate* isolate,
                                         Handle<NativeContext> context) {
  Handle<JSObject> webassembly(context->wasm_webassembly_object(), isolate);    //<------ 3.
  Handle<JSFunction> suspender_constructor = InstallConstructorFunc(
      isolate, webassembly, "Suspender", WebAssemblySuspender);
  context->set_wasm_suspender_constructor(*suspender_constructor);
  SetupConstructor(isolate, suspender_constructor, WASM_SUSPENDER_OBJECT_TYPE,
                   WasmSuspenderObject::kHeaderSize, "WebAssembly.Suspender");
}

By first setting the Suspender property on the WebAssembly object and then setting the global WebAssembly to a different object, the property name check will be performed on the newly assigned WebAssembly object while the property will be added in the context->wasm_assembly_object(), which already has a Suspender object. This then creates a corrupted object with a duplicated Suspender property. This also affects the InstallTypeReflection function when the Function property is installed.

Impact

This issue may lead to memory corruption in the Chrome renderer

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-2024-071 in any communication regarding this issue.