Skip to content

Conversation

deepak1556
Copy link
Member

@deepak1556 deepak1556 commented Jun 29, 2020

Description of Change

This is an edge case that was discovered in ci when a page holding webview is created and destroyed rapidly but after some debugging this is possible to trigger by users too depending on usage.

Thanks @rebornix for help with the detailed debugging.

Refs microsoft/vscode#99408 , microsoft/vscode#100321

The sequence of action before this PR were as follows:

  1. <webview> DOM element is created and attached to DOM tree by the user
  2. starts parsing the src attribute which inturn signals the browser process via an async ipc to create the backing webcontents via CreateGuest in guest-view-manager
  3. The above ipc returns a guestInstanceId that is used to uniquely identify the webview element
  4. The renderer then signals the browser process via another async ipc to attach the backing webcontents in the browser frame tree
  5. When the <webview> is removed from the DOM tree by the user this will signal a sync ipc to cleanup stuff on the browser process.

All this works well most of the time, but there can be situations where a page holding the webview is destroyed between step 3) and 4) , which causes the attach ipc call to cause UAF crashes in electron::WebViewGuestDelegate::AttachToIframe

This patch fixes the scenario by combining the creation and attaching of backing webcontents in a single ipc call that will avoid the race.

Checklist

Release Notes

Notes: Fixed crash in webview creation casued by UAF in the browser process

@electron-cation electron-cation bot added the new-pr 🌱 PR opened recently label Jun 29, 2020
@deepak1556 deepak1556 requested a review from zcbenz June 29, 2020 04:52
Copy link
Contributor

@nornagon nornagon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test? :)

@deepak1556
Copy link
Member Author

deepak1556 commented Jun 29, 2020

@nornagon hence the draft state 😄 , hopefully I can get a minimal test suite from the vscode team.

@electron-cation electron-cation bot removed the new-pr 🌱 PR opened recently label Jun 30, 2020
@rebornix
Copy link

rebornix commented Jul 8, 2020

I spent a few days trying to get a minimal reproduce on vanilla Electron but I found the test is simply about removing the webview shortly after the webview is created (sequence 1, 2, 3, 5, 4 per #24344 (comment)). On a relatively powerful machine, that's nanoseconds.

For example, I wrote a test like below and I can only crash the process 1-2 out of 100 times on some bad days (I'm guessing it's when my machine is on heavy loads)

const v8Util = process.electronBinding('v8_util');
const ipcRendererInternal = v8Util.getHiddenValue(global, 'ipc-internal');
const { ipc } = process.electronBinding('ipc');
function timeoutAsync(n) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve();
        }, n);
    });
}
const loadWebView = async (id, container, webview, attributes = {}) => {
    for (const [name, value] of Object.entries(attributes)) {
        webview.setAttribute(name, value);
    }
    container.appendChild(webview);
    setTimeout(() => {
        ipcRendererInternal.sendSync('ELECTRON_GUEST_VIEW_MANAGER_DETACH_GUEST', id + 1);
    }, 2);
};
async function test() {
    for (let i = 0; i < 500; i++) {
        let webview = new WebView();
        const container = document.createElement('div');
        document.body.appendChild(container);
        loadWebView(i + 1, container, webview, {
            src: `https://s3.amazonaws.com/duhaime/blog/visualizations/isolation-forests.html`
        });
        await timeoutAsync(10);
    }
}
window.onload = function () {
    test()
}

Even on our CI https://dev.azure.com/vscode/VSCode/_build/results?buildId=48185&view=logs&j=a5e52b91-c83f-5429-4a68-c246fc63a4f7&t=855ed636-0983-5316-9b28-7efa8f10a65b, on which we are seeing most of the crashes, we only saw crashes 1 out of 5 to 10 times. It made me think that if we are going to have a test, which can crash the process 100% of the time, we need to either

  • mimic the CI environment and make the CI machine under as heavy load as VS Code integration tests.
  • or, have code in electron/chromium directly to slow down the execution, to trigger the racing condition.

but none of above sounds valuable. I'm wondering if there is any other approach that we can take to move this forward?

@zcbenz
Copy link
Contributor

zcbenz commented Jul 9, 2020

I'm good without a test in this case.

@zcbenz zcbenz requested a review from nornagon July 9, 2020 13:03
@deepak1556 deepak1556 marked this pull request as ready for review July 9, 2020 16:01
@deepak1556 deepak1556 force-pushed the robo/fix_webview_creation_race branch from 0f6fc57 to b01f7fa Compare July 9, 2020 16:07
@nornagon
Copy link
Contributor

I'm a little uneasy that this fixes a UAF by shuffling some JavaScript around. It should be impossible to cause a UAF from JS. Can we address this on the C++ side?

@deepak1556
Copy link
Member Author

deepak1556 commented Jul 13, 2020

It should be impossible to cause a UAF from JS.

For webview it becomes possible because its backing webContents lifetime is tied to either the embedder on the main process or the DOM node on the renderer unlike the other JS objects we manage. Hence this mostly boils down to the mapping we maintain in guest-view-manager, there is a case that is not updating the mapping correctly during destruction of the embedder which would the root cause here. But our destruction sequence is quite complex to mess with, hence this turned out to be the simplest solution for backports. I agree that this doesn't fix the root cause but eliminates the abnormalities around webview creation.

Can we address this on the C++ side?

any ideas ?

@miniak
Copy link
Contributor

miniak commented Oct 16, 2020

@deepak1556 can you please rebase on top of latest master?

@deepak1556 deepak1556 force-pushed the robo/fix_webview_creation_race branch from b01f7fa to 9caadd2 Compare October 16, 2020 04:57
@deepak1556 deepak1556 requested a review from a team as a code owner October 16, 2020 06:44
@deepak1556 deepak1556 requested a review from codebytere October 16, 2020 08:18
@nornagon
Copy link
Contributor

nornagon commented Mar 8, 2021

We now have ASan tests enabled in master (on Linux only). That might make it easier to create a reliably-failing test.

@miniak miniak force-pushed the robo/fix_webview_creation_race branch from 5d4636d to 9eb6ba0 Compare May 15, 2021 15:18
@deepak1556 deepak1556 requested a review from a team as a code owner May 15, 2021 15:18
@miniak miniak force-pushed the robo/fix_webview_creation_race branch from 9eb6ba0 to 091139f Compare July 28, 2021 15:15
@miniak
Copy link
Contributor

miniak commented Jul 28, 2021

I am not seeing those crashes anymore.

@miniak
Copy link
Contributor

miniak commented Jul 28, 2021

@zcbenz, @codebytere can you please review?

@miniak miniak requested review from a team and removed request for a team July 29, 2021 16:25
@deepak1556
Copy link
Member Author

Failing tests are unrelated, merging.

@deepak1556 deepak1556 merged commit 2b897c8 into main Aug 2, 2021
@deepak1556 deepak1556 deleted the robo/fix_webview_creation_race branch August 2, 2021 15:35
@release-clerk
Copy link

release-clerk bot commented Aug 2, 2021

Release Notes Persisted

Fixed crash in webview creation casued by UAF in the browser process

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no-backport semver/patch backwards-compatible bug fixes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants