Browse Source

fix: ensure guest-embedder map is updated when webview is removed (#23342) (#23397)

There are use cases of webview where the container holding the webview is not
actually destroyed first, instead just webview gets removed from DOM, in such
situations the browser process map is not updated accordingly and holds reference
to stale guest contents, and any window operations like scroll, resize or keyboard
events that has to chain through browser embedder will lead to UAF crash.

Ref: https://github.com/microsoft/vscode/issues/92420
Robo 5 years ago
parent
commit
30ae6f45a4

+ 7 - 0
lib/browser/guest-view-manager.js

@@ -266,6 +266,9 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
 // Remove an guest-embedder relationship.
 const detachGuest = function (embedder, guestInstanceId) {
   const guestInstance = guestInstances[guestInstanceId];
+
+  if (!guestInstance) return;
+
   if (embedder !== guestInstance.embedder) {
     return;
   }
@@ -360,6 +363,10 @@ handleMessage('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function (event, embed
   }
 });
 
+handleMessageSync('ELECTRON_GUEST_VIEW_MANAGER_DETACH_GUEST', function (event, guestInstanceId) {
+  return detachGuest(event.sender, guestInstanceId);
+});
+
 // this message is sent by the actual <webview>
 ipcMainInternal.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
   const guest = getGuest(guestInstanceId);

+ 6 - 1
lib/renderer/web-view/guest-view-internal.ts

@@ -110,9 +110,14 @@ export function attachGuest (
   ipcRendererInternal.invoke('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', embedderFrameId, elementInstanceId, guestInstanceId, params);
 }
 
+export function detachGuest (guestInstanceId: number) {
+  return ipcRendererUtils.invokeSync('ELECTRON_GUEST_VIEW_MANAGER_DETACH_GUEST', guestInstanceId);
+}
+
 export const guestViewInternalModule = {
   deregisterEvents,
   createGuest,
   createGuestSync,
-  attachGuest
+  attachGuest,
+  detachGuest
 };

+ 3 - 0
lib/renderer/web-view/web-view-element.ts

@@ -66,6 +66,9 @@ const defineWebViewElement = (v8Util: NodeJS.V8UtilBinding, webViewImpl: typeof
         return;
       }
       guestViewInternal.deregisterEvents(internal.viewInstanceId);
+      if (internal.guestInstanceId) {
+        guestViewInternal.detachGuest(internal.guestInstanceId);
+      }
       internal.elementAttached = false;
       this.internalInstanceId = 0;
       internal.reset();