mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-25 14:05:15 +00:00
This is fixed by making the "about to be notified rejected promises list" use JS::Handle instead of JS::NonnullGCPtr. This UAF happens because notify_about_rejected_promises makes a local copy of this list, empties the member variable list and then moves the local copy into a JS::SafeFunction lambda. JS::SafeFunction can only see GC pointers that are in its storage, not external storage. Example exploit (requires fixed microtask timing by removing the dummy execution context): ```html <script> Promise.reject(new Error); // Exit the script block, causing a microtask checkpoint and thus // queuing of a task to fire the unhandled rejection event for the // above promise. // During the time after being queued but before being ran, these // promises are not kept alive. This is because JS::SafeFunction cannot // see into a Vector, meaning it can't visit the stored NonnullGCPtrs. </script> <script defer> // Cause a garbage collection, destroying the above promise. const b = []; for (var i = 0; i < 200000; i++) b.push({}); // Some time after this script block, the queued unhandled rejection // event task will fire, with the event object containing the dead // promise. window.onunhandledrejection = (event) => { let value = event.promise; console.log(value); } </script> ``` |
||
---|---|---|
.. | ||
ClassicScript.cpp | ||
ClassicScript.h | ||
Environments.cpp | ||
Environments.h | ||
ExceptionReporter.cpp | ||
ExceptionReporter.h | ||
Fetching.cpp | ||
Fetching.h | ||
ImportMap.h | ||
ModuleMap.cpp | ||
ModuleMap.h | ||
ModuleScript.cpp | ||
ModuleScript.h | ||
Script.cpp | ||
Script.h | ||
WindowEnvironmentSettingsObject.cpp | ||
WindowEnvironmentSettingsObject.h | ||
WorkerEnvironmentSettingsObject.h |