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

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
This commit is contained in:
Robo 2020-04-30 21:33:14 -07:00 committed by GitHub
parent 4bbb2fbf1f
commit c438b93f18
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 17 additions and 1 deletions

View file

@ -251,6 +251,9 @@ const attachGuest = function (event, embedderFrameId, elementInstanceId, guestIn
// Remove an guest-embedder relationship. // Remove an guest-embedder relationship.
const detachGuest = function (embedder, guestInstanceId) { const detachGuest = function (embedder, guestInstanceId) {
const guestInstance = guestInstances[guestInstanceId]; const guestInstance = guestInstances[guestInstanceId];
if (!guestInstance) return;
if (embedder !== guestInstance.embedder) { if (embedder !== guestInstance.embedder) {
return; return;
} }
@ -341,6 +344,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> // this message is sent by the actual <webview>
ipcMainInternal.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) { ipcMainInternal.on('ELECTRON_GUEST_VIEW_MANAGER_FOCUS_CHANGE', function (event, focus, guestInstanceId) {
const guest = getGuest(guestInstanceId); const guest = getGuest(guestInstanceId);

View file

@ -1,5 +1,6 @@
import { webFrame, IpcMessageEvent } from 'electron'; import { webFrame, IpcMessageEvent } from 'electron';
import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal'; import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-internal';
import * as ipcRendererUtils from '@electron/internal/renderer/ipc-renderer-internal-utils';
import { WebViewImpl } from '@electron/internal/renderer/web-view/web-view-impl'; import { WebViewImpl } from '@electron/internal/renderer/web-view/web-view-impl';
@ -105,8 +106,13 @@ export function attachGuest (
ipcRendererInternal.invoke('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', embedderFrameId, elementInstanceId, guestInstanceId, params); 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 = { export const guestViewInternalModule = {
deregisterEvents, deregisterEvents,
createGuest, createGuest,
attachGuest attachGuest,
detachGuest
}; };

View file

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