Compare commits

..

71 Commits

Author SHA1 Message Date
Sudowoodo Release Bot
6a75402ee8 Bump v14.2.7 2022-03-09 07:31:40 -08:00
Jeremy Rose
b6764c0276 chore: cherry-pick 62142d222a80 from chromium (#33184)
* chore: cherry-pick 62142d222a80 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-03-08 14:13:10 -05:00
Jeremy Rose
1856b71bc1 chore: cherry-pick 49e8ff16f1fe from angle (#33180)
* chore: cherry-pick 49e8ff16f1fe from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-03-08 13:45:13 -05:00
Jeremy Rose
302d4829b4 chore: cherry-pick 1887414c016d from chromium (#33177)
* chore: cherry-pick 1887414c016d from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-03-08 10:52:27 -05:00
Jeremy Rose
c3c2d844d5 chore: cherry-pick 6b2643846ae3 from chromium (#33167)
* chore: cherry-pick 6b2643846ae3 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-03-07 16:52:12 -08:00
Pedro Pontes
28eaf77a25 chore: cherry-pick be50c60b4225 from chromium (#32984)
* chore: cherry-pick be50c60b4225 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-03-01 10:22:20 -08:00
Sudowoodo Release Bot
68c436a3e5 Revert "Bump v14.2.7"
This reverts commit f659fa4f0b.
2022-02-23 15:48:14 -08:00
Sudowoodo Release Bot
f659fa4f0b Bump v14.2.7 2022-02-23 11:31:34 -08:00
trop[bot]
1fc49a55d6 chore: cherry-pick e3805f29fed7 from chromium (#32959)
* chore: cherry-pick e3805f29fed7 from chromium (#32901)

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>

* Update .patches

* chore: update patches

Co-authored-by: Pedro Pontes <ppontes@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-23 19:32:30 +09:00
Cheng Zhao
f46b3f48af chore: cherry-pick fix for 1277917 from chromium (#32787) 2022-02-22 10:20:29 -08:00
trop[bot]
83a933f303 fix: command string for windows protocol handler (#33009)
Co-authored-by: deepak1556 <hop2deep@gmail.com>
2022-02-22 16:26:51 +09:00
Pedro Pontes
133a69f43e chore: cherry-pick 05e714a87c from chromium (#32977)
Co-authored-by: Electron Bot <electron@github.com>
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-22 16:20:57 +09:00
Pedro Pontes
6ce4445e63 chore: cherry-pick 0081bb347e67 from chromium (#32986) 2022-02-21 14:07:28 -08:00
Pedro Pontes
8319490c59 chore: cherry-pick 11505c3867 from chromium (#32983)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-21 10:43:20 -08:00
Pedro Pontes
5dd4d85b60 chore: cherry-pick b790affce3 and 9c1efd3def from angle (#32982) 2022-02-21 15:05:26 +01:00
trop[bot]
f09df625f2 chore: add @electron/wg-security to patches/ CODEOWNERS (#33003)
Co-authored-by: Jeremy Rose <jeremya@chromium.org>
2022-02-21 15:00:01 +01:00
Pedro Pontes
8d59648128 chore: cherry-pick ebc188ad769e from chromium (#32978)
* chore: cherry-pick ebc188ad769e from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-02-21 09:27:58 +01:00
trop[bot]
f57244d00d fix: stale renderer process on quit (#32968)
Co-authored-by: Micha Hanselmann <micha.hanselmann@gmail.com>
2022-02-21 10:26:00 +09:00
Cheng Zhao
f47bc6be2b chore: cherry-pick fix for 1282354 from chromium (#32784)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-21 10:12:12 +09:00
Jeremy Rose
8540d7ddf6 chore: cherry-pick 9db9911e1242 from chromium (#32742)
* chore: cherry-pick 9db9911e1242 from chromium

* chore: update patches

* kick lint

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-02-18 11:11:35 +09:00
Jeremy Rose
dc3a2ffd31 chore: cherry-pick 22f27676515e from chromium (#32743)
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-02-17 14:42:46 -08:00
Cheng Zhao
351b10d179 chore: cherry-pick fix for 1283371 from chromium (#32780)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-17 21:07:50 +09:00
Cheng Zhao
465e599359 chore: cherry-pick fix for 1283375 from chromium (#32778)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-17 14:52:45 +09:00
Cheng Zhao
b6ad975666 chore: cherry-pick fix for 1283198 from chromium (#32782)
Co-authored-by: Electron Bot <electron@github.com>
2022-02-16 17:05:44 +09:00
Sudowoodo Release Bot
38a6fb9a53 Bump v14.2.6 2022-02-14 12:11:30 -08:00
trop[bot]
13fd1105c7 test: disable the test that makes spec runner hang on exit (#32835)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-02-09 14:16:53 -05:00
Jeremy Rose
5f3eae7119 chore: cherry-pick 27bc67f761e6 from v8 (#32740)
* chore: cherry-pick 27bc67f761e6 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-02-08 12:04:10 -05:00
Cheng Zhao
b4613cfe9f chore: cherry-pick fix for 1284367 from chromium (#32776) 2022-02-08 11:34:18 -05:00
trop[bot]
e95a593199 fix: WCO window hover on window controls on Windows (#32716)
* fix: WCO window hover on window controls

* Update shell/browser/ui/win/electron_desktop_window_tree_host_win.cc

Co-authored-by: Robo <hop2deep@gmail.com>

Co-authored-by: clavin <clavin@electronjs.org>
Co-authored-by: Calvin <clavin@users.noreply.github.com>
Co-authored-by: Robo <hop2deep@gmail.com>
2022-02-03 11:51:34 -05:00
trop[bot]
9c2eed2333 fix: some frameless windows showing a frame on Windows (#32709)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-02-02 12:00:22 -05:00
Sudowoodo Release Bot
f6798c5e99 Bump v14.2.5 2022-01-27 12:38:19 -08:00
Jeremy Rose
e3b8dd1d9d chore: cherry-pick c5571653d932 from chromium (#32354)
* chore: cherry-pick c5571653d932 from chromium

* fix patch

* Update cherry-pick-c5571653d932.patch

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-27 20:24:58 +09:00
trop[bot]
2b611690f9 ci: update ts-compile-doc-change to properly use src cache (#32624)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-26 10:31:02 -05:00
trop[bot]
f2774427f9 fix: webContents.setZoomFactor crash (#32618)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-26 20:06:04 +09:00
trop[bot]
16bf1edc77 test: disable flaky test on WOA (#32559)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-24 11:41:02 -05:00
trop[bot]
f617308c6f ci: call autoninja without ninjalog_uploader_wrapper.py (#32571)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2022-01-24 19:55:21 +09:00
Pedro Pontes
acc14843cf chore: cherry-pick cc44ae61f37b from angle (#32547) 2022-01-20 11:07:44 -08:00
Shelley Vohr
027d803d73 fix: maximize/unmaximize firing on linux (#32499) 2022-01-19 09:40:57 +01:00
trop[bot]
34d77ca691 fix: check for maximized window before unmaximizings (#32493)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-01-18 15:46:50 -05:00
trop[bot]
2d0d51ec43 docs: fix broken images for symbol server setup (#32523)
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2022-01-18 15:23:07 -05:00
trop[bot]
ef1243803f fix: corrupted title of alert dialog (#32467)
Co-authored-by: Takao Baba <babatakao@gmail.com>
2022-01-17 16:35:05 +09:00
trop[bot]
9629d8fc58 fix: optional postMessage transfer arg (#32457)
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2022-01-14 09:42:52 +09:00
Pedro Pontes
744e0ead87 chore: cherry-pick f0a63e1f361f from chromium (#32013)
* chore: cherry-pick f0a63e1f361f from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-13 12:35:18 +09:00
Milan Burda
be8f54ba8a build: pin colors to v1.4.0 in package.json (#32420) (#32443)
Co-authored-by: Charles Kerr <charles@charleskerr.com>
2022-01-13 10:46:11 +09:00
Pedro Pontes
ec0b62ea65 chore: cherry-pick 27eb11a28555 from chromium (#32016)
* chore: cherry-pick 27eb11a28555 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-13 09:36:14 +09:00
Pedro Pontes
e4c86842c3 chore: cherry-pick f781748dcb3c from chromium (#32022)
* chore: cherry-pick f781748dcb3c from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-12 16:45:31 +09:00
Sudowoodo Release Bot
771261f6b7 Bump v14.2.4 2022-01-11 11:18:50 -08:00
Pedro Pontes
8174553f84 chore: cherry-pick 855df1837e from chromium (#32033)
Co-authored-by: Electron Bot <electron@github.com>
2022-01-11 16:27:05 +01:00
trop[bot]
35561d7fb0 fix: incorrect skipTransformProcessType option parsing in win.setVisibleOnAllWorkspaces() (#32395)
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2022-01-11 14:45:28 +09:00
Pedro Pontes
3c9318cc17 chore: cherry-pick bdffa0ea5148 from angle (#32185)
* chore: cherry-pick bdffa0ea5148 from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-11 14:43:33 +09:00
Pedro Pontes
67a565310a chore: cherry-pick dbde8795233a from chromium (#32211)
* chore: cherry-pick dbde8795233a from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-11 14:42:10 +09:00
Pedro Pontes
e29c6aef2c chore: cherry-pick 05e69c75905f from angle (#32191)
* chore: cherry-pick 05e69c75905f from angle

* chore: update patches

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-10 16:16:06 -06:00
Milan Burda
d4edab2c9f docs: left is a valid mode in contents.openDevTools() options (#32372) (#32405) 2022-01-10 16:56:28 -05:00
Pedro Pontes
0e0bf5495b chore: cherry-pick 891020ed64d4 from angle (#32224)
* chore: cherry-pick 891020ed64d4 from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-10 12:49:19 +01:00
Pedro Pontes
bb7de2d7a0 chore: cherry-pick 2b98abd8cb6c from angle (#32188)
* chore: cherry-pick 2b98abd8cb6c from angle

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-06 16:14:17 -05:00
trop[bot]
2dc9091b3e fix: rename patch file to .patch to conform to naming standard which utilizes .gitattributes settings (#32344)
* Rename patch file to .patch to conform to naming standard which utilizes .gitattributes settings

* chore: remove backport patches

* chore: rename patch (previously added as new patch)

Co-authored-by: stsean <stsean@justin.tv>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2022-01-06 09:19:41 +09:00
trop[bot]
9af52185e1 fix: window.open not overriding parent's webPreferences (#32325)
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2022-01-06 09:18:48 +09:00
Micha Hanselmann
52c878b6bc fix: older systems crash when playing media files (#32349)
Co-authored-by: Micha Hanselmann <mhanselmann@microsoft.com>
2022-01-05 11:31:54 -08:00
Pedro Pontes
7cdf38c3fc chore: cherry-pick da11d71a0227 from chromium (#32182)
* chore: cherry-pick da11d71a0227 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
Co-authored-by: Electron Bot <electron@github.com>
2022-01-04 13:56:54 +01:00
trop[bot]
7a1c596d63 fix: #32141 register wrong command for setAsDefaultProtocolClient for windows (#32328)
Co-authored-by: Shubham-Kumar-2000 <shukhu10@gmail.com>
2022-01-04 16:08:40 +09:00
Pedro Pontes
c7a7e0f56b chore: cherry-pick 2b978fb482 from chromium (#32233)
Co-authored-by: Electron Bot <electron@github.com>
2022-01-04 10:09:43 +09:00
Pedro Pontes
b0d4474536 chore: cherry-pick 04a58fedd5 from v8 (#32236)
Co-authored-by: Electron Bot <electron@github.com>
2022-01-04 10:07:23 +09:00
Pedro Pontes
8ae3f8bf55 chore: cherry-pick 6bb320d134b1 from chromium (#32010)
* chore: cherry-pick 6bb320d134b1 from chromium

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-03 15:16:22 -05:00
Pedro Pontes
24e385f54b chore: cherry-pick 809830f1b3 from webrtc (#32227)
* chore: cherry-pick 809830f1b3 from webrtc

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2022-01-03 15:07:36 -05:00
Pedro Pontes
91b8fa26b8 chore: cherry-pick 05ccacee14 from v8. (#32217)
Co-authored-by: Electron Bot <electron@github.com>
2022-01-03 09:35:55 +01:00
trop[bot]
105ab32645 fix: check for single bluetooth listener (#32242)
Co-authored-by: VerteDinde <khammond@slack-corp.com>
2021-12-20 12:48:03 +09:00
Pedro Pontes
8e5e91cfc1 chore: cherry-pick 418c276ef228 from v8 (#32193)
* chore: cherry-pick 418c276ef228 from v8

* chore: update patches

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2021-12-20 12:45:52 +09:00
Sudowoodo Release Bot
582eb5c9bd Bump v14.2.3 2021-12-16 09:12:59 -08:00
trop[bot]
8fe397cecc fix: ensure bluetooth devices are not returned by default (#32196)
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-12-15 19:51:32 -08:00
Keeley Hammond
972213b032 build: add CI path-filtering for docs-only changes (#32058)
* build: add CI path-filtering for docs-only changes (#31741)

build: (wip) initial dynamic config research

* build: (wip) test path filtering option

* build: (wip) remove doc-only script, use path filtering to check changes

* build: (wip) add docker image with Electron dependencies

* build: (wip) clean up config

* build (wip): readd parameters, executors and env*s

* build: re-add steps and commands

* build: change doc-only to ts-compile-doc-only

* build: re-add workflows and jobs

* build: split configs to setup & build

* build: move lint to "always run" config

* build: clean up, remove old reference config

* build: bump to path-filtering 0.1.0

* build: remove ts-compile step from build-linux

* build: remove nightly-linux-release-test, linux-checks-nightly

* build: don't run build on publish

* build: set base-revision to main (runs branch vs commit)

* build: update config from chromium roll

* build: don't use python3 on sync-step

reverts ea6087e343, which doesn't apply to 14-x-y

* build: account for path-filtering workflow in release-build script (#32063)

* build: account for path-filtering workflow in release-build script

* build: update syntax for workflow id

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2021-12-06 11:36:34 +09:00
trop[bot]
5e36eed062 fix: gtk_native_dialog_run() calls show() internally (#32080)
In the synchronous code path, gtk_native_dialog_run() will call
gtk_native_dialog_show(). Previously this was causing an assertion to be
hit at run time.

Co-authored-by: Tristan Partin <tristan@partin.io>
2021-12-06 11:30:14 +09:00
84 changed files with 8606 additions and 2680 deletions

2416
.circleci/build_config.yml Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2
.github/CODEOWNERS vendored
View File

@@ -4,7 +4,7 @@
# https://git-scm.com/docs/gitignore
# Upgrades WG
/patches/ @electron/wg-upgrades
/patches/ @electron/wg-upgrades @electron/wg-security
DEPS @electron/wg-upgrades
# Releases WG

View File

@@ -1 +1 @@
14.2.2
14.2.7

View File

@@ -731,6 +731,8 @@ first available device will be selected. `callback` should be called with
`deviceId` to be selected, passing empty string to `callback` will
cancel the request.
If no event listener is added for this event, all bluetooth requests will be cancelled.
```javascript
const { app, BrowserWindow } = require('electron')
@@ -1595,7 +1597,7 @@ app.whenReady().then(() => {
* `options` Object (optional)
* `mode` String - Opens the devtools with specified dock state, can be
`right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
`left`, `right`, `bottom`, `undocked`, `detach`. Defaults to last used dock state.
In `undocked` mode it's possible to dock back. In `detach` mode it's not.
* `activate` Boolean (optional) - Whether to bring the opened devtools window
to the foreground. The default is `true`.

View File

@@ -65,6 +65,9 @@ window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIn
`features` will be passed to any registered `webContents`'s
`did-create-window` event handler in the `options` argument.
* `frameName` follows the specification of `windowName` located in the [native documentation](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#parameters).
* When opening `about:blank`, the child window's `WebPreferences` will be copied
from the parent window, and there is no way to override it because Chromium
skips browser side navigation in this case.
To customize or cancel the creation of the window, you can optionally set an
override handler with `webContents.setWindowOpenHandler()` from the main

View File

@@ -43,8 +43,9 @@ SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\sym
## Using the symbol server in Visual Studio
![Tools -> Options](https://mdn.mozillademos.org/files/733/symbol-server-vc8express-menu.jpg)
![Symbols Settings](https://mdn.mozillademos.org/files/2497/2005_options.gif)
![Tools -> Options](../images/vs-tools-options.png)
![Symbols Settings](../images/vs-options-debugging-symbols.png)
## Troubleshooting: Symbols will not load

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -669,16 +669,6 @@ WebContents.prototype._init = function () {
postBody
};
windowOpenOverriddenOptions = this._callWindowOpenHandler(event, details);
// if attempting to use this API with the deprecated new-window event,
// windowOpenOverriddenOptions will always return null. This ensures
// short-term backwards compatibility until new-window is removed.
const parsedFeatures = parseFeatures(rawFeatures);
const overriddenFeatures: BrowserWindowConstructorOptions = {
...parsedFeatures.options,
webPreferences: parsedFeatures.webPreferences
};
windowOpenOverriddenOptions = windowOpenOverriddenOptions || overriddenFeatures;
if (!event.defaultPrevented) {
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
// Allow setting of backgroundColor as a webPreference even though
@@ -688,9 +678,19 @@ WebContents.prototype._init = function () {
transparent: windowOpenOverriddenOptions.transparent,
...windowOpenOverriddenOptions.webPreferences
} : undefined;
this._setNextChildWebPreferences(
makeWebPreferences({ embedder: event.sender, secureOverrideWebPreferences })
);
// TODO(zcbenz): The features string is parsed twice: here where it is
// passed to C++, and in |makeBrowserWindowOptions| later where it is
// not actually used since the WebContents is created here.
// We should be able to remove the latter once the |nativeWindowOpen|
// option is removed.
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
// Parameters should keep same with |makeBrowserWindowOptions|.
const webPreferences = makeWebPreferences({
embedder: event.sender,
insecureParsedWebPreferences: parsedWebPreferences,
secureOverrideWebPreferences
});
this._setNextChildWebPreferences(webPreferences);
}
});
@@ -738,6 +738,14 @@ WebContents.prototype._init = function () {
}
});
this.on('select-bluetooth-device', (event, devices, callback) => {
if (this.listenerCount('select-bluetooth-device') === 1) {
// Cancel it if there are no handlers
event.preventDefault();
callback('');
}
});
const event = process._linkedBinding('electron_browser_event').createEmpty();
app.emit('web-contents-created', event, this);

View File

@@ -217,6 +217,10 @@ function makeBrowserWindowOptions ({ embedder, features, overrideOptions }: {
height: 600,
...parsedOptions,
...overrideOptions,
// Note that for |nativeWindowOpen: true| the WebContents is created in
// |api::WebContents::WebContentsCreatedWithFullParams|, with prefs
// parsed in the |-will-add-new-contents| event.
// The |webPreferences| here is only used by |nativeWindowOpen: false|.
webPreferences: makeWebPreferences({
embedder,
insecureParsedWebPreferences: parsedWebPreferences,

View File

@@ -1,6 +1,6 @@
{
"name": "electron",
"version": "14.2.2",
"version": "14.2.7",
"repository": "https://github.com/electron/electron",
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
"devDependencies": {
@@ -33,7 +33,7 @@
"asar": "^3.0.3",
"aws-sdk": "^2.727.1",
"check-for-leaks": "^1.2.1",
"colors": "^1.4.0",
"colors": "1.4.0",
"dotenv-safe": "^4.0.4",
"dugite": "^1.45.0",
"eslint": "^7.4.0",

View File

@@ -1 +1,9 @@
fix_integer_overflow_in_blocklayoutencoder.patch
cherry-pick-bdffa0ea5148.patch
cherry-pick-05e69c75905f.patch
cherry-pick-891020ed64d4.patch
cherry-pick-2b98abd8cb6c.patch
cherry-pick-cc44ae61f37b.patch
m98_vulkan_fix_vkcmdresolveimage_extents.patch
m98_vulkan_fix_vkcmdresolveimage_offsets.patch
cherry-pick-49e8ff16f1fe.patch

View File

@@ -0,0 +1,118 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lingfeng Yang <lfy@google.com>
Date: Wed, 1 Dec 2021 18:16:14 -0800
Subject: M96: Vulkan: remove staged updates on storage set
Previously we would allow staged updates to bigger versions of a texture
to go through even if the texture was redefined via glTexStorage*.
Bug: chromium:1262080
Change-Id: I9d861fed68d4a1fdcd0777b97caf729cc74c595e
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3312718
Reviewed-by: Charlie Lao <cclao@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
Commit-Queue: Lingfeng Yang <lfy@google.com>
(cherry picked from commit 929c8ed4e8c3912cf027d843e7a2af47b21e5612)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3328001
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index 68e7ffa73781b8431188d53c97d388bd1c7ffb52..ee159cbd3621a655f00ccf2eb24c8711e050da8b 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1236,6 +1236,10 @@ angle::Result TextureVk::setStorageMultisample(const gl::Context *context,
{
releaseAndDeleteImageAndViews(contextVk);
}
+ else if (mImage)
+ {
+ mImage->releaseStagingBuffer(contextVk->getRenderer());
+ }
const vk::Format &format = renderer->getFormat(internalformat);
ANGLE_TRY(ensureImageAllocated(contextVk, format));
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index f0b48cb803981d1fdc7c30093c7bf7c0d170dece..9a20527ae5b8aa33ad2fcb9572eb2180710cd31c 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -9547,6 +9547,73 @@ void main()
glUnmapBuffer(GL_SHADER_STORAGE_BUFFER);
}
+class TextureChangeStorageUploadTest : public ANGLETest
+{
+ protected:
+ TextureChangeStorageUploadTest()
+ {
+ setWindowWidth(256);
+ setWindowHeight(256);
+ setConfigRedBits(8);
+ setConfigGreenBits(8);
+ setConfigBlueBits(8);
+ setConfigAlphaBits(8);
+ }
+
+ void testSetUp() override
+ {
+ mProgram = CompileProgram(essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+ if (mProgram == 0)
+ {
+ FAIL() << "shader compilation failed.";
+ }
+
+ mColorLocation = glGetUniformLocation(mProgram, essl1_shaders::ColorUniform());
+
+ glUseProgram(mProgram);
+
+ glClearColor(0, 0, 0, 0);
+ glClearDepthf(0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glEnable(GL_BLEND);
+ glDisable(GL_DEPTH_TEST);
+
+ glGenTextures(1, &mTexture);
+ ASSERT_GL_NO_ERROR();
+ }
+
+ void testTearDown() override
+ {
+ glDeleteTextures(1, &mTexture);
+ glDeleteProgram(mProgram);
+ }
+
+ GLuint mProgram;
+ GLint mColorLocation;
+ GLuint mTexture;
+};
+
+// Verify that respecifying storage and re-uploading doesn't crash.
+TEST_P(TextureChangeStorageUploadTest, Basic)
+{
+ constexpr int kImageSize = 8; // 4 doesn't trip ASAN
+ constexpr int kSmallerImageSize = kImageSize / 2;
+ EXPECT_GT(kImageSize, kSmallerImageSize);
+ EXPECT_GT(kSmallerImageSize / 2, 0);
+
+ std::array<GLColor, kImageSize * kImageSize> kColor;
+
+ glBindTexture(GL_TEXTURE_2D, mTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kImageSize, kImageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kColor.data());
+ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, kSmallerImageSize, kSmallerImageSize);
+ // need partial update to sidestep optimizations that remove the full upload
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kSmallerImageSize / 2, kSmallerImageSize / 2, GL_RGBA,
+ GL_UNSIGNED_BYTE, kColor.data());
+ EXPECT_GL_NO_ERROR();
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
#define ES2_EMULATE_COPY_TEX_IMAGE() \
@@ -9660,4 +9727,6 @@ ANGLE_INSTANTIATE_TEST_ES31_AND(TextureBufferTestES31, WithDirectSPIRVGeneration
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CopyImageTestES31);
ANGLE_INSTANTIATE_TEST_ES31_AND(CopyImageTestES31, WithDirectSPIRVGeneration(ES31_VULKAN()));
+ANGLE_INSTANTIATE_TEST_ES3(TextureChangeStorageUploadTest);
+
} // anonymous namespace

View File

@@ -0,0 +1,96 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Tue, 30 Nov 2021 23:48:30 -0500
Subject: M96: Vulkan: Fix image respecify's usage tracking
When respecifying an image due to mip level count changes, the previous
image is staged as an update to the new image. The resource usage info
was not being transferred to the image being staged as an update,
causing it to be prematurely deleted.
Test based on one authored by sugoi@google.com.
Bug: chromium:1270658
Bug: angleproject:4835
Change-Id: I9810f8940e0107bc8a04fa3fb9c26a045c0d689c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3318257
Reviewed-by: Lingfeng Yang <lfy@google.com>
diff --git a/src/libANGLE/renderer/vulkan/ResourceVk.cpp b/src/libANGLE/renderer/vulkan/ResourceVk.cpp
index efb04acf0fe5dc7c2d860ac8cc33dbe30691c4a3..e2cd1e3a96b1fa4e034efe6ed78ea1a787af6af6 100644
--- a/src/libANGLE/renderer/vulkan/ResourceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ResourceVk.cpp
@@ -26,6 +26,12 @@ Resource::Resource(Resource &&other) : Resource()
mUse = std::move(other.mUse);
}
+Resource &Resource::operator=(Resource &&rhs)
+{
+ std::swap(mUse, rhs.mUse);
+ return *this;
+}
+
Resource::~Resource()
{
mUse.release();
diff --git a/src/libANGLE/renderer/vulkan/ResourceVk.h b/src/libANGLE/renderer/vulkan/ResourceVk.h
index 67440122bf7fa0f72b5412816853b2eddd770fd4..abab9900b7361c8564cb1ad30e0841eaf873ee2e 100644
--- a/src/libANGLE/renderer/vulkan/ResourceVk.h
+++ b/src/libANGLE/renderer/vulkan/ResourceVk.h
@@ -192,6 +192,7 @@ class Resource : angle::NonCopyable
protected:
Resource();
Resource(Resource &&other);
+ Resource &operator=(Resource &&rhs);
// Current resource lifetime.
SharedResourceUse mUse;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index e8378d01aa29b98ea4b6a9db270c41b19ba1809a..0c21d3ea8b075cbd0fbbe95d8f4754647276c21f 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -6020,6 +6020,9 @@ void ImageHelper::stageSelfAsSubresourceUpdates(ContextVk *contextVk,
// Move the necessary information for staged update to work, and keep the rest as part of this
// object.
+ // Usage info
+ prevImage->get().Resource::operator=(std::move(*this));
+
// Vulkan objects
prevImage->get().mImage = std::move(mImage);
prevImage->get().mDeviceMemory = std::move(mDeviceMemory);
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
index 4db00e78a7d2f7375fdcb9228fbdc83395973125..8a6d01ca36a84a9e294de3f6f0114ee7a54e1d9a 100644
--- a/src/tests/gl_tests/MipmapTest.cpp
+++ b/src/tests/gl_tests/MipmapTest.cpp
@@ -2106,6 +2106,30 @@ TEST_P(MipmapTestES3, GenerateMipmapZeroSize)
glGenerateMipmap(GL_TEXTURE_3D);
}
+// Test that reducing the size of the mipchain by resizing the base image then deleting it doesn't
+// cause a crash. Issue found by fuzzer.
+TEST_P(MipmapTestES3, ResizeBaseMipTo1x1ThenDelete)
+{
+ GLTexture tex;
+ glBindTexture(GL_TEXTURE_2D, tex);
+
+ std::vector<GLColor> data(2, GLColor::blue);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
+ glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
+
+ clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
+
+ data[0] = GLColor::green;
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data.data());
+
+ clearAndDrawQuad(m2DProgram, getWindowWidth(), getWindowHeight());
+
+ tex.reset();
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
ANGLE_INSTANTIATE_TEST_ES2_AND_ES3(MipmapTest);

View File

@@ -0,0 +1,381 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Tue, 25 Jan 2022 12:15:16 -0500
Subject: M99: Vulkan: Fix texture array level redefinition
When a level of a texture is redefined, all staged updates to that level
should be removed, not the ones specific to the new layers. The bug
fixed was that if the texture was redefined to have its number of layers
changed, the staged higher-layer-count update to the image was not
removed.
Bug: chromium:1289383
Change-Id: Iab79c38d846d1abbdd92e11b1b60a3adf0fbde4c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3441309
Reviewed-by: Lingfeng Yang <lfy@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index ee159cbd3621a655f00ccf2eb24c8711e050da8b..859e017d491f49d76db8c5fdd4c76ff51759075c 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1553,12 +1553,25 @@ angle::Result TextureVk::redefineLevel(const gl::Context *context,
if (mImage != nullptr)
{
- // If there is any staged changes for this index, we can remove them since we're going to
+ // If there are any staged changes for this index, we can remove them since we're going to
// override them with this call.
gl::LevelIndex levelIndexGL(index.getLevelIndex());
uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
- mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
- index.getLayerCount());
+ if (gl::IsArrayTextureType(index.getType()))
+ {
+ // A multi-layer texture is being redefined, remove all updates to this level; the
+ // number of layers may have changed.
+ mImage->removeStagedUpdates(contextVk, levelIndexGL, levelIndexGL);
+ }
+ else
+ {
+ // Otherwise remove only updates to this layer. For example, cube map updates can be
+ // done through glTexImage2D, one per cube face (i.e. layer) and so should not remove
+ // updates to the other layers.
+ ASSERT(index.getLayerCount() == 1);
+ mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
+ index.getLayerCount());
+ }
if (mImage->valid())
{
diff --git a/src/tests/gl_tests/MipmapTest.cpp b/src/tests/gl_tests/MipmapTest.cpp
index 8a6d01ca36a84a9e294de3f6f0114ee7a54e1d9a..957a52304edc9aa245f9f21e5557cc105cbad789 100644
--- a/src/tests/gl_tests/MipmapTest.cpp
+++ b/src/tests/gl_tests/MipmapTest.cpp
@@ -1686,6 +1686,106 @@ TEST_P(MipmapTestES3, MipmapsForTexture3D)
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
}
+// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
+// in the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(MipmapTestES3, TextureArrayRedefineThenGenerateMipmap)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
+
+ // Fill the whole texture with red, then redefine it and fill with green
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ // Generate mipmaps
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mArrayProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
+// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
+// the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(MipmapTestES3, TextureArrayUseThenRedefineThenGenerateMipmap)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture);
+
+ // Fill the whole texture with red.
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ // Generate mipmap
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mArrayProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Draw the fourth slice
+ glUniform1i(mTextureArraySliceUniformLocation, 3);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Redefine the image and fill with green
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ // Generate mipmap
+ glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mArrayProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
// Create a 2D texture with levels 0-2, call GenerateMipmap with base level 1 so that level 0 stays
// the same, and then sample levels 0 and 2.
// GLES 3.0.4 section 3.8.10:
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index f1df6b5b947ca2684a9db7bd800f5de59ce0c64c..54ab7910ddeacf740a27816c6b9c5a9ce12cba68 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -1025,31 +1025,37 @@ class SamplerArrayAsFunctionParameterTest : public SamplerArrayTest
class Texture2DArrayTestES3 : public TexCoordDrawTest
{
protected:
- Texture2DArrayTestES3() : TexCoordDrawTest(), m2DArrayTexture(0), mTextureArrayLocation(-1) {}
+ Texture2DArrayTestES3()
+ : TexCoordDrawTest(),
+ m2DArrayTexture(0),
+ mTextureArrayLocation(-1),
+ mTextureArraySliceUniformLocation(-1)
+ {}
const char *getVertexShaderSource() override
{
- return "#version 300 es\n"
- "out vec2 texcoord;\n"
- "in vec4 position;\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
- " texcoord = (position.xy * 0.5) + 0.5;\n"
- "}\n";
+ return R"(#version 300 es
+out vec2 texcoord;
+in vec4 position;
+void main()
+{
+ gl_Position = vec4(position.xy, 0.0, 1.0);
+ texcoord = (position.xy * 0.5) + 0.5;
+})";
}
const char *getFragmentShaderSource() override
{
- return "#version 300 es\n"
- "precision highp float;\n"
- "uniform highp sampler2DArray tex2DArray;\n"
- "in vec2 texcoord;\n"
- "out vec4 fragColor;\n"
- "void main()\n"
- "{\n"
- " fragColor = texture(tex2DArray, vec3(texcoord.x, texcoord.y, 0.0));\n"
- "}\n";
+ return R"(#version 300 es
+precision highp float;
+uniform highp sampler2DArray tex2DArray;
+uniform int slice;
+in vec2 texcoord;
+out vec4 fragColor;
+void main()
+{
+ fragColor = texture(tex2DArray, vec3(texcoord, float(slice)));
+})";
}
void testSetUp() override
@@ -1061,6 +1067,9 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
mTextureArrayLocation = glGetUniformLocation(mProgram, "tex2DArray");
ASSERT_NE(-1, mTextureArrayLocation);
+ mTextureArraySliceUniformLocation = glGetUniformLocation(mProgram, "slice");
+ ASSERT_NE(-1, mTextureArraySliceUniformLocation);
+
glGenTextures(1, &m2DArrayTexture);
ASSERT_GL_NO_ERROR();
}
@@ -1073,6 +1082,7 @@ class Texture2DArrayTestES3 : public TexCoordDrawTest
GLuint m2DArrayTexture;
GLint mTextureArrayLocation;
+ GLint mTextureArraySliceUniformLocation;
};
class TextureSizeTextureArrayTest : public TexCoordDrawTest
@@ -1715,28 +1725,28 @@ class Texture2DArrayIntegerTestES3 : public Texture2DArrayTestES3
const char *getVertexShaderSource() override
{
- return "#version 300 es\n"
- "out vec2 texcoord;\n"
- "in vec4 position;\n"
- "void main()\n"
- "{\n"
- " gl_Position = vec4(position.xy, 0.0, 1.0);\n"
- " texcoord = (position.xy * 0.5) + 0.5;\n"
- "}\n";
+ return R"(#version 300 es
+out vec2 texcoord;
+in vec4 position;
+void main()
+{
+ gl_Position = vec4(position.xy, 0.0, 1.0);
+ texcoord = (position.xy * 0.5) + 0.5;
+})";
}
const char *getFragmentShaderSource() override
{
- return "#version 300 es\n"
- "precision highp float;\n"
- "uniform highp usampler2DArray tex2DArray;\n"
- "in vec2 texcoord;\n"
- "out vec4 fragColor;\n"
- "void main()\n"
- "{\n"
- " fragColor = vec4(texture(tex2DArray, vec3(texcoord.x, texcoord.y, "
- "0.0)))/255.0;\n"
- "}\n";
+ return R"(#version 300 es
+precision highp float;
+uniform highp usampler2DArray tex2DArray;
+uniform int slice;
+in vec2 texcoord;
+out vec4 fragColor;
+void main()
+{
+ fragColor = vec4(texture(tex2DArray, vec3(texcoord, slice)))/255.0;
+})";
}
};
@@ -4972,6 +4982,94 @@ TEST_P(Texture2DArrayTestES3, DrawWithLevelsOutsideRangeWithInconsistentDimensio
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::cyan);
}
+// Create a 2D array, then immediately redefine it to have fewer layers. Regression test for a bug
+// in the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(Texture2DArrayTestES3, TextureArrayRedefineThenUse)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+
+ // Fill the whole texture with red, then redefine it and fill with green
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
+// Create a 2D array, use it, then redefine it to have fewer layers. Regression test for a bug in
+// the Vulkan backend where the old higher-layer-count data upload was not removed.
+TEST_P(Texture2DArrayTestES3, TextureArrayUseThenRedefineThenUse)
+{
+ int px = getWindowWidth() / 2;
+ int py = getWindowHeight() / 2;
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, m2DArrayTexture);
+
+ // Fill the whole texture with red.
+ std::vector<GLColor> pixelsRed(2 * 2 * 4, GLColor::red);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsRed.data());
+
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_GL_NO_ERROR();
+
+ glUseProgram(mProgram);
+ EXPECT_GL_NO_ERROR();
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Draw the fourth slice
+ glUniform1i(mTextureArraySliceUniformLocation, 3);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
+
+ // Redefine the image and fill with green
+ std::vector<GLColor> pixelsGreen(2 * 2 * 2, GLColor::green);
+ glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixelsGreen.data());
+
+ // Draw the first slice
+ glUniform1i(mTextureArraySliceUniformLocation, 0);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+
+ // Draw the second slice
+ glUniform1i(mTextureArraySliceUniformLocation, 1);
+ drawQuad(mProgram, "position", 0.5f);
+ EXPECT_GL_NO_ERROR();
+ EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
+}
+
// Test that texture completeness is updated if texture max level changes.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)

View File

@@ -0,0 +1,163 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jonah Ryan-Davis <jonahr@google.com>
Date: Mon, 22 Nov 2021 14:30:52 -0500
Subject: Ignore the pixel unpack state for compressed textures.
From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding
a compressed texture image
This was causing a bad access when calling compressedTexImage3D
with GL_UNPACK_IMAGE_HEIGHT greater than the image height.
Bug: chromium:1267496
Change-Id: I9b1f4c645548af64f2695fd23262225a1ad07cd7
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3296622
Commit-Queue: Jonah Ryan-Davis <jonahr@google.com>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
(cherry picked from commit 870f458f507ff7ba0f67b28a30a27955ce79dd3e)
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3309097
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 1e989ebaffb25da1a1a281afa0610a9088232119..67356b5bd47e96e98e2a5e4880a71f5042ca918d 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -4923,7 +4923,9 @@ void Context::compressedTexImage2D(TextureTarget target,
Extents size(width, height, 1);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
internalformat, size, imageSize,
static_cast<const uint8_t *>(data)));
}
@@ -4955,7 +4957,9 @@ void Context::compressedTexImage3D(TextureTarget target,
Extents size(width, height, depth);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, mState.getUnpackState(), target, level,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedImage(this, PixelUnpackState(), target, level,
internalformat, size, imageSize,
static_cast<const uint8_t *>(data)));
}
@@ -4989,8 +4993,10 @@ void Context::compressedTexSubImage2D(TextureTarget target,
Box area(xoffset, yoffset, 0, width, height, 1);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
- area, format, imageSize,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
+ format, imageSize,
static_cast<const uint8_t *>(data)));
}
@@ -5031,8 +5037,10 @@ void Context::compressedTexSubImage3D(TextureTarget target,
Box area(xoffset, yoffset, zoffset, width, height, depth);
Texture *texture = getTextureByTarget(target);
- ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, mState.getUnpackState(), target, level,
- area, format, imageSize,
+ // From OpenGL ES 3 spec: All pixel storage modes are ignored when decoding a compressed texture
+ // image. So we use an empty PixelUnpackState.
+ ANGLE_CONTEXT_TRY(texture->setCompressedSubImage(this, PixelUnpackState(), target, level, area,
+ format, imageSize,
static_cast<const uint8_t *>(data)));
}
diff --git a/src/tests/gl_tests/TextureTest.cpp b/src/tests/gl_tests/TextureTest.cpp
index 9a20527ae5b8aa33ad2fcb9572eb2180710cd31c..f1df6b5b947ca2684a9db7bd800f5de59ce0c64c 100644
--- a/src/tests/gl_tests/TextureTest.cpp
+++ b/src/tests/gl_tests/TextureTest.cpp
@@ -5011,6 +5011,43 @@ TEST_P(Texture2DTestES3, TextureCompletenessChangesWithMaxLevel)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::black);
}
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture3DTestES3, PixelUnpackStateTexImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5);
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D);
+
+ uint8_t data[64] = {0};
+ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64,
+ data);
+ EXPECT_GL_NO_ERROR();
+}
+
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture3DTestES3, PixelUnpackStateTexSubImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glBindTexture(GL_TEXTURE_2D_ARRAY, mTexture3D);
+
+ uint8_t data[64] = {0};
+ glCompressedTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 4, 0, 64,
+ data);
+ EXPECT_GL_NO_ERROR();
+
+ glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5);
+
+ glCompressedTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 4, 4, 4,
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 64, data);
+ EXPECT_GL_NO_ERROR();
+}
+
// Test that 3D texture completeness is updated if texture max level changes.
// GLES 3.0.4 section 3.8.13 Texture completeness
TEST_P(Texture3DTestES3, Texture3DCompletenessChangesWithMaxLevel)
@@ -5690,6 +5727,41 @@ TEST_P(Texture2DTestES3, TextureCOMPRESSEDSRGB8ETC2ImplicitAlpha1)
EXPECT_PIXEL_ALPHA_EQ(0, 0, 255);
}
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture2DTestES3, PixelUnpackStateTexImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5);
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+
+ uint8_t data[16] = {0};
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data);
+ EXPECT_GL_NO_ERROR();
+}
+
+// Test that compressed textures ignore the pixel unpack state.
+// (https://crbug.org/1267496)
+TEST_P(Texture2DTestES3, PixelUnpackStateTexSubImage)
+{
+ ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_texture_compression_s3tc") &&
+ !IsGLExtensionEnabled("GL_ANGLE_texture_compression_dxt3"));
+
+ glBindTexture(GL_TEXTURE_2D, mTexture2D);
+
+ uint8_t data[16] = {0};
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 4, 4, 0, 16, data);
+ EXPECT_GL_NO_ERROR();
+
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 5);
+
+ glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 16,
+ data);
+ EXPECT_GL_NO_ERROR();
+}
+
// Copied from Texture2DTest::TexStorage
// Test that glTexSubImage2D works properly when glTexStorage2DEXT has initialized the image with a
// default color.

View File

@@ -0,0 +1,169 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Thu, 2 Dec 2021 14:30:42 -0500
Subject: M96: Fix changing attached renderbuffer from MSRTT to non-MSRTT
FramebufferAttachment::mRenderToTextureSamples was never updated if the
renderbuffer storage was changed after attaching to framebuffer.
Bug: chromium:1272068
Change-Id: Icddbb5650354ea16d06c49532d6a8d0ae962ab5f
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3320923
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libANGLE/FramebufferAttachment.cpp b/src/libANGLE/FramebufferAttachment.cpp
index 00714d0a0303050893abcd9564e760b22d9b2de5..720d3000d42e6c8c23214e66eee4aa6982216a60 100644
--- a/src/libANGLE/FramebufferAttachment.cpp
+++ b/src/libANGLE/FramebufferAttachment.cpp
@@ -129,7 +129,7 @@ void FramebufferAttachment::attach(const Context *context,
mNumViews = numViews;
mBaseViewIndex = baseViewIndex;
mIsMultiview = isMultiview;
- mRenderToTextureSamples = samples;
+ mRenderToTextureSamples = type == GL_RENDERBUFFER ? kDefaultRenderToTextureSamples : samples;
resource->onAttach(context, framebufferSerial);
if (mResource != nullptr)
@@ -222,6 +222,29 @@ GLint FramebufferAttachment::getBaseViewIndex() const
return mBaseViewIndex;
}
+bool FramebufferAttachment::isRenderToTexture() const
+{
+ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE);
+
+ if (mType == GL_RENDERBUFFER)
+ {
+ return getRenderbuffer()->getMultisamplingMode() ==
+ MultisamplingMode::MultisampledRenderToTexture;
+ }
+ return mRenderToTextureSamples != kDefaultRenderToTextureSamples;
+}
+
+GLsizei FramebufferAttachment::getRenderToTextureSamples() const
+{
+ ASSERT(mRenderToTextureSamples == kDefaultRenderToTextureSamples || mType == GL_TEXTURE);
+
+ if (mType == GL_RENDERBUFFER)
+ {
+ return getRenderbuffer()->getState().getSamples();
+ }
+ return mRenderToTextureSamples;
+}
+
Texture *FramebufferAttachment::getTexture() const
{
return rx::GetAs<Texture>(mResource);
diff --git a/src/libANGLE/FramebufferAttachment.h b/src/libANGLE/FramebufferAttachment.h
index 013a1e02874e4df3680e9b4a56f74aaf94d188a9..6235b42cf2fdfcb0e9fa33242b458934f1afa5b0 100644
--- a/src/libANGLE/FramebufferAttachment.h
+++ b/src/libANGLE/FramebufferAttachment.h
@@ -117,11 +117,8 @@ class FramebufferAttachment final
bool isMultiview() const;
GLint getBaseViewIndex() const;
- bool isRenderToTexture() const
- {
- return mRenderToTextureSamples != kDefaultRenderToTextureSamples;
- }
- GLsizei getRenderToTextureSamples() const { return mRenderToTextureSamples; }
+ bool isRenderToTexture() const;
+ GLsizei getRenderToTextureSamples() const;
// The size of the underlying resource the attachment points to. The 'depth' value will
// correspond to a 3D texture depth or the layer count of a 2D array texture. For Surfaces and
@@ -195,6 +192,14 @@ class FramebufferAttachment final
GLsizei mNumViews;
bool mIsMultiview;
GLint mBaseViewIndex;
+ // A single-sampled texture can be attached to a framebuffer either as single-sampled or as
+ // multisampled-render-to-texture. In the latter case, |mRenderToTextureSamples| will contain
+ // the number of samples. For renderbuffers, the number of samples is inherited from the
+ // renderbuffer itself.
+ //
+ // Note that textures cannot change storage between single and multisample once attached to a
+ // framebuffer. Renderbuffers instead can, and caching the number of renderbuffer samples here
+ // can lead to stale data.
GLsizei mRenderToTextureSamples;
};
@@ -253,8 +258,7 @@ inline Format FramebufferAttachment::getFormat() const
inline GLsizei FramebufferAttachment::getSamples() const
{
- return (mRenderToTextureSamples != kDefaultRenderToTextureSamples) ? getRenderToTextureSamples()
- : getResourceSamples();
+ return isRenderToTexture() ? getRenderToTextureSamples() : getResourceSamples();
}
inline GLsizei FramebufferAttachment::getResourceSamples() const
diff --git a/src/tests/gl_tests/FramebufferTest.cpp b/src/tests/gl_tests/FramebufferTest.cpp
index ff01848daff091d92e4fdce08bc6842a3bdd3ee9..cd733be3ae5c179860d882e305ec84d093a283ed 100644
--- a/src/tests/gl_tests/FramebufferTest.cpp
+++ b/src/tests/gl_tests/FramebufferTest.cpp
@@ -3366,6 +3366,65 @@ void main() {
// This shouldn't crash.
glDrawArrays(GL_POINTS, 0, 1);
+ ASSERT_GL_NO_ERROR();
+}
+
+// Modify renderbuffer attachment samples after bind
+TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySamples)
+{
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+ glUseProgram(program);
+ GLint colorUniformLocation =
+ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
+ ASSERT_NE(colorUniformLocation, -1);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLsizei size = 16;
+ glViewport(0, 0, size, size);
+
+ GLRenderbuffer color;
+ glBindRenderbuffer(GL_RENDERBUFFER, color);
+
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA8, size, size);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size);
+
+ glUniform4f(colorUniformLocation, 1, 0, 0, 1);
+ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+ ASSERT_GL_NO_ERROR();
+}
+
+// Modify renderbuffer attachment size after bind
+TEST_P(FramebufferTest_ES3, BindRenderbufferThenModifySize)
+{
+ ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+ glUseProgram(program);
+ GLint colorUniformLocation =
+ glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
+ ASSERT_NE(colorUniformLocation, -1);
+
+ GLFramebuffer fbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ GLsizei size = 16;
+ glViewport(0, 0, size, size);
+
+ GLRenderbuffer color;
+ glBindRenderbuffer(GL_RENDERBUFFER, color);
+
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size, size);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, color);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, size / 2, size * 2);
+
+ glUniform4f(colorUniformLocation, 1, 0, 0, 1);
+ drawQuad(program, essl1_shaders::PositionAttrib(), 0.5f);
+
+ EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
+ ASSERT_GL_NO_ERROR();
}
ANGLE_INSTANTIATE_TEST_ES2(AddMockTextureNoRenderTargetTest);

View File

@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jamie Madill <jmadill@chromium.org>
Date: Tue, 4 Jan 2022 12:28:55 -0500
Subject: M96: D3D11: Fix OOB access in vertex conversion code.
This could happen when using certain combinations of stride and
offset. Fix the issue by using checked math.
Bug: chromium:1274499
Change-Id: I3e286a30fe128ab4684ee5e172dc9e3345e3b2f4
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3365657
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
index 43fcdc8de5a0d15aacf4b06e0e32df008d78f886..031a12e2b8b0e0dee91087c02cbd2f8b17435a2b 100644
--- a/src/libANGLE/renderer/d3d/VertexDataManager.cpp
+++ b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
@@ -58,17 +58,15 @@ int ElementsInBuffer(const gl::VertexAttribute &attrib,
const gl::VertexBinding &binding,
unsigned int size)
{
- // Size cannot be larger than a GLsizei
- if (size > static_cast<unsigned int>(std::numeric_limits<int>::max()))
- {
- size = static_cast<unsigned int>(std::numeric_limits<int>::max());
- }
+ angle::CheckedNumeric<size_t> bufferSize(size);
+ angle::CheckedNumeric<size_t> stride = ComputeVertexAttributeStride(attrib, binding);
+ angle::CheckedNumeric<size_t> offset = ComputeVertexAttributeOffset(attrib, binding);
+ angle::CheckedNumeric<size_t> elementSize = ComputeVertexAttributeTypeSize(attrib);
+
+ auto elementsInBuffer = (bufferSize - (offset % stride) + (stride - elementSize)) / stride;
+ auto elementsInBufferInt = angle::CheckedNumeric<int>::cast(elementsInBuffer);
- GLsizei stride = static_cast<GLsizei>(ComputeVertexAttributeStride(attrib, binding));
- GLsizei offset = static_cast<GLsizei>(ComputeVertexAttributeOffset(attrib, binding));
- return (size - offset % stride +
- (stride - static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib)))) /
- stride;
+ return elementsInBufferInt.ValueOrDefault(0);
}
// Warning: you should ensure binding really matches attrib.bindingIndex before using this function.

View File

@@ -0,0 +1,112 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 31 Jan 2022 12:07:43 -0500
Subject: M98: Vulkan: Fix vkCmdResolveImage extents
The source framebuffer's extents were accidentally used instead of the
blit area extents.
Bug: chromium:1288020
Change-Id: I5c6128a191deeea2f972dc7f010be9d40c674ce6
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3457022
Reviewed-by: Tim Van Patten <timvp@google.com>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 7d088be90bc7a384ec7d6934bccddea28f8cfa0a..892983bd1ad52c6e0080c977022689c1d6a20ac5 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -1459,8 +1459,8 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
resolveRegion.dstOffset.x = params.destOffset[0];
resolveRegion.dstOffset.y = params.destOffset[1];
resolveRegion.dstOffset.z = 0;
- resolveRegion.extent.width = params.srcExtents[0];
- resolveRegion.extent.height = params.srcExtents[1];
+ resolveRegion.extent.width = params.blitArea.width;
+ resolveRegion.extent.height = params.blitArea.height;
resolveRegion.extent.depth = 1;
vk::PerfCounters &perfCounters = contextVk->getPerfCounters();
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index dddb58fd10e4671e179f1db21781c750d7234460..72e32c27efabe8393ae840a9fef4ce37b3c5088c 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -68,6 +68,7 @@
// the test says. The test also fails on Intel/Vulkan/Windows.
6068 INTEL VULKAN : MultiviewRenderPrimitiveTest.LineLoop/* = SKIP
6068 INTEL VULKAN : MultiviewRenderPrimitiveTest.LineStrip/* = SKIP
+6962 WIN INTEL VULKAN : BlitFramebufferTestES31.PartialResolve/* = SKIP
// Mac
6025 MAC AMD OPENGL : IndexBufferOffsetTestES3.UseAsUBOThenUpdateThenUInt8Index/* = SKIP
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
index 61f462cf4ce20b6fe14e7cab7c77b1498c1c2aa3..02f7d025d52f50fd067aea1b8ef1057afdfd4657 100644
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -2632,6 +2632,67 @@ TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel)
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
}
+// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was using the src extents
+// as the resolve area instead of the area passed to glBlitFramebuffer.
+TEST_P(BlitFramebufferTestES31, PartialResolve)
+{
+ constexpr GLint kWidth = 16;
+ constexpr GLint kHeight = 32;
+
+ // Read framebuffer is multisampled.
+ GLTexture readTexture;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture);
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE);
+
+ GLFramebuffer readFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, readFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
+ readTexture, 0);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(1, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Draw framebuffer is single sampled. It's bound to a texture with base level the same size as
+ // the read framebuffer, but it's bound to mip 1.
+ GLTexture drawTexture;
+ glBindTexture(GL_TEXTURE_2D, drawTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ nullptr);
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ GLFramebuffer drawFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, drawFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 1);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(0, 1, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kHeight / 2, GLColor::green);
+
+ constexpr GLint kResolveX0 = 1;
+ constexpr GLint kResolveY0 = 2;
+ constexpr GLint kResolveX1 = 4;
+ constexpr GLint kResolveY1 = 6;
+
+ // Resolve only a portion of the read framebuffer.
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
+ glBlitFramebuffer(kResolveX0, kResolveY0, kResolveX1, kResolveY1, kResolveX0, kResolveY0,
+ kResolveX1, kResolveY1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth / 2, kResolveY0, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kResolveX0, kHeight / 2, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(kResolveX1, 0, kWidth / 2 - kResolveX1, kHeight / 2, GLColor::green);
+ EXPECT_PIXEL_RECT_EQ(0, kResolveY1, kWidth / 2, kHeight / 2 - kResolveY1, GLColor::green);
+
+ EXPECT_PIXEL_RECT_EQ(kResolveX0, kResolveY0, kResolveX1 - kResolveX0, kResolveY1 - kResolveY0,
+ GLColor::red);
+}
+
// Use this to select which configurations (e.g. which renderer, which GLES major version) these
// tests should be run against.
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BlitFramebufferANGLETest);

View File

@@ -0,0 +1,109 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shahbaz Youssefi <syoussefi@chromium.org>
Date: Mon, 7 Feb 2022 13:46:46 -0500
Subject: M98: Vulkan: Fix vkCmdResolveImage offsets
glBlitFramebuffer takes identical regions for src and dst when
resolving. vkCmdResolveImage should use the clipped area instead of
using the actual offsets passed to this function.
Bug: chromium:1292537
Change-Id: If283a8acbca3249b771facbc30bd9f8080a03656
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3457023
Reviewed-by: Tim Van Patten <timvp@google.com>
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 892983bd1ad52c6e0080c977022689c1d6a20ac5..7fc8e785af2c9c50f624790eccf5f57ce4af2c87 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -1451,13 +1451,13 @@ angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
resolveRegion.srcSubresource.mipLevel = 0;
resolveRegion.srcSubresource.baseArrayLayer = params.srcLayer;
resolveRegion.srcSubresource.layerCount = 1;
- resolveRegion.srcOffset.x = params.srcOffset[0];
- resolveRegion.srcOffset.y = params.srcOffset[1];
+ resolveRegion.srcOffset.x = params.blitArea.x;
+ resolveRegion.srcOffset.y = params.blitArea.y;
resolveRegion.srcOffset.z = 0;
resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resolveRegion.dstSubresource.layerCount = 1;
- resolveRegion.dstOffset.x = params.destOffset[0];
- resolveRegion.dstOffset.y = params.destOffset[1];
+ resolveRegion.dstOffset.x = params.blitArea.x;
+ resolveRegion.dstOffset.y = params.blitArea.y;
resolveRegion.dstOffset.z = 0;
resolveRegion.extent.width = params.blitArea.width;
resolveRegion.extent.height = params.blitArea.height;
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 72e32c27efabe8393ae840a9fef4ce37b3c5088c..87041f3b43a9ab50a0ec87ea4c338b498024b1b5 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -15,6 +15,8 @@
6142 VULKAN : BlitFramebufferTest.BlitDepthStencilPixelByPixel/* = SKIP
6153 VULKAN WIN INTEL : GLSLTest_ES31.StructAndArrayEqualOperator/ES3_1_Vulkan_DirectSPIRVGen = SKIP
6153 VULKAN PIXEL4ORXL : GLSLTest_ES31.StructAndArrayEqualOperator/ES3_1_Vulkan_DirectSPIRVGen = SKIP
+6989 OPENGL : BlitFramebufferTestES31.OOBResolve/* = SKIP
+6989 GLES : BlitFramebufferTestES31.OOBResolve/* = SKIP
// SPIR-V generation doesn't yet support bools in interface blocks
4889 VULKAN : GLSLTest.NestedSequenceOperatorWithTernaryInside/ES2_Vulkan_DirectSPIRVGen = SKIP
diff --git a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
index 02f7d025d52f50fd067aea1b8ef1057afdfd4657..ae2844d072ee5ab4c584bfa663b955994c011b0c 100644
--- a/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
+++ b/src/tests/gl_tests/BlitFramebufferANGLETest.cpp
@@ -2632,6 +2632,55 @@ TEST_P(BlitFramebufferTest, BlitDepthStencilPixelByPixel)
EXPECT_PIXEL_RECT_EQ(64, 0, 128, 1, GLColor::blue);
}
+// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was used with
+// out-of-bounds regions.
+TEST_P(BlitFramebufferTestES31, OOBResolve)
+{
+ constexpr GLint kWidth = 16;
+ constexpr GLint kHeight = 32;
+
+ // Read framebuffer is multisampled.
+ GLTexture readTexture;
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, readTexture);
+ glTexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, kWidth, kHeight, GL_TRUE);
+
+ GLFramebuffer readFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, readFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE,
+ readTexture, 0);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(1, 0, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Draw framebuffer is single sampled.
+ GLTexture drawTexture;
+ glBindTexture(GL_TEXTURE_2D, drawTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ nullptr);
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ GLFramebuffer drawFbo;
+ glBindFramebuffer(GL_FRAMEBUFFER, drawFbo);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawTexture, 0);
+ ASSERT_GL_NO_ERROR();
+ ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
+
+ glClearColor(0, 1, 0, 1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::green);
+
+ // Resolve the read framebuffer, using bounds that are outside the size of the image.
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
+ glBlitFramebuffer(-kWidth * 2, -kHeight * 3, kWidth * 11, kHeight * 8, -kWidth * 2,
+ -kHeight * 3, kWidth * 11, kHeight * 8, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ ASSERT_GL_NO_ERROR();
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, drawFbo);
+ EXPECT_PIXEL_RECT_EQ(0, 0, kWidth, kHeight, GLColor::red);
+}
+
// Regression test for a bug in the Vulkan backend where vkCmdResolveImage was using the src extents
// as the resolve area instead of the area passed to glBlitFramebuffer.
TEST_P(BlitFramebufferTestES31, PartialResolve)

View File

@@ -112,7 +112,6 @@ cherry-pick-3a5bafa35def.patch
cherry-pick-b2c4e4dc21e5.patch
m90-lts_prevents_non-browser_processes_from_requesting_memory.patch
check_direction_of_rtcencodedframes.patch
mas_gate_private_enterprise_APIs
cherry-pick-c69dddfe1cde.patch
speculative_fix_for_eye_dropper_getcolor_crash.patch
cherry-pick-0894af410c4e.patch
@@ -126,4 +125,31 @@ introduce_crossthreadcopier_skbitmap.patch
allow_null_skbitmap_to_be_transferred_across_threads.patch
use_weakptrs_for_the_threadediconloader_s_background_tasks.patch
cherry-pick-a5f54612590d.patch
mas_gate_private_enterprise_APIs.patch
fix_aspect_ratio_with_max_size.patch
cherry-pick-f0a63e1f361f.patch
cherry-pick-27eb11a28555.patch
cherry-pick-f781748dcb3c.patch
sandbox_fix_sandbox_inheritance_m96_merge.patch
cherry-pick-dbde8795233a.patch
cherry-pick-da11d71a0227.patch
m96_fileapi_move_origin_checks_in_bloburlstore_sooner.patch
cherry-pick-6bb320d134b1.patch
cherry-pick-c5571653d932.patch
cherry-pick-1282354.patch
cherry-pick-9db9911e1242.patch
cherry-pick-22f27676515e.patch
cherry-pick-1283371.patch
cherry-pick-1283375.patch
cherry-pick-1283198.patch
cherry-pick-1284367.patch
cherry-pick-be50c60b4225.patch
cherry-pick-e3805f29fed7.patch
m98_fs_fix_fileutil_lifetime_issue.patch
cherry-pick-0081bb347e67.patch
cleanup_pausablecriptexecutor_usage.patch
cherry-pick-ebc188ad769e.patch
cherry-pick-1277917.patch
cherry-pick-62142d222a80.patch
cherry-pick-1887414c016d.patch
cherry-pick-6b2643846ae3.patch

View File

@@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Matt Reynolds <mattreynolds@google.com>
Date: Wed, 19 Jan 2022 21:03:08 +0000
Subject: gamepad: Return an invalid handle after ReportBadMessage
Bug: 1285449
Change-Id: I746c539577f7bdf69cbe4212ac380e0c92a5c771
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3373944
Auto-Submit: Matt Reynolds <mattreynolds@chromium.org>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Commit-Queue: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#961125}
diff --git a/device/gamepad/gamepad_monitor.cc b/device/gamepad/gamepad_monitor.cc
index ce8ba1ef7551e52f8ae4d9a112a08308ab2ce51c..28082924e632a895fc5bc4725bc6de3d6ca120ac 100644
--- a/device/gamepad/gamepad_monitor.cc
+++ b/device/gamepad/gamepad_monitor.cc
@@ -53,6 +53,8 @@ void GamepadMonitor::GamepadStartPolling(GamepadStartPollingCallback callback) {
GamepadService* service = GamepadService::GetInstance();
if (!service->ConsumerBecameActive(this)) {
mojo::ReportBadMessage("GamepadMonitor::GamepadStartPolling failed");
+ std::move(callback).Run(base::ReadOnlySharedMemoryRegion());
+ return;
}
std::move(callback).Run(service->DuplicateSharedMemoryRegion());
}

View File

@@ -0,0 +1,176 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Simon Pelchat <spelchat@chromium.org>
Date: Fri, 7 Jan 2022 20:00:37 +0000
Subject: Avoid UAF on StreamingSearchPrefetchURLLoader.
StreamingSearchPrefetchURLLoader::OnDataAvailable used to "delete this",
which results in deleting the DataPipeDrainer, which will then be used
once OnDataAvailable returns. Instead, we post a task to delete the
URL loader later on.
Bug: 1277917
Change-Id: I8d78c73a01fff0315b96ccb0e7fe605884b99823
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3365387
Reviewed-by: Max Curran <curranmax@chromium.org>
Reviewed-by: Robert Ogden <robertogden@chromium.org>
Commit-Queue: Simon Pelchat <spelchat@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956628}
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
index 1d3d1ea93c026d371a6ad5678e8ff37dc58f8423..e3eaad96fbada18211f295988c07d218ab67921f 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.cc
@@ -5,6 +5,7 @@
#include "chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h"
#include "chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h"
+#include "streaming_search_prefetch_request.h"
StreamingSearchPrefetchRequest::StreamingSearchPrefetchRequest(
const GURL& prefetch_url,
@@ -19,7 +20,9 @@ void StreamingSearchPrefetchRequest::StartPrefetchRequestInternal(
std::unique_ptr<network::ResourceRequest> resource_request,
const net::NetworkTrafficAnnotationTag& network_traffic_annotation) {
streaming_url_loader_ = std::make_unique<StreamingSearchPrefetchURLLoader>(
- this, profile, std::move(resource_request), network_traffic_annotation);
+ this, profile, std::move(resource_request), network_traffic_annotation,
+ base::BindOnce(&StreamingSearchPrefetchRequest::StopPrefetch,
+ weak_factory_.GetWeakPtr()));
}
std::unique_ptr<SearchPrefetchURLLoader>
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
index ff051c61e9cbed67d5cffbcac007d6c12a26cc76..ad75d404abe9e743d079725ffd8b01d3a49ae017 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_request.h
@@ -47,6 +47,8 @@ class StreamingSearchPrefetchRequest : public BaseSearchPrefetchRequest {
private:
// The ongoing prefetch request. Null before and after the fetch.
std::unique_ptr<StreamingSearchPrefetchURLLoader> streaming_url_loader_;
+
+ base::WeakPtrFactory<StreamingSearchPrefetchRequest> weak_factory_{this};
};
#endif // CHROME_BROWSER_PREFETCH_SEARCH_PREFETCH_STREAMING_SEARCH_PREFETCH_REQUEST_H_
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
index 09a8f5c444c5346dd6d2544c403a4b844e0ba781..2134bdbd2514d86b912b83480ca90242d7f7455e 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.cc
@@ -26,15 +26,18 @@
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/early_hints.mojom.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
+#include "streaming_search_prefetch_url_loader.h"
#include "url/gurl.h"
StreamingSearchPrefetchURLLoader::StreamingSearchPrefetchURLLoader(
StreamingSearchPrefetchRequest* streaming_prefetch_request,
Profile* profile,
std::unique_ptr<network::ResourceRequest> resource_request,
- const net::NetworkTrafficAnnotationTag& network_traffic_annotation)
+ const net::NetworkTrafficAnnotationTag& network_traffic_annotation,
+ base::OnceClosure stop_prefetch_closure)
: resource_request_(std::move(resource_request)),
- streaming_prefetch_request_(streaming_prefetch_request) {
+ streaming_prefetch_request_(streaming_prefetch_request),
+ stop_prefetch_closure_(std::move(stop_prefetch_closure)) {
DCHECK(streaming_prefetch_request_);
auto url_loader_factory = profile->GetDefaultStoragePartition()
->GetURLLoaderFactoryForBrowserProcess();
@@ -130,7 +133,7 @@ void StreamingSearchPrefetchURLLoader::OnReceiveRedirect(
if (streaming_prefetch_request_) {
streaming_prefetch_request_->ErrorEncountered();
} else {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
}
}
@@ -213,7 +216,7 @@ void StreamingSearchPrefetchURLLoader::OnStartLoadingResponseBodyFromData() {
mojo::CreateDataPipe(&options, producer_handle_, consumer_handle);
if (rv != MOJO_RESULT_OK) {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
return;
}
@@ -235,7 +238,7 @@ void StreamingSearchPrefetchURLLoader::OnHandleReady(
MojoResult result,
const mojo::HandleSignalsState& state) {
if (result != MOJO_RESULT_OK) {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
return;
}
PushData();
@@ -261,7 +264,7 @@ void StreamingSearchPrefetchURLLoader::PushData() {
}
if (result != MOJO_RESULT_OK) {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
return;
}
@@ -348,16 +351,24 @@ void StreamingSearchPrefetchURLLoader::OnURLLoaderMojoDisconnect() {
DCHECK(streaming_prefetch_request_);
streaming_prefetch_request_->ErrorEncountered();
} else {
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
}
}
void StreamingSearchPrefetchURLLoader::OnURLLoaderClientMojoDisconnect() {
DCHECK(forwarding_client_);
DCHECK(!streaming_prefetch_request_);
- delete this;
+ PostTaskToStopPrefetchAndDeleteSelf();
}
void StreamingSearchPrefetchURLLoader::ClearOwnerPointer() {
streaming_prefetch_request_ = nullptr;
}
+
+void StreamingSearchPrefetchURLLoader::PostTaskToStopPrefetchAndDeleteSelf() {
+ // To avoid UAF bugs, post a separate task to delete this object.
+ if (stop_prefetch_closure_) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(stop_prefetch_closure_));
+ }
+}
diff --git a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
index 2213fb079e3f29566d67030dd2fa399ce11024e2..ed225db0b4d2b0d24aae967f320a7010c1a45044 100644
--- a/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
+++ b/chrome/browser/prefetch/search_prefetch/streaming_search_prefetch_url_loader.h
@@ -39,7 +39,8 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
StreamingSearchPrefetchRequest* streaming_prefetch_request,
Profile* profile,
std::unique_ptr<network::ResourceRequest> resource_request,
- const net::NetworkTrafficAnnotationTag& network_traffic_annotation);
+ const net::NetworkTrafficAnnotationTag& network_traffic_annotation,
+ base::OnceClosure stop_prefetch_closure);
~StreamingSearchPrefetchURLLoader() override;
@@ -105,6 +106,9 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
// Clears |producer_handle_| and |handle_watcher_|.
void Finish();
+ // Post a task to delete this object by running stop_prefetch_closure_.
+ void PostTaskToStopPrefetchAndDeleteSelf();
+
// Sets up mojo forwarding to the navigation path. Resumes
// |network_url_loader_| calls. Serves the start of the response to the
// navigation path. After this method is called, |this| manages its own
@@ -164,6 +168,9 @@ class StreamingSearchPrefetchURLLoader : public network::mojom::URLLoader,
mojo::ScopedDataPipeProducerHandle producer_handle_;
std::unique_ptr<mojo::SimpleWatcher> handle_watcher_;
+ // Closure to cancel this prefetch. Running this callback will destroy |this|.
+ base::OnceClosure stop_prefetch_closure_;
+
base::WeakPtrFactory<StreamingSearchPrefetchURLLoader> weak_factory_{this};
};

View File

@@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Chris Bookholt <bookholt@chromium.org>
Date: Tue, 11 Jan 2022 00:33:53 +0000
Subject: ServiceWorkerContainerHost::EnsureFileAccess: abort request
processing if the requesting process lacks file access
Bug: 1282354
Change-Id: Ia37ef5b97eedb0d2ad25ffe2869844a40e5be862
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3379268
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
Commit-Queue: Chris Bookholt <bookholt@chromium.org>
Cr-Commit-Position: refs/heads/main@{#957344}
diff --git a/content/browser/service_worker/service_worker_container_host.cc b/content/browser/service_worker/service_worker_container_host.cc
index 5aca9f432a9efdb9739363e80b52233339529a1c..8b15f204e457904423da33b01bead1b03b59597a 100644
--- a/content/browser/service_worker/service_worker_container_host.cc
+++ b/content/browser/service_worker/service_worker_container_host.cc
@@ -375,10 +375,12 @@ void ServiceWorkerContainerHost::EnsureFileAccess(
ChildProcessSecurityPolicyImpl* policy =
ChildProcessSecurityPolicyImpl::GetInstance();
for (const auto& file : file_paths) {
- if (!policy->CanReadFile(process_id_, file))
+ if (!policy->CanReadFile(process_id_, file)) {
mojo::ReportBadMessage(
"The renderer doesn't have access to the file "
"but it tried to grant access to the controller.");
+ return;
+ }
if (!policy->CanReadFile(controller_process_id, file))
policy->GrantReadFile(controller_process_id, file);

View File

@@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Hosseinian <dhoss@chromium.org>
Date: Thu, 30 Dec 2021 05:08:29 +0000
Subject: CHECK page on thumbnail requests
Elevate DCHECK to CHECK.
Fixed: 1283198
Change-Id: Iacb3da961cfb44f94f7a377e225270a57809ef9c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3361538
Auto-Submit: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: K. Moon <kmoon@chromium.org>
Commit-Queue: K. Moon <kmoon@chromium.org>
Cr-Commit-Position: refs/heads/main@{#954552}
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 7f70791ceddf298d2c95ca3569799a0f4d3746a3..c7ae1b65d416024a7d90e377a57b5ae1ea3e0c07 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -4224,7 +4224,7 @@ void PDFiumEngine::SetLinkUnderCursorForAnnotation(FPDF_ANNOTATION annot,
void PDFiumEngine::RequestThumbnail(int page_index,
float device_pixel_ratio,
SendThumbnailCallback send_callback) {
- DCHECK(PageIndexInBounds(page_index));
+ CHECK(PageIndexInBounds(page_index));
pages_[page_index]->RequestThumbnail(device_pixel_ratio,
std::move(send_callback));
}

View File

@@ -0,0 +1,138 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Clark DuVall <cduvall@chromium.org>
Date: Thu, 6 Jan 2022 01:21:21 +0000
Subject: Fix lifetime bug in PrefetchURLLoader
PrefetchURLLoader is now owned by PrefetchURLLoaderService, which is no
longer refcounted. This makes the lifetime much easier to reason about.
Bug: 1283371
Change-Id: Iaa58c1f44cc9f066459ce344012f57faca533197
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3361198
Reviewed-by: John Abd-El-Malek <jam@chromium.org>
Reviewed-by: Kunihiko Sakamoto <ksakamoto@chromium.org>
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Cr-Commit-Position: refs/heads/main@{#955986}
diff --git a/content/browser/loader/prefetch_url_loader_service.cc b/content/browser/loader/prefetch_url_loader_service.cc
index 5211d5552d6b2e1c1967d7dd6c6079001fef6895..345bf021541a121ea183ba16fa7ed76373f0dfd1 100644
--- a/content/browser/loader/prefetch_url_loader_service.cc
+++ b/content/browser/loader/prefetch_url_loader_service.cc
@@ -202,29 +202,25 @@ void PrefetchURLLoaderService::CreateLoaderAndStart(
->prefetched_signed_exchange_cache;
}
- // For now we make self owned receiver for the loader to the request, while we
- // can also possibly make the new loader owned by the factory so that they can
- // live longer than the client (i.e. run in detached mode).
- // TODO(kinuko): Revisit this.
- mojo::MakeSelfOwnedReceiver(
- std::make_unique<PrefetchURLLoader>(
- request_id, options, current_context.frame_tree_node_id,
- resource_request,
- resource_request.trusted_params
- ? resource_request.trusted_params->isolation_info
- .network_isolation_key()
- : current_context.render_frame_host->GetNetworkIsolationKey(),
- std::move(client), traffic_annotation,
- std::move(network_loader_factory_to_use),
- base::BindRepeating(
- &PrefetchURLLoaderService::CreateURLLoaderThrottles, this,
- resource_request, current_context.frame_tree_node_id),
- browser_context_, signed_exchange_prefetch_metric_recorder_,
- std::move(prefetched_signed_exchange_cache), accept_langs_,
- base::BindOnce(
- &PrefetchURLLoaderService::GenerateRecursivePrefetchToken, this,
- current_context.weak_ptr_factory.GetWeakPtr())),
- std::move(receiver));
+ // base::Unretained is safe here since |this| owns the loader.
+ auto loader = std::make_unique<PrefetchURLLoader>(
+ request_id, options, current_context.frame_tree_node_id, resource_request,
+ resource_request.trusted_params
+ ? resource_request.trusted_params->isolation_info
+ .network_isolation_key()
+ : current_context.render_frame_host->GetNetworkIsolationKey(),
+ std::move(client), traffic_annotation,
+ std::move(network_loader_factory_to_use),
+ base::BindRepeating(&PrefetchURLLoaderService::CreateURLLoaderThrottles,
+ base::Unretained(this), resource_request,
+ current_context.frame_tree_node_id),
+ browser_context_, signed_exchange_prefetch_metric_recorder_,
+ std::move(prefetched_signed_exchange_cache), accept_langs_,
+ base::BindOnce(&PrefetchURLLoaderService::GenerateRecursivePrefetchToken,
+ base::Unretained(this),
+ current_context.weak_ptr_factory.GetWeakPtr()));
+ auto* raw_loader = loader.get();
+ prefetch_receivers_.Add(raw_loader, std::move(receiver), std::move(loader));
}
PrefetchURLLoaderService::~PrefetchURLLoaderService() = default;
diff --git a/content/browser/loader/prefetch_url_loader_service.h b/content/browser/loader/prefetch_url_loader_service.h
index 210794966c8d25947f3e6b490538c1f851d80d52..c5fff844f73deaf2912716de9cf97547c498e4e5 100644
--- a/content/browser/loader/prefetch_url_loader_service.h
+++ b/content/browser/loader/prefetch_url_loader_service.h
@@ -35,13 +35,11 @@ class URLLoaderFactoryGetter;
// prefetches. The renderer uses it for prefetch requests including <link
// rel="prefetch">.
class CONTENT_EXPORT PrefetchURLLoaderService final
- : public base::RefCountedThreadSafe<
- PrefetchURLLoaderService,
- content::BrowserThread::DeleteOnUIThread>,
- public blink::mojom::RendererPreferenceWatcher,
+ : public blink::mojom::RendererPreferenceWatcher,
public network::mojom::URLLoaderFactory {
public:
explicit PrefetchURLLoaderService(BrowserContext* browser_context);
+ ~PrefetchURLLoaderService() override;
void GetFactory(
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
@@ -67,12 +65,8 @@ class CONTENT_EXPORT PrefetchURLLoaderService final
}
private:
- friend class base::DeleteHelper<content::PrefetchURLLoaderService>;
- friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
struct BindContext;
- ~PrefetchURLLoaderService() override;
-
// network::mojom::URLLoaderFactory:
void CreateLoaderAndStart(
mojo::PendingReceiver<network::mojom::URLLoader> receiver,
@@ -114,6 +108,9 @@ class CONTENT_EXPORT PrefetchURLLoaderService final
mojo::ReceiverSet<network::mojom::URLLoaderFactory,
std::unique_ptr<BindContext>>
loader_factory_receivers_;
+ mojo::ReceiverSet<network::mojom::URLLoader,
+ std::unique_ptr<network::mojom::URLLoader>>
+ prefetch_receivers_;
// Used in the IO thread.
mojo::Receiver<blink::mojom::RendererPreferenceWatcher>
preference_watcher_receiver_{this};
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 263fe6195ac6d48cd7a985ca844d1a6e421a9b1d..ac0bba6a7b41e497eb28c820476f36de5c63bc34 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1285,7 +1285,7 @@ void StoragePartitionImpl::Initialize(
blob_context, filesystem_context_, fallback_blob_registry);
prefetch_url_loader_service_ =
- base::MakeRefCounted<PrefetchURLLoaderService>(browser_context_);
+ std::make_unique<PrefetchURLLoaderService>(browser_context_);
cookie_store_context_ = base::MakeRefCounted<CookieStoreContext>();
// Unit tests use the Initialize() callback to crash early if restoring the
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 6d1c4031c340e0a16943b1f0c0efdf9f5dc5f99b..ba0ae57aae69a5edf4ce23c202a93c8cdb003051 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -561,7 +561,7 @@ class CONTENT_EXPORT StoragePartitionImpl
std::unique_ptr<BroadcastChannelProvider> broadcast_channel_provider_;
std::unique_ptr<BluetoothAllowedDevicesMap> bluetooth_allowed_devices_map_;
scoped_refptr<BlobRegistryWrapper> blob_registry_;
- scoped_refptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
+ std::unique_ptr<PrefetchURLLoaderService> prefetch_url_loader_service_;
scoped_refptr<CookieStoreContext> cookie_store_context_;
scoped_refptr<BucketContext> bucket_context_;
scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;

View File

@@ -0,0 +1,74 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alan Screen <awscreen@chromium.org>
Date: Fri, 7 Jan 2022 09:38:01 +0000
Subject: Ensure valid print render host before proceeding to print.
Bug: 1283375
Change-Id: I5691fc2a9d09040e777aafd0061b957025643b8a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3369086
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Alan Screen <awscreen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956443}
diff --git a/chrome/browser/printing/print_view_manager.cc b/chrome/browser/printing/print_view_manager.cc
index bfed66e625f1d6e53b31750cd7d5fa7748cae75c..6c5ec9086264972ff67beab712ae2695ffa93395 100644
--- a/chrome/browser/printing/print_view_manager.cc
+++ b/chrome/browser/printing/print_view_manager.cc
@@ -91,6 +91,11 @@ bool PrintViewManager::PrintForSystemDialogNow(
on_print_dialog_shown_callback_ = std::move(dialog_shown_callback);
is_switching_to_system_dialog_ = true;
+ // Remember the ID for `print_preview_rfh_`, to enable checking that the
+ // `RenderFrameHost` is still valid after a possible inner message loop runs
+ // in `DisconnectFromCurrentPrintJob()`.
+ content::GlobalRenderFrameHostId rfh_id = print_preview_rfh_->GetGlobalId();
+
auto weak_this = weak_factory_.GetWeakPtr();
DisconnectFromCurrentPrintJob();
if (!weak_this)
@@ -100,6 +105,10 @@ bool PrintViewManager::PrintForSystemDialogNow(
if (IsCrashed())
return false;
+ // Don't print if `print_preview_rfh_` is no longer live.
+ if (!content::RenderFrameHost::FromID(rfh_id))
+ return false;
+
// TODO(crbug.com/809738) Register with `PrintBackendServiceManager` when
// system print is enabled out-of-process.
diff --git a/chrome/browser/printing/print_view_manager_base.cc b/chrome/browser/printing/print_view_manager_base.cc
index 562800bf194e1f07f58b912b54a740b7c7dcabb6..c34f3ba9bb4adbfa8f190d5ef75cfa72937f0b1d 100644
--- a/chrome/browser/printing/print_view_manager_base.cc
+++ b/chrome/browser/printing/print_view_manager_base.cc
@@ -39,6 +39,7 @@
#include "components/services/print_compositor/public/cpp/print_service_mojo_types.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
@@ -364,6 +365,11 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh,
bool silent,
base::Value settings,
CompletionCallback callback) {
+ // Remember the ID for `rfh`, to enable checking that the `RenderFrameHost`
+ // is still valid after a possible inner message loop runs in
+ // `DisconnectFromCurrentPrintJob()`.
+ content::GlobalRenderFrameHostId rfh_id = rfh->GetGlobalId();
+
auto weak_this = weak_ptr_factory_.GetWeakPtr();
DisconnectFromCurrentPrintJob();
if (!weak_this)
@@ -373,6 +379,10 @@ bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh,
if (IsCrashed())
return false;
+ // Don't print if `rfh` is no longer live.
+ if (!content::RenderFrameHost::FromID(rfh_id))
+ return false;
+
// TODO(crbug.com/809738) Register with `PrintBackendServiceManager` when
// system print is enabled out-of-process. A corresponding unregister should
// go in `ReleasePrintJob()`.

View File

@@ -0,0 +1,188 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Xinghui Lu <xinghuilu@chromium.org>
Date: Thu, 6 Jan 2022 08:36:45 +0000
Subject: Use RFH global id to ensure the RFH is valid.
Observing via RenderFrameDeleted and RenderFrameHostChanged is not
sufficient for validating the RFH is still valid, because the frames
can belong to inner WebContents. As suggested in
https://crrev.com/c/2449389, storing a GlobalFrameRoutingId is the
preferred method of keeping a reference to a RFH.
Bug: 1284367
Change-Id: I3afb40e394d6e2e7fd19b2704e0dd68fa23c7bb2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3367466
Reviewed-by: Daniel Rubery <drubery@chromium.org>
Commit-Queue: Xinghui Lu <xinghuilu@chromium.org>
Cr-Commit-Position: refs/heads/main@{#956061}
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index 4ba3daa516121e73ead560fd3ba9d6e011ceadc7..c7ca2f45eb8afdb2713630e507733741bf4a8307 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -596,7 +596,8 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails) {
parent_node->children.push_back(GURL(kDOMChildURL));
params.push_back(std::move(parent_node));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
@@ -815,10 +816,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames) {
// Send both sets of nodes from different render frames.
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(),
+ main_rfh()->GetGlobalId(),
std::move(outer_params_copy));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- child_rfh, std::move(inner_params_copy));
+ child_rfh->GetGlobalId(),
+ std::move(inner_params_copy));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
@@ -864,9 +866,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames) {
// Send both sets of nodes from different render frames.
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- child_rfh, std::move(inner_params));
+ child_rfh->GetGlobalId(),
+ std::move(inner_params));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(outer_params));
+ main_rfh()->GetGlobalId(),
+ std::move(outer_params));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
@@ -990,9 +994,11 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_AmbiguousDOM) {
// Send both sets of nodes from different render frames.
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(outer_params));
+ main_rfh()->GetGlobalId(),
+ std::move(outer_params));
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- child_rfh, std::move(inner_params));
+ child_rfh->GetGlobalId(),
+ std::move(inner_params));
std::string serialized = WaitForThreatDetailsDone(
report.get(), false /* did_proceed*/, 0 /* num_visit */);
ClientSafeBrowsingReportRequest actual;
@@ -1257,10 +1263,10 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_TrimToAdTags) {
// Send both sets of nodes from different render frames.
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), child_rfh,
+ mojo::Remote<mojom::ThreatReporter>(), child_rfh->GetGlobalId(),
std::move(inner_params));
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), main_rfh(),
+ mojo::Remote<mojom::ThreatReporter>(), main_rfh()->GetGlobalId(),
std::move(outer_params));
std::string serialized = WaitForThreatDetailsDone(
@@ -1333,10 +1339,10 @@ TEST_F(ThreatDetailsTest, ThreatDOMDetails_EmptyReportNotSent) {
// Send both sets of nodes from different render frames.
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), child_rfh,
+ mojo::Remote<mojom::ThreatReporter>(), child_rfh->GetGlobalId(),
std::move(inner_params));
trimmed_report->OnReceivedThreatDOMDetails(
- mojo::Remote<mojom::ThreatReporter>(), main_rfh(),
+ mojo::Remote<mojom::ThreatReporter>(), main_rfh()->GetGlobalId(),
std::move(outer_params));
std::string serialized = WaitForThreatDetailsDone(
@@ -1593,7 +1599,8 @@ TEST_F(ThreatDetailsTest, HTTPCache) {
// The cache collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the cache callbacks complete.
base::RunLoop().RunUntilIdle();
@@ -1673,7 +1680,8 @@ TEST_F(ThreatDetailsTest, HttpsResourceSanitization) {
// The cache collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the cache callbacks complete.
base::RunLoop().RunUntilIdle();
@@ -1756,7 +1764,8 @@ TEST_F(ThreatDetailsTest, HTTPCacheNoEntries) {
// The cache collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the cache callbacks complete.
base::RunLoop().RunUntilIdle();
@@ -1815,7 +1824,8 @@ TEST_F(ThreatDetailsTest, HistoryServiceUrls) {
// The redirects collection starts after the IPC from the DOM is fired.
std::vector<mojom::ThreatDOMDetailsNodePtr> params;
report->OnReceivedThreatDOMDetails(mojo::Remote<mojom::ThreatReporter>(),
- main_rfh(), std::move(params));
+ main_rfh()->GetGlobalId(),
+ std::move(params));
// Let the redirects callbacks complete.
base::RunLoop().RunUntilIdle();
diff --git a/components/safe_browsing/content/browser/threat_details.cc b/components/safe_browsing/content/browser/threat_details.cc
index f3fe647b5d443c2a2f284289ae66d81782c5f6e8..361830189b0ab6324fe87719f36f2fa0bc948224 100644
--- a/components/safe_browsing/content/browser/threat_details.cc
+++ b/components/safe_browsing/content/browser/threat_details.cc
@@ -664,16 +664,20 @@ void ThreatDetails::RequestThreatDOMDetails(content::RenderFrameHost* frame) {
pending_render_frame_hosts_.push_back(frame);
raw_threat_report->GetThreatDOMDetails(
base::BindOnce(&ThreatDetails::OnReceivedThreatDOMDetails, GetWeakPtr(),
- std::move(threat_reporter), frame));
+ std::move(threat_reporter), frame->GetGlobalId()));
}
// When the renderer is done, this is called.
void ThreatDetails::OnReceivedThreatDOMDetails(
mojo::Remote<mojom::ThreatReporter> threat_reporter,
- content::RenderFrameHost* sender,
+ content::GlobalRenderFrameHostId sender_id,
std::vector<mojom::ThreatDOMDetailsNodePtr> params) {
// If the RenderFrameHost was closed between sending the IPC and this callback
// running, |sender| will be invalid.
+ auto* sender = content::RenderFrameHost::FromID(sender_id);
+ if (!sender) {
+ return;
+ }
const auto sender_it = std::find(pending_render_frame_hosts_.begin(),
pending_render_frame_hosts_.end(), sender);
if (sender_it == pending_render_frame_hosts_.end()) {
diff --git a/components/safe_browsing/content/browser/threat_details.h b/components/safe_browsing/content/browser/threat_details.h
index 8cb89700141561aab49edc474799c9e7148b8ae8..61dcb8d9c772d223661236d99aebd1d3ebe01d3a 100644
--- a/components/safe_browsing/content/browser/threat_details.h
+++ b/components/safe_browsing/content/browser/threat_details.h
@@ -24,6 +24,7 @@
#include "components/safe_browsing/core/common/proto/csd.pb.h"
#include "components/security_interstitials/core/unsafe_resource.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/remote.h"
@@ -169,7 +170,7 @@ class ThreatDetails : public content::WebContentsObserver {
void OnReceivedThreatDOMDetails(
mojo::Remote<mojom::ThreatReporter> threat_reporter,
- content::RenderFrameHost* sender,
+ content::GlobalRenderFrameHostId sender_id,
std::vector<mojom::ThreatDOMDetailsNodePtr> params);
void AddRedirectUrlList(const std::vector<GURL>& urls);

View File

@@ -0,0 +1,53 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Muyao Xu <muyaoxu@google.com>
Date: Thu, 17 Feb 2022 16:23:29 +0000
Subject: Replace WidgetObserver::OnWidgetClosing() with OnWidgetDestroying()
In some cases, OnWidgetClosing() is not called when the widget is
closed, resulting an invalid pointer |widget_| stored in
WebContentsDisplayObserverView.
This CL replaces OnWidgetClosing() with OnWidgetDestroying(), which
is recommended in crbug.com/1240365
(cherry picked from commit 4535fe2334d0713535adb52b641a8cb34e11333c)
Bug: 1291728
Change-Id: I64fef8b30930f60220008809ee00f4385d6c3520
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3425473
Auto-Submit: Muyao Xu <muyaoxu@google.com>
Commit-Queue: Takumi Fujimoto <takumif@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#965431}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3435985
Reviewed-by: Michael Ershov <miersh@google.com>
Owners-Override: Michael Ershov <miersh@google.com>
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1480}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
index b2cd4550d26fcbe5463043181800e5d705559cb3..e2a1c772c31a3c073c8629cb745c7a5dd16174a8 100644
--- a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
+++ b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.cc
@@ -64,7 +64,7 @@ void WebContentsDisplayObserverView::OnBrowserSetLastActive(Browser* browser) {
}
}
-void WebContentsDisplayObserverView::OnWidgetClosing(views::Widget* widget) {
+void WebContentsDisplayObserverView::OnWidgetDestroying(views::Widget* widget) {
if (widget_)
widget_->RemoveObserver(this);
widget_ = nullptr;
diff --git a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
index 17a8ca48b1c836a82e2be5e5c605bc1837150cba..b63cf4505318a44c65585b06ec13960bad5d9e32 100644
--- a/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
+++ b/chrome/browser/ui/views/media_router/web_contents_display_observer_view.h
@@ -28,7 +28,7 @@ class WebContentsDisplayObserverView : public WebContentsDisplayObserver,
void OnBrowserSetLastActive(Browser* browser) override;
// views::WidgetObserver overrides:
- void OnWidgetClosing(views::Widget* widget) override;
+ void OnWidgetDestroying(views::Widget* widget) override;
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& new_bounds) override;

View File

@@ -0,0 +1,86 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Christopher Cameron <ccameron@chromium.org>
Date: Tue, 9 Nov 2021 00:23:45 +0000
Subject: WebContentsVideoCaptureDevice: Fix use-after-free
The classes WebContentsVideoCaptureDevice,
AuraWindowVideoCaptureDevice::WindowTracker, and
ViewsWidgetVideoCaptureDeviceMac::UIThreadDelegate all keep a raw
pointer that they use to access the MouseCursorOverlayController.
This raw pointer comes from the base class FrameSinkVideoCaptureDevice
and should outlive the class that has a raw pointer. On macOS, this
isn't necessarily the case.
Avoid this sharp edge by using a WeakPtr for the
MouseCursorOverlayController, and checking that it is valid before
using it.
Bug: 1252562, 1179098
Change-Id: I1d74bea1255597662aab3f9f2430c49d2e39836a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3260842
Commit-Queue: ccameron <ccameron@chromium.org>
Reviewed-by: mark a. foltz <mfoltz@chromium.org>
Cr-Commit-Position: refs/heads/main@{#939604}
diff --git a/content/browser/media/capture/views_widget_video_capture_device_mac.cc b/content/browser/media/capture/views_widget_video_capture_device_mac.cc
index fee27cebfd64ee1cddbcb9873fa4b5e67cb526fc..50da870a417c17b1999b7d98bd8c2cb82e356c06 100644
--- a/content/browser/media/capture/views_widget_video_capture_device_mac.cc
+++ b/content/browser/media/capture/views_widget_video_capture_device_mac.cc
@@ -19,9 +19,10 @@ namespace content {
class ViewsWidgetVideoCaptureDeviceMac::UIThreadDelegate
: public remote_cocoa::ScopedCGWindowID::Observer {
public:
- UIThreadDelegate(uint32_t cg_window_id,
- const base::WeakPtr<FrameSinkVideoCaptureDevice> device,
- MouseCursorOverlayController* cursor_controller)
+ UIThreadDelegate(
+ uint32_t cg_window_id,
+ const base::WeakPtr<FrameSinkVideoCaptureDevice> device,
+ const base::WeakPtr<MouseCursorOverlayController> cursor_controller)
: cg_window_id_(cg_window_id),
device_task_runner_(base::ThreadTaskRunnerHandle::Get()),
device_(device),
@@ -83,8 +84,11 @@ class ViewsWidgetVideoCaptureDeviceMac::UIThreadDelegate
void OnScopedCGWindowIDMouseMoved(uint32_t cg_window_id,
const gfx::PointF& location_in_window,
const gfx::Size& window_size) override {
- cursor_controller_->SetTargetSize(window_size);
- cursor_controller_->OnMouseMoved(location_in_window);
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ if (cursor_controller_) {
+ cursor_controller_->SetTargetSize(window_size);
+ cursor_controller_->OnMouseMoved(location_in_window);
+ }
}
const uint32_t cg_window_id_;
@@ -96,20 +100,21 @@ class ViewsWidgetVideoCaptureDeviceMac::UIThreadDelegate
// |device_| may only be dereferenced by tasks posted to
// |device_task_runner_|.
- base::WeakPtr<FrameSinkVideoCaptureDevice> device_;
+ const base::WeakPtr<FrameSinkVideoCaptureDevice> device_;
- // Owned by FrameSinkVideoCaptureDevice. This will be valid for the life of
- // UIThreadDelegate because the UIThreadDelegate deleter task will be posted
- // to the UI thread before the MouseCursorOverlayController deleter task.
- // See similar behavior in WebContentsVideoCaptureDevice::FrameTracker.
- MouseCursorOverlayController* const cursor_controller_;
+ // Owned by FrameSinkVideoCaptureDevice. This may only be accessed on the
+ // UI thread. This is not guaranteed to be valid and must be checked before
+ // use.
+ // https://crbug.com/1252562
+ const base::WeakPtr<MouseCursorOverlayController> cursor_controller_;
};
ViewsWidgetVideoCaptureDeviceMac::ViewsWidgetVideoCaptureDeviceMac(
const DesktopMediaID& source_id)
: weak_factory_(this) {
ui_thread_delegate_ = std::make_unique<UIThreadDelegate>(
- source_id.id, weak_factory_.GetWeakPtr(), cursor_controller());
+ source_id.id, weak_factory_.GetWeakPtr(),
+ cursor_controller()->GetWeakPtr());
}
ViewsWidgetVideoCaptureDeviceMac::~ViewsWidgetVideoCaptureDeviceMac() {

View File

@@ -0,0 +1,71 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Yutaka Hirano <yhirano@chromium.org>
Date: Wed, 29 Sep 2021 07:58:26 +0000
Subject: Run CORS check for manual redirects
...to prevent status code leak.
Bug: 1251179
Change-Id: I7fcab0daf49e16305ed53702f42d1d1eacc933e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3193481
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
Cr-Commit-Position: refs/heads/main@{#926166}
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 6e4e8acf811f29712e87994e3fa125a811da978a..72aac202ca076fe7ea81f833549773f540e9b7d7 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -303,13 +303,6 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info,
DCHECK(forwarding_client_);
DCHECK(!deferred_redirect_url_);
- if (request_.redirect_mode == mojom::RedirectMode::kManual) {
- deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
- forwarding_client_->OnReceiveRedirect(redirect_info,
- std::move(response_head));
- return;
- }
-
// If |CORS flag| is set and a CORS check for |request| and |response| returns
// failure, then return a network error.
if (fetch_cors_flag_ && IsCorsEnabledRequestMode(request_.mode)) {
@@ -327,6 +320,13 @@ void CorsURLLoader::OnReceiveRedirect(const net::RedirectInfo& redirect_info,
}
}
+ if (request_.redirect_mode == mojom::RedirectMode::kManual) {
+ deferred_redirect_url_ = std::make_unique<GURL>(redirect_info.new_url);
+ forwarding_client_->OnReceiveRedirect(redirect_info,
+ std::move(response_head));
+ return;
+ }
+
timing_allow_failed_flag_ = !PassesTimingAllowOriginCheck(*response_head);
// Because we initiate a new request on redirect in some cases, we cannot
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
index eed44e0414cb8947c9b7c21df6ef288f733f8994..9f1ff98c65af97bcf185867ac6c6e128dbd77715 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/redirect/redirect-mode.any.js
@@ -1,6 +1,7 @@
// META: script=/common/get-host-info.sub.js
var redirectLocation = "cors-top.txt";
+const { ORIGIN, REMOTE_ORIGIN } = get_host_info();
function testRedirect(origin, redirectStatus, redirectMode, corsMode) {
var url = new URL("../resources/redirect.py", self.location);
@@ -47,4 +48,12 @@ for (var origin of ["same-origin", "cross-origin"]) {
}
}
+promise_test(async (t) => {
+ const destination = `${ORIGIN}/common/blank.html`;
+ // We use /common/redirect.py intentionally, as we want a CORS error.
+ const url =
+ `${REMOTE_ORIGIN}/common/redirect.py?location=${destination}`;
+ await promise_rejects_js(t, TypeError, fetch(url, { redirect: "manual" }));
+}, "manual redirect with a CORS error should be rejected");
+
done();

View File

@@ -0,0 +1,151 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Thu, 24 Feb 2022 15:13:13 +0000
Subject: Validate message headers sooner
M96 merge issues:
- multiplex_router.h: conflict in removed lines because of
differences in comments above header_validator_
- connector.h: conflicting includes
Message header validation has been tied to interface message dispatch,
but not all mojo::Message consumers are interface bindings.
mojo::Connector is a more general-purpose entry point through which
incoming messages are received and transformed into mojo::Message
objects. Blink's MessagePort implementation uses Connector directly to
transmit and receive raw serialized object data.
This change moves MessageHeaderValidator ownership into Connector and
always applies its validation immediately after reading a message from
the pipe, thereby ensuring that all mojo::Message objects used in
production have validated headers before use.
(cherry picked from commit 8d5bc69146505785ce299c490e35e3f3ef19f69c)
Fixed: 1281908
Change-Id: Ie0e251ab04681a4fd4b849d82c247e0ed800dc04
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3462461
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Original-Commit-Position: refs/heads/main@{#971263}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3483815
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
Owners-Override: Victor-Gabriel Savu <vsavu@google.com>
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1505}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/mojo/public/cpp/bindings/connector.h b/mojo/public/cpp/bindings/connector.h
index 3975d01a434d6caf229c6d8eaedfe5e2acf684f8..ff17af9b378a1992dbd681e80e957826ebfd83dd 100644
--- a/mojo/public/cpp/bindings/connector.h
+++ b/mojo/public/cpp/bindings/connector.h
@@ -18,6 +18,7 @@
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/connection_group.h"
#include "mojo/public/cpp/bindings/message.h"
+#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/sync_handle_watcher.h"
#include "mojo/public/cpp/system/core.h"
#include "mojo/public/cpp/system/handle_signal_tracker.h"
@@ -345,6 +346,8 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) Connector : public MessageReceiver {
// The number of pending tasks for |CallDispatchNextMessageFromPipe|.
size_t num_pending_dispatch_tasks_ = 0;
+ MessageHeaderValidator header_validator_;
+
#if defined(ENABLE_IPC_FUZZER)
std::unique_ptr<MessageReceiver> message_dumper_;
#endif
diff --git a/mojo/public/cpp/bindings/lib/connector.cc b/mojo/public/cpp/bindings/lib/connector.cc
index 92a9756cbaebe12377e9c9b81467260c73528311..cb08f13b1bfa13a1a79f7f39005f826e51c12a69 100644
--- a/mojo/public/cpp/bindings/lib/connector.cc
+++ b/mojo/public/cpp/bindings/lib/connector.cc
@@ -19,6 +19,7 @@
#include "base/rand_util.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "base/task/current_thread.h"
#include "base/threading/sequence_local_storage_slot.h"
@@ -152,7 +153,11 @@ Connector::Connector(ScopedMessagePipeHandle message_pipe,
force_immediate_dispatch_(!EnableTaskPerMessage()),
outgoing_serialization_mode_(g_default_outgoing_serialization_mode),
incoming_serialization_mode_(g_default_incoming_serialization_mode),
- interface_name_(interface_name) {
+ interface_name_(interface_name),
+ header_validator_(
+ base::JoinString({interface_name ? interface_name : "Generic",
+ "MessageHeaderValidator"},
+ "")) {
if (config == MULTI_THREADED_SEND)
lock_.emplace();
@@ -492,6 +497,7 @@ MojoResult Connector::ReadMessage(Message* message) {
return result;
*message = Message::CreateFromMessageHandle(&handle);
+
if (message->IsNull()) {
// Even if the read was successful, the Message may still be null if there
// was a problem extracting handles from it. We treat this essentially as
@@ -507,6 +513,10 @@ MojoResult Connector::ReadMessage(Message* message) {
return MOJO_RESULT_ABORTED;
}
+ if (!header_validator_.Accept(message)) {
+ return MOJO_RESULT_ABORTED;
+ }
+
return MOJO_RESULT_OK;
}
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc
index 605e51344d64eb5ede3ab475bc8833b37a458535..23e3970089e33d07b18d734d4f599c9c9f9e4bc8 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -23,7 +23,6 @@
#include "mojo/public/cpp/bindings/interface_endpoint_controller.h"
#include "mojo/public/cpp/bindings/lib/may_auto_lock.h"
#include "mojo/public/cpp/bindings/lib/message_quota_checker.h"
-#include "mojo/public/cpp/bindings/message_header_validator.h"
#include "mojo/public/cpp/bindings/sequence_local_sync_event_watcher.h"
namespace mojo {
@@ -389,14 +388,7 @@ MultiplexRouter::MultiplexRouter(
if (quota_checker)
connector_.SetMessageQuotaChecker(std::move(quota_checker));
- std::unique_ptr<MessageHeaderValidator> header_validator =
- std::make_unique<MessageHeaderValidator>();
- header_validator_ = header_validator.get();
- dispatcher_.SetValidator(std::move(header_validator));
-
if (primary_interface_name) {
- header_validator_->SetDescription(base::JoinString(
- {primary_interface_name, "[primary] MessageHeaderValidator"}, " "));
control_message_handler_.SetDescription(base::JoinString(
{primary_interface_name, "[primary] PipeControlMessageHandler"}, " "));
}
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h
index 3d3bbb16e25b1adc678e536bd977fa22fc478920..3a9f76a57e301aa89d1bdc5aa1000f815793e238 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -38,7 +38,6 @@ class SequencedTaskRunner;
namespace mojo {
class AsyncFlusher;
-class MessageHeaderValidator;
class PendingFlush;
namespace internal {
@@ -301,9 +300,6 @@ class COMPONENT_EXPORT(MOJO_CPP_BINDINGS) MultiplexRouter
scoped_refptr<base::SequencedTaskRunner> task_runner_;
- // Owned by |dispatcher_| below.
- MessageHeaderValidator* header_validator_ = nullptr;
-
MessageDispatcher dispatcher_;
Connector connector_;

View File

@@ -0,0 +1,150 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ted Meyer <tmathmeyer@chromium.org>
Date: Thu, 24 Feb 2022 17:39:53 +0000
Subject: Guard BatchingMediaLog::event_handlers_ with lock
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It seems that despite MediaLog::OnWebMediaPlayerDestroyed and
MediaLog::AddLogRecord both grabbing a lock,
BatchingMediaLog::AddLogRecordLocked can escape the lock handle by
posting BatchingMediaLog::SendQueuedMediaEvents, causing a race.
When the addition of an event is interrupted by the deletion of a player
due to player culling in MediaInspectorContextImpl, a UAF can occur.
R=dalecurtis
(cherry picked from commit 34526c3d0a857a22618e4d77c7f63b5ca6f8d3d2)
Bug: 1295786
Change-Id: I77df94988f806e4d98924669d27860e50455299d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3451494
Commit-Queue: Ted (Chromium) Meyer <tmathmeyer@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#970815}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3483655
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
Owners-Override: Victor-Gabriel Savu <vsavu@google.com>
Commit-Queue: Roger Felipe Zanoni da Silva <rzanoni@google.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1508}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/content/renderer/media/batching_media_log.cc b/content/renderer/media/batching_media_log.cc
index 8d8c5cb28b9bb0fcebcceb9e56db98fdace13c88..2d12a5eb42b930acac74a5ea2b2961e6c7e32fcf 100644
--- a/content/renderer/media/batching_media_log.cc
+++ b/content/renderer/media/batching_media_log.cc
@@ -52,9 +52,9 @@ BatchingMediaLog::BatchingMediaLog(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
std::vector<std::unique_ptr<EventHandler>> event_handlers)
: task_runner_(std::move(task_runner)),
- event_handlers_(std::move(event_handlers)),
tick_clock_(base::DefaultTickClock::GetInstance()),
last_ipc_send_time_(tick_clock_->NowTicks()),
+ event_handlers_(std::move(event_handlers)),
ipc_send_pending_(false),
logged_rate_limit_warning_(false) {
// Pre-bind the WeakPtr on the right thread since we'll receive calls from
@@ -76,6 +76,7 @@ BatchingMediaLog::~BatchingMediaLog() {
}
void BatchingMediaLog::OnWebMediaPlayerDestroyedLocked() {
+ base::AutoLock lock(lock_);
for (const auto& handler : event_handlers_)
handler->OnWebMediaPlayerDestroyed();
}
@@ -198,32 +199,30 @@ std::string BatchingMediaLog::MediaEventToMessageString(
void BatchingMediaLog::SendQueuedMediaEvents() {
DCHECK(task_runner_->BelongsToCurrentThread());
+ base::AutoLock auto_lock(lock_);
- std::vector<media::MediaLogRecord> events_to_send;
- {
- base::AutoLock auto_lock(lock_);
- DCHECK(ipc_send_pending_);
- ipc_send_pending_ = false;
-
- if (last_duration_changed_event_) {
- queued_media_events_.push_back(*last_duration_changed_event_);
- last_duration_changed_event_.reset();
- }
+ DCHECK(ipc_send_pending_);
+ ipc_send_pending_ = false;
- if (last_buffering_state_event_) {
- queued_media_events_.push_back(*last_buffering_state_event_);
- last_buffering_state_event_.reset();
- }
+ if (last_duration_changed_event_) {
+ queued_media_events_.push_back(*last_duration_changed_event_);
+ last_duration_changed_event_.reset();
+ }
- queued_media_events_.swap(events_to_send);
- last_ipc_send_time_ = tick_clock_->NowTicks();
+ if (last_buffering_state_event_) {
+ queued_media_events_.push_back(*last_buffering_state_event_);
+ last_buffering_state_event_.reset();
}
- if (events_to_send.empty())
+ last_ipc_send_time_ = tick_clock_->NowTicks();
+
+ if (queued_media_events_.empty())
return;
for (const auto& handler : event_handlers_)
- handler->SendQueuedMediaEvents(events_to_send);
+ handler->SendQueuedMediaEvents(queued_media_events_);
+
+ queued_media_events_.clear();
}
void BatchingMediaLog::SetTickClockForTesting(
diff --git a/content/renderer/media/batching_media_log.h b/content/renderer/media/batching_media_log.h
index 5810efdf0a75b809b94fb5abcd5f3dfbde7b019d..c59dbf2a2b980a89b41c45818476c77e9096339b 100644
--- a/content/renderer/media/batching_media_log.h
+++ b/content/renderer/media/batching_media_log.h
@@ -63,9 +63,6 @@ class CONTENT_EXPORT BatchingMediaLog : public media::MediaLog {
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- // impl for sending queued events.
- std::vector<std::unique_ptr<EventHandler>> event_handlers_;
-
// |lock_| protects access to all of the following member variables. It
// allows any render process thread to AddEvent(), while preserving their
// sequence for throttled send on |task_runner_| and coherent retrieval by
@@ -73,19 +70,24 @@ class CONTENT_EXPORT BatchingMediaLog : public media::MediaLog {
// guarantees provided by MediaLog, since SendQueuedMediaEvents must also
// be synchronized with respect to AddEvent.
mutable base::Lock lock_;
- const base::TickClock* tick_clock_;
- base::TimeTicks last_ipc_send_time_;
- std::vector<media::MediaLogRecord> queued_media_events_;
+ const base::TickClock* tick_clock_ GUARDED_BY(lock_);
+ base::TimeTicks last_ipc_send_time_ GUARDED_BY(lock_);
+ std::vector<media::MediaLogRecord> queued_media_events_ GUARDED_BY(lock_);
+
+ // impl for sending queued events.
+ std::vector<std::unique_ptr<EventHandler>> event_handlers_ GUARDED_BY(lock_);
// For enforcing max 1 pending send.
- bool ipc_send_pending_;
+ bool ipc_send_pending_ GUARDED_BY(lock_);
// True if we've logged a warning message about exceeding rate limits.
- bool logged_rate_limit_warning_;
+ bool logged_rate_limit_warning_ GUARDED_BY(lock_);
// Limits the number of events we send over IPC to one.
- absl::optional<media::MediaLogRecord> last_duration_changed_event_;
- absl::optional<media::MediaLogRecord> last_buffering_state_event_;
+ absl::optional<media::MediaLogRecord> last_duration_changed_event_
+ GUARDED_BY(lock_);
+ absl::optional<media::MediaLogRecord> last_buffering_state_event_
+ GUARDED_BY(lock_);
// Holds the earliest MEDIA_ERROR_LOG_ENTRY event added to this log. This is
// most likely to contain the most specific information available describing

View File

@@ -0,0 +1,765 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Victor Costan <pwnall@chromium.org>
Date: Thu, 11 Nov 2021 00:22:30 +0000
Subject: M96: Storage Foundation: Share FileState ownership with I/O threads.
blink::NativeIOFile methods implementing the Storage Foundation
JavaScript API pass raw pointers to NativeIOFile::FileState instances to
their corresponding blink::NativeIOFile::Do*() methods, which rely on
that CrossThreadPersistent<NativeIOFile> arguments to keep the
underlying NativeIOFile::FileState instances alive.
CrossThreadPersistent can be used across threads to keep a garbage
collected object alive, together with any non-garbage-collected objects
that it owns. However, relying on CrossThreadPersistent existence to
access the owned objects on a different thread is not safe.
cppgc::subtle::CrossThreadPersistent (blink::CrossThreadPersistent is an
alias to that) has comments explaining that the garbage collected heap
can go away while the CrossThreadPersistent instance exists.
This CL fixes the problem by having the ownership of
NativeIOFile::FileState be shared between the corresponding NativeIOFile
instance and any threads doing I/O on the FileState.
(cherry picked from commit 7dc02206707362f3f92cea93f8eb2fa4af0d375f)
Bug: 1240593
Change-Id: I5c9c818bcb23316fe1fd5afa57ed9c3fdb034377
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3269947
Commit-Queue: Victor Costan <pwnall@chromium.org>
Reviewed-by: Austin Sullivan <asully@chromium.org>
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: enne <enne@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#940130}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3272672
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4664@{#945}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.cc b/third_party/blink/renderer/modules/native_io/native_io_file.cc
index 4d5aa4efa13930aea4886bac0fd8ba892ce8b5a5..615c1d3a20cba732a3d981bf6b2df181e56d2727 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file.cc
+++ b/third_party/blink/renderer/modules/native_io/native_io_file.cc
@@ -9,6 +9,7 @@
#include "base/check.h"
#include "base/files/file.h"
#include "base/location.h"
+#include "base/memory/scoped_refptr.h"
#include "base/numerics/checked_math.h"
#include "base/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
@@ -47,31 +48,167 @@
namespace blink {
-struct NativeIOFile::FileState {
- explicit FileState(base::File file) : file(std::move(file)) {}
+// State and logic for performing file I/O off the JavaScript thread.
+//
+// Instances are allocated on the PartitionAlloc heap. Instances cannot be
+// garbage-collected, because garbage collected heaps get deallocated when the
+// underlying threads are terminated, and we need a guarantee that each
+// instance remains alive while it is used by a thread performing file I/O.
+//
+// Instances are initially constructed on a Blink thread that executes
+// JavaScript, which can be Blink's main thread, or a worker thread. Afterwards,
+// instances are (mostly*) only accessed on dedicated threads that do blocking
+// file I/O.
+//
+// Mostly*: On macOS < 10.15, SetLength() synchronously accesses FileState on
+// the JavaScript thread. This could be fixed with extra thread hopping. We're
+// not currently planning to invest in the fix.
+class NativeIOFile::FileState
+ : public base::RefCountedThreadSafe<NativeIOFile::FileState> {
+ public:
+ explicit FileState(base::File file) : file_(std::move(file)) {
+ DCHECK(file_.IsValid());
+ }
FileState(const FileState&) = delete;
FileState& operator=(const FileState&) = delete;
~FileState() = default;
+ // Returns true until Close() is called. Returns false afterwards.
+ //
+ // On macOS < 10.15, returns false between a TakeFile() call and the
+ // corresponding SetFile() call.
+ bool IsValid() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker locker(mutex_);
+ return file_.IsValid();
+ }
+
+ void Close() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ file_.Close();
+ }
+
+ // Returns {length, base::File::FILE_OK} in case of success.
+ // Returns {invalid number, error} in case of failure.
+ std::pair<int64_t, base::File::Error> GetLength() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ int64_t length = file_.GetLength();
+ base::File::Error error =
+ (length < 0) ? file_.GetLastFileError() : base::File::FILE_OK;
+
+ return {length, error};
+ }
+
+ // Returns {expected_length, base::File::FILE_OK} in case of success.
+ // Returns {actual file length, error} in case of failure.
+ std::pair<int64_t, base::File::Error> SetLength(int64_t expected_length) {
+ DCHECK(!IsMainThread());
+ DCHECK_GE(expected_length, 0);
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ bool success = file_.SetLength(expected_length);
+ base::File::Error error =
+ success ? base::File::FILE_OK : file_.GetLastFileError();
+ int64_t actual_length = success ? expected_length : file_.GetLength();
+
+ return {actual_length, error};
+ }
+
+#if defined(OS_MAC)
+ // Used to implement browser-side SetLength() on macOS < 10.15.
+ base::File TakeFile() {
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ return std::move(file_);
+ }
+
+ // Used to implement browser-side SetLength() on macOS < 10.15.
+ void SetFile(base::File file) {
+ WTF::MutexLocker locker(mutex_);
+ DCHECK(!file_.IsValid()) << __func__ << " called on valid file";
+
+ file_ = std::move(file);
+ }
+#endif // defined(OS_MAC)
+
+ // Returns {read byte count, base::File::FILE_OK} in case of success.
+ // Returns {invalid number, error} in case of failure.
+ std::pair<int, base::File::Error> Read(NativeIODataBuffer* buffer,
+ int64_t file_offset,
+ int read_size) {
+ DCHECK(!IsMainThread());
+ DCHECK(buffer);
+ DCHECK_GE(file_offset, 0);
+ DCHECK_GE(read_size, 0);
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ int read_bytes = file_.Read(file_offset, buffer->Data(), read_size);
+ base::File::Error error =
+ (read_bytes < 0) ? file_.GetLastFileError() : base::File::FILE_OK;
+
+ return {read_bytes, error};
+ }
+
+ // Returns {0, write_size, base::File::FILE_OK} in case of success.
+ // Returns {actual file length, written bytes, base::File::OK} in case of a
+ // short write.
+ // Returns {actual file length, invalid number, error} in case of failure.
+ std::tuple<int64_t, int, base::File::Error> Write(NativeIODataBuffer* buffer,
+ int64_t file_offset,
+ int write_size) {
+ DCHECK(!IsMainThread());
+ DCHECK(buffer);
+ DCHECK_GE(file_offset, 0);
+ DCHECK_GE(write_size, 0);
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ int written_bytes = file_.Write(file_offset, buffer->Data(), write_size);
+ base::File::Error error =
+ (written_bytes < 0) ? file_.GetLastFileError() : base::File::FILE_OK;
+ int64_t actual_file_length_on_failure = 0;
+ if (written_bytes < write_size || error != base::File::FILE_OK) {
+ actual_file_length_on_failure = file_.GetLength();
+ if (actual_file_length_on_failure < 0 && error != base::File::FILE_OK)
+ error = file_.GetLastFileError();
+ }
+
+ return {actual_file_length_on_failure, written_bytes, error};
+ }
+
+ base::File::Error Flush() {
+ DCHECK(!IsMainThread());
+
+ WTF::MutexLocker mutex_locker(mutex_);
+ DCHECK(file_.IsValid()) << __func__ << " called on invalid file";
+
+ bool success = file_.Flush();
+ return success ? base::File::FILE_OK : file_.GetLastFileError();
+ }
+
+ private:
// Lock coordinating cross-thread access to the state.
- WTF::Mutex mutex;
+ WTF::Mutex mutex_;
+
// The file on disk backing this NativeIOFile.
- //
- // The mutex is there to protect us against using the file after it was
- // closed, and against OS-specific behavior around concurrent file access. It
- // should never cause the main (JS) thread to block. This is because the mutex
- // is only taken on the main thread in CloseBackingFile(), which is called
- // when the NativeIOFile is destroyed (which implies there's no pending I/O
- // operation, because all I/O operations hold onto a Persistent<NativeIOFile>)
- // and when the mojo pipe is closed, which currently only happens when the JS
- // context is being torn down.
- //
- // TODO(rstz): Is it possible and worthwhile to remove the mutex and rely
- // exclusively on |NativeIOFile::io_pending_|, or remove
- // |NativeIOFile::io_pending_| in favor of the mutex (might be harder)?
- base::File file GUARDED_BY(mutex);
+ base::File file_ GUARDED_BY(mutex_);
};
NativeIOFile::NativeIOFile(
@@ -81,7 +218,7 @@ NativeIOFile::NativeIOFile(
NativeIOCapacityTracker* capacity_tracker,
ExecutionContext* execution_context)
: file_length_(backing_file_length),
- file_state_(std::make_unique<FileState>(std::move(backing_file))),
+ file_state_(base::MakeRefCounted<FileState>(std::move(backing_file))),
// TODO(pwnall): Get a dedicated queue when the specification matures.
resolver_task_runner_(
execution_context->GetTaskRunner(TaskType::kMiscPlatformAPI)),
@@ -94,7 +231,7 @@ NativeIOFile::NativeIOFile(
}
NativeIOFile::~NativeIOFile() {
- // Needed to avoid having the base::File destructor close the file descriptor
+ // Needed to avoid having the FileState destructor close the file descriptor
// synchronously on the main thread.
CloseBackingFile();
}
@@ -114,6 +251,9 @@ ScriptPromise NativeIOFile::close(ScriptState* script_state) {
queued_close_resolver_ = resolver;
if (!io_pending_) {
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+
// Pretend that a close() promise was queued behind an I/O operation, and
// the operation just finished. This is less logic than handling the
// non-queued case separately.
@@ -138,18 +278,15 @@ ScriptPromise NativeIOFile::getLength(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
- io_pending_ = true;
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+ io_pending_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState
- // instance is owned by this NativeIOFile, which is also passed to the task
- // via WrapCrossThreadPersistent. Therefore, the FileState instance is
- // guaranteed to remain alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoGetLength, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_));
return resolver->Promise();
}
@@ -175,6 +312,9 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+
int64_t expected_length = base::as_signed(new_length);
DCHECK_GE(expected_length, 0);
@@ -201,8 +341,8 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
}
file_length_ = expected_length;
}
- io_pending_ = true;
+ io_pending_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
#if defined(OS_MAC)
@@ -217,26 +357,19 @@ ScriptPromise NativeIOFile::setLength(ScriptState* script_state,
// To preserve this invariant, we pass this file's handle to the browser
// process during the SetLength() mojo call, and the browser passes it back
// when the call completes.
- {
- WTF::MutexLocker locker(file_state_->mutex);
- backend_file_->SetLength(
- expected_length, std::move(file_state_->file),
- WTF::Bind(&NativeIOFile::DidSetLengthIpc, WrapPersistent(this),
- WrapPersistent(resolver)));
- }
+ base::File file = file_state_->TakeFile();
+ backend_file_->SetLength(
+ expected_length, std::move(file),
+ WTF::Bind(&NativeIOFile::DidSetLengthIpc, WrapPersistent(this),
+ WrapPersistent(resolver)));
return resolver->Promise();
}
#endif // defined(OS_MAC)
- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState
- // instance is owned by this NativeIOFile, which is also passed to the task
- // via WrapCrossThreadPersistent. Therefore, the FileState instance is
- // guaranteed to remain alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoSetLength, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_, expected_length));
return resolver->Promise();
}
@@ -258,6 +391,8 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
// TODO(pwnall): This assignment should move right before the
// worker_pool::PostTask() call.
@@ -281,16 +416,10 @@ ScriptPromise NativeIOFile::read(ScriptState* script_state,
DCHECK(buffer->IsDetached());
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // The first CrossThreadUnretained() is safe here because the
- // NativeIOFile::FileState instance is owned by this NativeIOFile, which is
- // also passed to the task via WrapCrossThreadPersistent. Therefore, the
- // FileState instance is guaranteed to remain alive during the task's
- // execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoRead, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_, std::move(result_buffer_data),
file_offset, read_size));
return resolver->Promise();
@@ -313,6 +442,8 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
int write_size = NativeIOOperationSize(*buffer);
int64_t write_end_offset;
@@ -346,6 +477,14 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
file_length_ = write_end_offset;
}
+ // TODO(pwnall): This assignment should move right before the
+ // worker_pool::PostTask() call.
+ //
+ // `io_pending_` should only be set to true when we know for sure we'll post a
+ // task that eventually results in getting `io_pending_` set back to false.
+ // Having `io_pending_` set to true in an early return case (rejecting with an
+ // exception) leaves the NativeIOFile "stuck" in a state where all future I/O
+ // method calls will reject.
io_pending_ = true;
std::unique_ptr<NativeIODataBuffer> result_buffer_data =
@@ -358,16 +497,10 @@ ScriptPromise NativeIOFile::write(ScriptState* script_state,
DCHECK(buffer->IsDetached());
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // The first CrossThreadUnretained() is safe here because the
- // NativeIOFile::FileState instance is owned by this NativeIOFile, which is
- // also passed to the task via WrapCrossThreadPersistent. Therefore, the
- // FileState instance is guaranteed to remain alive during the task's
- // execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoWrite, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_, std::move(result_buffer_data),
file_offset, write_size));
return resolver->Promise();
@@ -391,18 +524,15 @@ ScriptPromise NativeIOFile::flush(ScriptState* script_state,
"The file was already closed"));
return ScriptPromise();
}
- io_pending_ = true;
+ DCHECK(file_state_)
+ << "file_state_ nulled out without setting closed_ or io_pending_";
+ io_pending_ = true;
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
- // CrossThreadUnretained() is safe here because the NativeIOFile::FileState
- // instance is owned by this NativeIOFile, which is also passed to the task
- // via WrapCrossThreadPersistent. Therefore, the FileState instance is
- // guaranteed to remain alive during the task's execution.
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoFlush, WrapCrossThreadPersistent(this),
- WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
+ WrapCrossThreadPersistent(resolver), file_state_,
resolver_task_runner_));
return resolver->Promise();
}
@@ -430,28 +560,29 @@ void NativeIOFile::DispatchQueuedClose() {
ScriptPromiseResolver* resolver = queued_close_resolver_;
queued_close_resolver_ = nullptr;
+ scoped_refptr<FileState> file_state = std::move(file_state_);
+ DCHECK(!file_state_);
+
worker_pool::PostTask(
FROM_HERE, {base::MayBlock()},
CrossThreadBindOnce(&DoClose, WrapCrossThreadPersistent(this),
WrapCrossThreadPersistent(resolver),
- CrossThreadUnretained(file_state_.get()),
- resolver_task_runner_));
+ std::move(file_state), resolver_task_runner_));
}
// static
void NativeIOFile::DoClose(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+ DCHECK(resolver_task_runner);
- {
- WTF::MutexLocker locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- file_state->file.Close();
- }
+ file_state->Close();
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -482,19 +613,17 @@ void NativeIOFile::DidClose(
void NativeIOFile::DoGetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+ DCHECK(resolver_task_runner);
+
+ int64_t length;
base::File::Error get_length_error;
- int64_t length = -1;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- length = file_state->file.GetLength();
- get_length_error = (length < 0) ? file_state->file.GetLastFileError()
- : base::File::FILE_OK;
- }
+ std::tie(length, get_length_error) = file_state->GetLength();
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -541,22 +670,20 @@ void NativeIOFile::DidGetLength(
void NativeIOFile::DoSetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
int64_t expected_length) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+ DCHECK(resolver_task_runner);
+ DCHECK_GE(expected_length, 0);
- base::File::Error set_length_error;
int64_t actual_length;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- bool success = file_state->file.SetLength(expected_length);
- set_length_error =
- success ? base::File::FILE_OK : file_state->file.GetLastFileError();
- actual_length = success ? expected_length : file_state->file.GetLength();
- }
+ base::File::Error set_length_error;
+ std::tie(actual_length, set_length_error) =
+ file_state->SetLength(expected_length);
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -619,10 +746,7 @@ void NativeIOFile::DidSetLengthIpc(
int64_t actual_length,
mojom::blink::NativeIOErrorPtr set_length_error) {
DCHECK(backing_file.IsValid()) << "browser returned closed file";
- {
- WTF::MutexLocker locker(file_state_->mutex);
- file_state_->file = std::move(backing_file);
- }
+ file_state_->SetFile(std::move(backing_file));
ScriptState* script_state = resolver->GetScriptState();
DCHECK(io_pending_) << "I/O operation performed without io_pending_ set";
@@ -673,13 +797,15 @@ void NativeIOFile::DidSetLengthIpc(
void NativeIOFile::DoRead(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int read_size) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
-
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
DCHECK(resolver_task_runner);
DCHECK(result_buffer_data);
DCHECK(result_buffer_data->IsValid());
@@ -690,15 +816,8 @@ void NativeIOFile::DoRead(
int read_bytes;
base::File::Error read_error;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- read_bytes = file_state->file.Read(file_offset, result_buffer_data->Data(),
- read_size);
- read_error = (read_bytes < 0) ? file_state->file.GetLastFileError()
- : base::File::FILE_OK;
- }
+ std::tie(read_bytes, read_error) =
+ file_state->Read(result_buffer_data.get(), file_offset, read_size);
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -743,12 +862,15 @@ void NativeIOFile::DidRead(
void NativeIOFile::DoWrite(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
int write_size) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
DCHECK(resolver_task_runner);
DCHECK(result_buffer_data);
DCHECK(result_buffer_data->IsValid());
@@ -760,22 +882,8 @@ void NativeIOFile::DoWrite(
int written_bytes;
int64_t actual_file_length_on_failure = 0;
base::File::Error write_error;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- written_bytes = file_state->file.Write(
- file_offset, result_buffer_data->Data(), write_size);
- write_error = (written_bytes < 0) ? file_state->file.GetLastFileError()
- : base::File::FILE_OK;
- if (written_bytes < write_size || write_error != base::File::FILE_OK) {
- actual_file_length_on_failure = file_state->file.GetLength();
- if (actual_file_length_on_failure < 0 &&
- write_error != base::File::FILE_OK) {
- write_error = file_state->file.GetLastFileError();
- }
- }
- }
+ std::tie(actual_file_length_on_failure, written_bytes, write_error) =
+ file_state->Write(result_buffer_data.get(), file_offset, write_size);
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -846,18 +954,14 @@ void NativeIOFile::DidWrite(
void NativeIOFile::DoFlush(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner) {
DCHECK(!IsMainThread()) << "File I/O should not happen on the main thread";
- base::File::Error flush_error;
- {
- WTF::MutexLocker mutex_locker(file_state->mutex);
- DCHECK(file_state->file.IsValid())
- << "file I/O operation queued after file closed";
- bool success = file_state->file.Flush();
- flush_error =
- success ? base::File::FILE_OK : file_state->file.GetLastFileError();
- }
+ DCHECK(file_state);
+ DCHECK(file_state->IsValid())
+ << "File I/O operation queued after file closed";
+
+ base::File::Error flush_error = file_state->Flush();
PostCrossThreadTask(
*resolver_task_runner, FROM_HERE,
@@ -887,20 +991,23 @@ void NativeIOFile::DidFlush(
void NativeIOFile::CloseBackingFile() {
closed_ = true;
- file_state_->mutex.lock();
- base::File backing_file = std::move(file_state_->file);
- file_state_->mutex.unlock();
- if (!backing_file.IsValid()) {
+ if (!file_state_) {
// Avoid posting a cross-thread task if the file is already closed. This is
// the expected path.
return;
}
- worker_pool::PostTask(
- FROM_HERE, {base::MayBlock()},
- CrossThreadBindOnce([](base::File file) { file.Close(); },
- std::move(backing_file)));
+ scoped_refptr<FileState> file_state = std::move(file_state_);
+ DCHECK(!file_state_);
+
+ worker_pool::PostTask(FROM_HERE, {base::MayBlock()},
+ CrossThreadBindOnce(
+ [](scoped_refptr<FileState> file_state) {
+ DCHECK(file_state);
+ file_state->Close();
+ },
+ std::move(file_state)));
}
} // namespace blink
diff --git a/third_party/blink/renderer/modules/native_io/native_io_file.h b/third_party/blink/renderer/modules/native_io/native_io_file.h
index 8ae49ebc2d36d547d152d4e56192e30f8cacd641..95d2da4ac3e1859a0abc21ea15d269758eed1681 100644
--- a/third_party/blink/renderer/modules/native_io/native_io_file.h
+++ b/third_party/blink/renderer/modules/native_io/native_io_file.h
@@ -67,12 +67,7 @@ class NativeIOFile final : public ScriptWrappable {
void Trace(Visitor* visitor) const override;
private:
- // Data accessed on the threads that do file I/O.
- //
- // Instances are allocated on the PartitionAlloc heap. Instances are initially
- // constructed on Blink's main thread, or on a worker thread. Afterwards,
- // instances are only accessed on dedicated threads that do blocking file I/O.
- struct FileState;
+ class FileState;
// Called when the mojo backend disconnects.
void OnBackendDisconnect();
@@ -84,7 +79,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoClose(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
// Performs the post file I/O part of close(), on the main thread.
void DidClose(CrossThreadPersistent<ScriptPromiseResolver> resolver);
@@ -93,7 +88,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoGetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
// Performs the post file I/O part of getLength(), on the main thread.
void DidGetLength(CrossThreadPersistent<ScriptPromiseResolver> resolver,
@@ -104,7 +99,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoSetLength(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
int64_t expected_length);
// Performs the post file I/O part of setLength(), on the main thread.
@@ -128,7 +123,7 @@ class NativeIOFile final : public ScriptWrappable {
// Performs the file I/O part of read(), off the main thread.
static void DoRead(CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
@@ -143,7 +138,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoWrite(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> resolver_task_runner,
std::unique_ptr<NativeIODataBuffer> result_buffer_data,
uint64_t file_offset,
@@ -163,7 +158,7 @@ class NativeIOFile final : public ScriptWrappable {
static void DoFlush(
CrossThreadPersistent<NativeIOFile> native_io_file,
CrossThreadPersistent<ScriptPromiseResolver> resolver,
- NativeIOFile::FileState* file_state,
+ scoped_refptr<NativeIOFile::FileState> file_state,
scoped_refptr<base::SequencedTaskRunner> file_task_runner);
// Performs the post file-I/O part of flush(), on the main thread.
void DidFlush(CrossThreadPersistent<ScriptPromiseResolver> resolver,
@@ -210,8 +205,13 @@ class NativeIOFile final : public ScriptWrappable {
// TODO(rstz): Consider moving this variable into `file_state_`
int64_t file_length_ = 0;
- // See NativeIOFile::FileState, declared above.
- const std::unique_ptr<FileState> file_state_;
+ // Points to a NativeIOFile::FileState while the underlying file is open.
+ //
+ // When the underlying file is closed, this pointer is nulled out, and the
+ // FileState instance is passed to a different thread, where the closing
+ // happens. This avoids having any I/O performed by the base::File::Close()
+ // jank the JavaScript thread that owns this NativeIOFile instance.
+ scoped_refptr<FileState> file_state_;
// Schedules resolving Promises with file I/O results.
const scoped_refptr<base::SequencedTaskRunner> resolver_task_runner_;

View File

@@ -0,0 +1,151 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Stephen Roettger <sroettger@google.com>
Date: Fri, 7 Jan 2022 09:36:31 +0000
Subject: Keep a set of previously dropped peers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Test that a given node name hasn't been seen before.
A side effect of this fix is that re-invitation will not work anymore.
BUG=chromium:1274113
Change-Id: Ibdc50291efa1f6298614b163b544ad980615a981
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3341553
Reviewed-by: Ken Rockot <rockot@google.com>
Commit-Queue: Stephen Röttger <sroettger@google.com>
Cr-Commit-Position: refs/heads/main@{#956441}
diff --git a/mojo/core/invitation_unittest.cc b/mojo/core/invitation_unittest.cc
index 2c8eeef9feefc6be689f1ca2052af316b4b7db68..0687a58ee2b294580d1165e872ec5855e5de2b53 100644
--- a/mojo/core/invitation_unittest.cc
+++ b/mojo/core/invitation_unittest.cc
@@ -693,7 +693,8 @@ DEFINE_TEST_CLIENT(ProcessErrorsClient) {
EXPECT_EQ(kDisconnectMessage, ReadMessage(pipe));
}
-TEST_F(InvitationTest, Reinvitation) {
+// Temporary removed support for reinvitation for non-isolated connections.
+TEST_F(InvitationTest, DISABLED_Reinvitation) {
// The gist of this test is that a process should be able to accept an
// invitation, lose its connection to the process network, and then accept a
// new invitation to re-establish communication.
diff --git a/mojo/core/node_controller.cc b/mojo/core/node_controller.cc
index 21edab39368e69ee6665e490b2c4de13f424edbd..79b933ebbe9eb1cb9eb11512f8480c682811745c 100644
--- a/mojo/core/node_controller.cc
+++ b/mojo/core/node_controller.cc
@@ -543,7 +543,8 @@ scoped_refptr<NodeChannel> NodeController::GetBrokerChannel() {
void NodeController::AddPeer(const ports::NodeName& name,
scoped_refptr<NodeChannel> channel,
- bool start_channel) {
+ bool start_channel,
+ bool allow_name_reuse) {
DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
DCHECK(name != ports::kInvalidNodeName);
@@ -562,6 +563,11 @@ void NodeController::AddPeer(const ports::NodeName& name,
return;
}
+ if (dropped_peers_.Contains(name) && !allow_name_reuse) {
+ LOG(ERROR) << "Trying to re-add dropped peer " << name;
+ return;
+ }
+
auto result = peers_.insert(std::make_pair(name, channel));
DCHECK(result.second);
@@ -602,6 +608,7 @@ void NodeController::DropPeer(const ports::NodeName& node_name,
if (it != peers_.end()) {
ports::NodeName peer = it->first;
peers_.erase(it);
+ dropped_peers_.Insert(peer);
DVLOG(1) << "Dropped peer " << peer;
}
@@ -1265,7 +1272,8 @@ void NodeController::OnAcceptPeer(const ports::NodeName& from_node,
// Note that we explicitly drop any prior connection to the same peer so
// that new isolated connections can replace old ones.
DropPeer(peer_name, nullptr);
- AddPeer(peer_name, channel, false /* start_channel */);
+ AddPeer(peer_name, channel, false /* start_channel */,
+ true /* allow_name_reuse */);
DVLOG(1) << "Node " << name_ << " accepted peer " << peer_name;
}
@@ -1381,5 +1389,24 @@ NodeController::IsolatedConnection&
NodeController::IsolatedConnection::operator=(IsolatedConnection&& other) =
default;
+BoundedPeerSet::BoundedPeerSet() = default;
+BoundedPeerSet::~BoundedPeerSet() = default;
+
+void BoundedPeerSet::Insert(const ports::NodeName& name) {
+ if (new_set_.size() == kHalfSize) {
+ old_set_.clear();
+ std::swap(old_set_, new_set_);
+ }
+ new_set_.insert(name);
+}
+
+bool BoundedPeerSet::Contains(const ports::NodeName& name) {
+ if (old_set_.find(name) != old_set_.end())
+ return true;
+ if (new_set_.find(name) != new_set_.end())
+ return true;
+ return false;
+}
+
} // namespace core
} // namespace mojo
diff --git a/mojo/core/node_controller.h b/mojo/core/node_controller.h
index 040eeab79f72efcdb2823cf62e7dbaefa8b9233f..571e578da4950135456bb97c8ea7a30ceabca7cc 100644
--- a/mojo/core/node_controller.h
+++ b/mojo/core/node_controller.h
@@ -38,6 +38,26 @@ namespace core {
class Broker;
class Core;
+// A set of NodeNames that is bounded by a maximum size.
+// If the max size is reached, it will delete the older half of stored names.
+class BoundedPeerSet {
+ public:
+ BoundedPeerSet();
+ BoundedPeerSet(const BoundedPeerSet&) = delete;
+ BoundedPeerSet& operator=(const BoundedPeerSet&) = delete;
+
+ ~BoundedPeerSet();
+
+ void Insert(const ports::NodeName& name);
+ bool Contains(const ports::NodeName& name);
+
+ private:
+ static constexpr int kHalfSize = 50000;
+
+ std::unordered_set<ports::NodeName> old_set_;
+ std::unordered_set<ports::NodeName> new_set_;
+};
+
// The owner of ports::Node which facilitates core EDK implementation. All
// public interface methods are safe to call from any thread.
class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
@@ -180,7 +200,8 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
void AddPeer(const ports::NodeName& name,
scoped_refptr<NodeChannel> channel,
- bool start_channel);
+ bool start_channel,
+ bool allow_name_reuse = false);
void DropPeer(const ports::NodeName& name, NodeChannel* channel);
void SendPeerEvent(const ports::NodeName& name, ports::ScopedEvent event);
void DropAllPeers();
@@ -265,6 +286,7 @@ class MOJO_SYSTEM_IMPL_EXPORT NodeController : public ports::NodeDelegate,
// Channels to known peers, including inviter and invitees, if any.
NodeMap peers_;
+ BoundedPeerSet dropped_peers_;
// Outgoing message queues for peers we've heard of but can't yet talk to.
std::unordered_map<ports::NodeName, OutgoingMessageQueue>

View File

@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Wed, 2 Feb 2022 05:45:44 +0000
Subject: Viz: Fix UAF on context loss
(cherry picked from commit 98d246cabe677e1d8287e4d42ce02825417be9e2)
Fixed: 1250655
Change-Id: I2898316635d370fa36b94e0ae2564ed357745b2c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3413372
Auto-Submit: Ken Rockot <rockot@google.com>
Reviewed-by: Kyle Charbonneau <kylechar@chromium.org>
Commit-Queue: Kyle Charbonneau <kylechar@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#963012}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3430523
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Commit-Position: refs/branch-heads/4758@{#1050}
Cr-Branched-From: 4a2cf4baf90326df19c3ee70ff987960d59a386e-refs/heads/main@{#950365}
diff --git a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
index a31c10c610000415b5a88a0824eea63b45a435cc..1b323f142d934afea0215dea190efaa197cec554 100644
--- a/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/services/viz/public/cpp/gpu/context_provider_command_buffer.cc
@@ -478,9 +478,13 @@ const gpu::GpuFeatureInfo& ContextProviderCommandBuffer::GetGpuFeatureInfo()
void ContextProviderCommandBuffer::OnLostContext() {
CheckValidThreadOrLockAcquired();
- // Ensure |this| isn't destroyed in the middle of OnLostContext() if observers
- // drop all references to it.
- scoped_refptr<ContextProviderCommandBuffer> ref(this);
+ // Observers may drop the last persistent references to `this`, but there may
+ // be weak references in use further up the stack. This task is posted to
+ // ensure that destruction is deferred until it's safe.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce([](scoped_refptr<ContextProviderCommandBuffer>) {},
+ base::WrapRefCounted(this)));
for (auto& observer : observers_)
observer.OnContextLost();

View File

@@ -0,0 +1,183 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jarryd <jarrydg@chromium.org>
Date: Wed, 29 Dec 2021 19:49:22 +0000
Subject: Quota: Use Threadsafe Pressure Callback.
Fixes UAF by removing use of raw ptr to StorageNotificationService.
Instead, the service's interface exposes a method to create a
thread-safe callback to pass to the quota manager instead.
This change also changes the parameter type for the call chain from
url::Origin to blink::StorageKey to match the type Quota is keyed on.
Bug:1275020
(cherry picked from commit e304c0373f9cc4a65d39d7094e4897627e83390e)
Change-Id: Icc696d22fa41324e7a6c056599db635bb5de6291
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3347939
Reviewed-by: Joshua Bell <jsbell@chromium.org>
Reviewed-by: Nasko Oskov <nasko@chromium.org>
Commit-Queue: Jarryd Goodman <jarrydg@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#953375}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3360203
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Owners-Override: Krishna Govind <govind@chromium.org>
Commit-Queue: Krishna Govind <govind@chromium.org>
Cr-Commit-Position: refs/branch-heads/4664@{#1352}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/chrome/browser/storage/storage_notification_service_impl.cc b/chrome/browser/storage/storage_notification_service_impl.cc
index f8b38745827b25e46bfd1b4225bb3c55f2836d02..ceeafe0ad40e69574ccf885e4230ce042ecbaaaa 100644
--- a/chrome/browser/storage/storage_notification_service_impl.cc
+++ b/chrome/browser/storage/storage_notification_service_impl.cc
@@ -10,6 +10,8 @@
#include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/ui/storage_pressure_bubble.h"
@@ -36,8 +38,26 @@ const base::TimeDelta GetThrottlingInterval() {
} // namespace
+StoragePressureNotificationCallback
+StorageNotificationServiceImpl::CreateThreadSafePressureNotificationCallback() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ auto thread_unsafe_callback = base::BindRepeating(
+ &StorageNotificationServiceImpl::MaybeShowStoragePressureNotification,
+ weak_ptr_factory_.GetWeakPtr());
+ return base::BindRepeating(
+ [](StoragePressureNotificationCallback cb, blink::StorageKey key) {
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce([](StoragePressureNotificationCallback callback,
+ blink::StorageKey key) { callback.Run(key); },
+ std::move(cb), key));
+ },
+ std::move(thread_unsafe_callback));
+}
+
void StorageNotificationServiceImpl::MaybeShowStoragePressureNotification(
- const url::Origin origin) {
+ const blink::StorageKey storage_key) {
+ auto origin = storage_key.origin();
if (!disk_pressure_notification_last_sent_at_.is_null() &&
base::TimeTicks::Now() - disk_pressure_notification_last_sent_at_ <
GetThrottlingInterval()) {
diff --git a/chrome/browser/storage/storage_notification_service_impl.h b/chrome/browser/storage/storage_notification_service_impl.h
index 497a3063c835a37fe9141052263cf70c863235fa..44fe169b82ced5e328060f191d608aaa57d3af71 100644
--- a/chrome/browser/storage/storage_notification_service_impl.h
+++ b/chrome/browser/storage/storage_notification_service_impl.h
@@ -5,10 +5,12 @@
#ifndef CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_IMPL_H_
#define CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_IMPL_H_
+#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/profiles/profile.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/storage_notification_service.h"
+#include "third_party/blink/public/common/storage_key/storage_key.h"
class StorageNotificationServiceImpl
: public content::StorageNotificationService,
@@ -16,13 +18,20 @@ class StorageNotificationServiceImpl
public:
StorageNotificationServiceImpl();
~StorageNotificationServiceImpl() override;
- void MaybeShowStoragePressureNotification(const url::Origin) override;
+ // Called from the UI thread, this method returns a callback that can passed
+ // to any thread, and proxies calls to
+ // `MaybeShowStoragePressureNotification()` back to the UI thread. It wraps a
+ // weak pointer to `this`.
+ StoragePressureNotificationCallback
+ CreateThreadSafePressureNotificationCallback() override;
+ void MaybeShowStoragePressureNotification(const blink::StorageKey) override;
base::TimeTicks GetLastSentAtForTesting() {
return disk_pressure_notification_last_sent_at_;
}
private:
base::TimeTicks disk_pressure_notification_last_sent_at_;
+ base::WeakPtrFactory<StorageNotificationServiceImpl> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_STORAGE_STORAGE_NOTIFICATION_SERVICE_IMPL_H_
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index 86c6de60739a0c5aa49ed63f1546b478d7f58054..263fe6195ac6d48cd7a985ca844d1a6e421a9b1d 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1169,23 +1169,14 @@ void StoragePartitionImpl::Initialize(
StorageNotificationService* storage_notification_service =
browser_context_->GetStorageNotificationService();
if (storage_notification_service) {
- // base::Unretained is safe to use because the BrowserContext is guaranteed
- // to outlive QuotaManager. This is because BrowserContext outlives this
- // StoragePartitionImpl, which destroys the QuotaManager on teardown.
- base::RepeatingCallback<void(const blink::StorageKey)>
- send_notification_function = base::BindRepeating(
- [](StorageNotificationService* service,
- const blink::StorageKey storage_key) {
- GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&StorageNotificationService::
- MaybeShowStoragePressureNotification,
- base::Unretained(service),
- std::move(storage_key.origin())));
- },
- base::Unretained(storage_notification_service));
-
- quota_manager_->SetStoragePressureCallback(send_notification_function);
+ // The weak ptr associated with the pressure notification callback will be
+ // created and evaluated by a task runner on the UI thread, as confirmed by
+ // the DCHECK's above, ensuring that the task runner does not attempt to run
+ // the callback in the case that the storage notification service is already
+ // destructed.
+ quota_manager_->SetStoragePressureCallback(
+ storage_notification_service
+ ->CreateThreadSafePressureNotificationCallback());
}
// Each consumer is responsible for registering its QuotaClient during
diff --git a/content/public/browser/storage_notification_service.h b/content/public/browser/storage_notification_service.h
index 3eec5ef29051008041695bcf7ebbf63787f5bd89..e72adada318f1cb998e2a9e7468a6f2e54742760 100644
--- a/content/public/browser/storage_notification_service.h
+++ b/content/public/browser/storage_notification_service.h
@@ -8,6 +8,15 @@
#include "base/bind.h"
#include "url/origin.h"
+namespace blink {
+class StorageKey;
+}
+
+namespace {
+using StoragePressureNotificationCallback =
+ base::RepeatingCallback<void(const blink::StorageKey)>;
+}
+
namespace content {
// This interface is used to create a connection between the storage layer and
@@ -19,12 +28,15 @@ class StorageNotificationService {
StorageNotificationService() = default;
~StorageNotificationService() = default;
- // This pure virtual function should be implemented in the embedder layer
+ // These pure virtual functions should be implemented in the embedder layer
// where calls to UI and notification code can be implemented. This closure
// is passed to QuotaManager in StoragePartitionImpl, where it is called
// when QuotaManager determines appropriate to alert the user that the device
// is in a state of storage pressure.
- virtual void MaybeShowStoragePressureNotification(const url::Origin) = 0;
+ virtual void MaybeShowStoragePressureNotification(
+ const blink::StorageKey) = 0;
+ virtual StoragePressureNotificationCallback
+ CreateThreadSafePressureNotificationCallback() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(StorageNotificationService);

View File

@@ -0,0 +1,62 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Fri, 10 Dec 2021 01:03:53 +0000
Subject: mojo/ipc: Drop messages targeting invalid task runner
If the endpoint's task runner does not match the current task runner (or
an equivalent main-thread task runner for the ChannelProxy) when a
executing a message dispatch task for that endpoint, this ignores the
message instead of dispatching it on the wrong sequence.
(cherry picked from commit 0747c9405e1098c0bbbc5593183696eafb45b72c)
Fixed: 1263457
Change-Id: I4f6ba22de3ff8cf3994b748e1ffd0f0aabb17b70
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3318601
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Ken Rockot <rockot@google.com>
Cr-Original-Commit-Position: refs/heads/main@{#949140}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3328403
Auto-Submit: Ken Rockot <rockot@google.com>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/branch-heads/4664@{#1269}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc
index 18b4dc9be5bf54e6f5443d53739bc06ba3f98767..07e522337090494e278395ac4e7ead73c472ef72 100644
--- a/ipc/ipc_mojo_bootstrap.cc
+++ b/ipc/ipc_mojo_bootstrap.cc
@@ -966,11 +966,14 @@ class ChannelAssociatedGroupController
if (!client)
return;
+ if (!endpoint->task_runner()->RunsTasksInCurrentSequence() &&
+ !proxy_task_runner_->RunsTasksInCurrentSequence()) {
+ return;
+ }
+
// Using client->interface_name() is safe here because this is a static
// string defined for each mojo interface.
TRACE_EVENT0("mojom", client->interface_name());
- DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence() ||
- proxy_task_runner_->RunsTasksInCurrentSequence());
// Sync messages should never make their way to this method.
DCHECK(!message.has_flag(mojo::Message::kFlagIsSync));
@@ -1000,11 +1003,14 @@ class ChannelAssociatedGroupController
if (!client)
return;
+ if (!endpoint->task_runner()->RunsTasksInCurrentSequence() &&
+ !proxy_task_runner_->RunsTasksInCurrentSequence()) {
+ return;
+ }
+
// Using client->interface_name() is safe here because this is a static
// string defined for each mojo interface.
TRACE_EVENT0("mojom", client->interface_name());
- DCHECK(endpoint->task_runner()->RunsTasksInCurrentSequence() ||
- proxy_task_runner_->RunsTasksInCurrentSequence());
MessageWrapper message_wrapper = endpoint->PopSyncMessage(message_id);
// The message must have already been dequeued by the endpoint waking up

View File

@@ -0,0 +1,308 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Patrick Meenan <pmeenan@chromium.org>
Date: Fri, 3 Dec 2021 18:15:17 +0000
Subject: Prevent opaque range request responses from entering the preload
cache
ResourceLoader cancels range request responses that were not initiated
with range request headers causing them to error out and be cleared from
the preload cache. Other responses (200, 416, error, etc) complete
successfully and would otherwise enter the preload cache, making them
observable.
This prevents opaque range responses of any kind from persisting in the
preload cache (which would not naturally have any anyway).
(cherry picked from commit a5f630e5f94da28a926d60da7dde194acd8697f0)
Bug: 1270990
Change-Id: Ife9922fe0b88e39722f3664ddd091a1516892157
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3294001
Reviewed-by: Ben Kelly <wanderview@chromium.org>
Reviewed-by: Yoav Weiss <yoavweiss@chromium.org>
Commit-Queue: Patrick Meenan <pmeenan@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#946055}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3313416
Auto-Submit: Patrick Meenan <pmeenan@chromium.org>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1222}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
index 8fc72ba0b932bd20b96630373e3bc4ee7765c8a1..d27c52259038fe5daf23f9ad0acbf7cb1ade38fb 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1873,6 +1873,19 @@ void ResourceFetcher::HandleLoaderFinish(Resource* resource,
}
resource->VirtualTimePauser().UnpauseVirtualTime();
+
+ // A response should not serve partial content if it was not requested via a
+ // Range header: https://fetch.spec.whatwg.org/#main-fetch so keep it out
+ // of the preload cache in case of a non-206 response (which generates an
+ // error).
+ if (resource->GetResponse().GetType() ==
+ network::mojom::FetchResponseType::kOpaque &&
+ resource->GetResponse().HasRangeRequested() &&
+ !resource->GetResourceRequest().HttpHeaderFields().Contains(
+ net::HttpRequestHeaders::kRange)) {
+ RemovePreload(resource);
+ }
+
if (type == kDidFinishLoading) {
resource->Finish(response_end, freezable_task_runner_.get());
diff --git a/third_party/blink/web_tests/external/wpt/fetch/range/resources/partial-text.py b/third_party/blink/web_tests/external/wpt/fetch/range/resources/partial-text.py
new file mode 100644
index 0000000000000000000000000000000000000000..a0058551d52d45b3c16882014be740d75e51ddd1
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/range/resources/partial-text.py
@@ -0,0 +1,47 @@
+"""
+This generates a partial response for a 100-byte text file.
+"""
+import re
+
+from wptserve.utils import isomorphic_decode
+
+def main(request, response):
+ total_length = int(request.GET.first(b'length', b'100'))
+ partial_code = int(request.GET.first(b'partial', b'206'))
+ range_header = request.headers.get(b'Range', b'')
+
+ # Send a 200 if there is no range request
+ if not range_header:
+ to_send = ''.zfill(total_length)
+ response.headers.set(b"Content-Type", b"text/plain")
+ response.headers.set(b"Cache-Control", b"no-cache")
+ response.headers.set(b"Content-Length", total_length)
+ response.content = to_send
+ return
+
+ # Simple range parsing, requires specifically "bytes=xxx-xxxx"
+ range_header_match = re.search(r'^bytes=(\d*)-(\d*)$', isomorphic_decode(range_header))
+ start, end = range_header_match.groups()
+ start = int(start)
+ end = int(end) if end else total_length
+ length = end - start
+
+ # Error the request if the range goes beyond the length
+ if length <= 0 or end > total_length:
+ response.set_error(416, u"Range Not Satisfiable")
+ response.write()
+ return
+
+ # Generate a partial response of the requested length
+ to_send = ''.zfill(length)
+ response.headers.set(b"Content-Type", b"text/plain")
+ response.headers.set(b"Accept-Ranges", b"bytes")
+ response.headers.set(b"Cache-Control", b"no-cache")
+ response.status = partial_code
+
+ content_range = b"bytes %d-%d/%d" % (start, end, total_length)
+
+ response.headers.set(b"Content-Range", content_range)
+ response.headers.set(b"Content-Length", length)
+
+ response.content = to_send
diff --git a/third_party/blink/web_tests/external/wpt/fetch/range/resources/range-sw.js b/third_party/blink/web_tests/external/wpt/fetch/range/resources/range-sw.js
index 3680c0c471d3d5f36c4aba4cc58dcd52c38a08df..b47823f03b4ef3749e622fbf7dd3b515a216b5be 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/range/resources/range-sw.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/range/resources/range-sw.js
@@ -12,7 +12,7 @@ async function broadcast(msg) {
}
}
-addEventListener('fetch', event => {
+addEventListener('fetch', async event => {
/** @type Request */
const request = event.request;
const url = new URL(request.url);
@@ -34,6 +34,11 @@ addEventListener('fetch', event => {
case 'broadcast-accept-encoding':
broadcastAcceptEncoding(event);
return;
+ case 'record-media-range-request':
+ return recordMediaRangeRequest(event);
+ case 'use-media-range-request':
+ useMediaRangeRequest(event);
+ return;
}
});
@@ -157,3 +162,57 @@ function broadcastAcceptEncoding(event) {
// Just send back any response, it isn't important for the test.
event.respondWith(new Response(''));
}
+
+let rangeResponse = {};
+
+async function recordMediaRangeRequest(event) {
+ /** @type Request */
+ const request = event.request;
+ const url = new URL(request.url);
+ const urlParams = new URLSearchParams(url.search);
+ const size = urlParams.get("size");
+ const id = urlParams.get('id');
+ const key = 'size' + size;
+
+ if (key in rangeResponse) {
+ // Don't re-fetch ranges we already have.
+ const clonedResponse = rangeResponse[key].clone();
+ event.respondWith(clonedResponse);
+ } else if (event.request.headers.get("range") === "bytes=0-") {
+ // Generate a bogus 206 response to trigger subsequent range requests
+ // of the desired size.
+ const length = urlParams.get("length") + 100;
+ const body = "A".repeat(Number(size));
+ event.respondWith(new Response(body, {status: 206, headers: {
+ "Content-Type": "audio/mp4",
+ "Content-Range": `bytes 0-1/${length}`
+ }}));
+ } else if (event.request.headers.get("range") === `bytes=${Number(size)}-`) {
+ // Pass through actual range requests which will attempt to fetch up to the
+ // length in the original response which is bigger than the actual resource
+ // to make sure 206 and 416 responses are treated the same.
+ rangeResponse[key] = await fetch(event.request);
+
+ // Let the client know we have the range response for the given ID
+ broadcast({id});
+ } else {
+ event.respondWith(Promise.reject(Error("Invalid Request")));
+ }
+}
+
+function useMediaRangeRequest(event) {
+ /** @type Request */
+ const request = event.request;
+ const url = new URL(request.url);
+ const urlParams = new URLSearchParams(url.search);
+ const size = urlParams.get("size");
+ const key = 'size' + size;
+
+ // Send a clone of the range response to preload.
+ if (key in rangeResponse) {
+ const clonedResponse = rangeResponse[key].clone();
+ event.respondWith(clonedResponse);
+ } else {
+ event.respondWith(Promise.reject(Error("Invalid Request")));
+ }
+}
diff --git a/third_party/blink/web_tests/external/wpt/fetch/range/resources/utils.js b/third_party/blink/web_tests/external/wpt/fetch/range/resources/utils.js
index 16ed737f63e8eee26a306c70acb0589e424db35d..ad2853b33dc7474293df1423dd8af459571736b9 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/range/resources/utils.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/range/resources/utils.js
@@ -8,6 +8,18 @@ function loadScript(url, { doc = document }={}) {
})
}
+function preloadImage(url, { doc = document }={}) {
+ return new Promise((resolve, reject) => {
+ const preload = doc.createElement('link');
+ preload.rel = 'preload';
+ preload.as = 'image';
+ preload.onload = () => resolve();
+ preload.onerror = () => resolve();
+ preload.href = url;
+ doc.body.appendChild(preload);
+ })
+}
+
/**
*
* @param {Document} document
diff --git a/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window-expected.txt
index 134b0a7abd817599921d4fb430e8247a2cb40f82..a9577f01727678cd7a76bcc65e132fd6fcb230ac 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window-expected.txt
@@ -4,6 +4,7 @@ PASS Defer range header passthrough tests to service worker
PASS Ranged response not allowed following no-cors ranged request
PASS Non-opaque ranged response executed
FAIL Accept-Encoding should not appear in a service worker assert_equals: Accept-Encoding should not be set for media expected (object) null but got (string) "identity;q=1, *;q=0"
+PASS Opaque range preload successes and failures should be indistinguishable
PASS Range headers correctly preserved
PASS Range headers correctly removed
PASS Headers correctly filtered
diff --git a/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window.js b/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window.js
index 76f80e9416c615417ad2a9fbaa565641ff5b8a12..42e4ac6d75afdcbb2ad1e9d3e4069d9cbfd10dbd 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/range/sw.https.window.js
@@ -149,3 +149,78 @@ promise_test(async t => {
assert_equals((await audioBroadcast).acceptEncoding, null, "Accept-Encoding should not be set for media");
}, `Accept-Encoding should not appear in a service worker`);
+
+promise_test(async t => {
+ const scope = BASE_SCOPE + Math.random();
+ await setupRegistration(t, scope);
+ const iframe = await with_iframe(scope);
+ const w = iframe.contentWindow;
+ const length = 100;
+ const count = 3;
+ const counts = {};
+
+ // test a single range request size
+ async function testSizedRange(size, partialResponseCode) {
+ const rangeId = Math.random() + '';
+ const rangeBroadcast = awaitMessage(w.navigator.serviceWorker, rangeId);
+
+ // Create a bogus audo element to trick the browser into sending
+ // cross-origin range requests that can be manipulated by the service worker.
+ const sound_url = new URL('partial-text.py', w.location);
+ sound_url.hostname = REMOTE_HOST;
+ sound_url.searchParams.set('action', 'record-media-range-request');
+ sound_url.searchParams.set('length', length);
+ sound_url.searchParams.set('size', size);
+ sound_url.searchParams.set('partial', partialResponseCode);
+ sound_url.searchParams.set('id', rangeId);
+ appendAudio(w.document, sound_url);
+
+ // wait for the range requests to happen
+ await rangeBroadcast;
+
+ // Create multiple preload requests and count the number of resource timing
+ // entries that get created to make sure 206 and 416 range responses are treated
+ // the same.
+ const url = new URL('partial-text.py', w.location);
+ url.searchParams.set('action', 'use-media-range-request');
+ url.searchParams.set('size', size);
+ counts['size' + size] = 0;
+ for (let i = 0; i < count; i++) {
+ await preloadImage(url, { doc: w.document });
+ }
+ }
+
+ // Test range requests from 1 smaller than the correct size to 1 larger than
+ // the correct size to exercise the various permutations using the default 206
+ // response code for successful range requests.
+ for (let size = length - 1; size <= length + 1; size++) {
+ await testSizedRange(size, '206');
+ }
+
+ // Test a successful range request using a 200 response.
+ await testSizedRange(length - 2, '200');
+
+ // Check the resource timing entries and count the reported number of fetches of each type
+ const resources = w.performance.getEntriesByType("resource");
+ for (const entry of resources) {
+ const url = new URL(entry.name);
+ if (url.searchParams.has('action') &&
+ url.searchParams.get('action') == 'use-media-range-request' &&
+ url.searchParams.has('size')) {
+ counts['size' + url.searchParams.get('size')]++;
+ }
+ }
+
+ // Make sure there are a non-zero number of preload requests and they are all the same
+ let counts_valid = true;
+ const first = 'size' + (length - 2);
+ for (let size = length - 2; size <= length + 1; size++) {
+ let key = 'size' + size;
+ if (!(key in counts) || counts[key] <= 0 || counts[key] != counts[first]) {
+ counts_valid = false;
+ break;
+ }
+ }
+
+ assert_true(counts_valid, `Opaque range request preloads were different for error and success`);
+}, `Opaque range preload successes and failures should be indistinguishable`);

View File

@@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kevin Ellis <kevers@google.com>
Date: Fri, 11 Feb 2022 01:36:04 +0000
Subject: Code health cleanup: replacing animations.
Animation::Update performed a synchronous processing of the finish
microtask to ensure that finished events where dispatched ahead of
replace events. This step does not align with the spec. Instead we
should be queuing the replace event. Microtasks will be processed in
the correct order.
Spec link: https://www.w3.org/TR/web-animations-1/#timelines
Change-Id: Ibe7753e792fb6cf905bbe6815a080a8cc51c2803
(cherry picked from commit d4fb69ff0fe343fe8a171014785a88eabfe2b1c2)
Bug: 1290858
Change-Id: Ibe7753e792fb6cf905bbe6815a080a8cc51c2803
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3414765
Reviewed-by: Mustaq Ahmed <mustaq@chromium.org>
Commit-Queue: Kevin Ellis <kevers@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#964223}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3453925
Reviewed-by: Adrian Taylor <adetaylor@google.com>
Commit-Queue: Krishna Govind <govind@chromium.org>
Cr-Commit-Position: refs/branch-heads/4758@{#1134}
Cr-Branched-From: 4a2cf4baf90326df19c3ee70ff987960d59a386e-refs/heads/main@{#950365}
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 545dcd7f0faae91cee574fce60fdedb4f6903bb6..96ecc0bf8c7dbb01714f680b6f0930d1e801f4a8 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -2232,10 +2232,6 @@ bool Animation::Update(TimingUpdateReason reason) {
if (reason == kTimingUpdateForAnimationFrame) {
if (idle || CalculateAnimationPlayState() == kFinished) {
- // TODO(crbug.com/1029348): Per spec, we should have a microtask
- // checkpoint right after the update cycle. Once this is fixed we should
- // no longer need to force a synchronous resolution here.
- AsyncFinishMicrotask();
finished_ = true;
}
}
diff --git a/third_party/blink/renderer/core/animation/document_animations.cc b/third_party/blink/renderer/core/animation/document_animations.cc
index 6e5b4f970387929b6b940b18e14e997d2baa339c..f8090e41f8b0aa2e138738f5a3ba7c434d85535b 100644
--- a/third_party/blink/renderer/core/animation/document_animations.cc
+++ b/third_party/blink/renderer/core/animation/document_animations.cc
@@ -45,6 +45,7 @@
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/page_animator.h"
#include "third_party/blink/renderer/platform/bindings/microtask.h"
+#include "third_party/blink/renderer/platform/heap/persistent.h"
namespace blink {
@@ -286,10 +287,13 @@ void DocumentAnimations::RemoveReplacedAnimations(
// The list of animations for removal is constructed in reverse composite
// ordering for efficiency. Flip the ordering to ensure that events are
- // dispatched in composite order.
+ // dispatched in composite order. Queue as a microtask so that the finished
+ // event is dispatched ahead of the remove event.
for (auto it = animations_to_remove.rbegin();
it != animations_to_remove.rend(); it++) {
- (*it)->RemoveReplacedAnimation();
+ Animation* animation = *it;
+ Microtask::EnqueueMicrotask(WTF::Bind(&Animation::RemoveReplacedAnimation,
+ WrapWeakPersistent(animation)));
}
}

View File

@@ -0,0 +1,55 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ken Rockot <rockot@google.com>
Date: Sat, 5 Feb 2022 13:41:47 +0000
Subject: Fix potential handle reuse in Mojo
(cherry picked from commit 76eca90d0e9c09bfbb8c3e8999f36e6da6842a39)
(cherry picked from commit e1432faf5e101b3a516037a26818c03c759d2fdd)
Fixed: 1270333
Change-Id: Ife188d519092e4e634355fd53d97c85009771b76
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3414063
Auto-Submit: Ken Rockot <rockot@google.com>
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Cr-Original-Original-Commit-Position: refs/heads/main@{#962946}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3421488
Commit-Queue: Ken Rockot <rockot@google.com>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Original-Commit-Position: refs/branch-heads/4844@{#87}
Cr-Original-Branched-From: 007241ce2e6c8e5a7b306cc36c730cd07cd38825-refs/heads/main@{#961656}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3427544
Reviewed-by: Jana Grill <janagrill@google.com>
Owners-Override: Jana Grill <janagrill@google.com>
Commit-Queue: Zakhar Voit <voit@google.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1455}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/mojo/core/handle_table.cc b/mojo/core/handle_table.cc
index 9426281d73f050598bd5f88b38aac39c4b994ff3..a044f1c8e38f0affe269a87a10c70b49fe6d353c 100644
--- a/mojo/core/handle_table.cc
+++ b/mojo/core/handle_table.cc
@@ -65,13 +65,19 @@ bool HandleTable::AddDispatchersFromTransit(
const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
MojoHandle* handles) {
// Oops, we're out of handles.
- if (next_available_handle_ == MOJO_HANDLE_INVALID)
+ if (next_available_handle_ == MOJO_HANDLE_INVALID) {
return false;
+ }
+
+ // MOJO_HANDLE_INVALID is zero.
+ DCHECK_GE(next_available_handle_, 1u);
- DCHECK_LE(dispatchers.size(), std::numeric_limits<uint32_t>::max());
// If this insertion would cause handle overflow, we're out of handles.
- if (next_available_handle_ + dispatchers.size() < next_available_handle_)
+ const uint32_t num_handles_available =
+ std::numeric_limits<uint32_t>::max() - next_available_handle_ + 1;
+ if (num_handles_available < dispatchers.size()) {
return false;
+ }
for (size_t i = 0; i < dispatchers.size(); ++i) {
MojoHandle handle = MOJO_HANDLE_INVALID;

View File

@@ -0,0 +1,245 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Adam Rice <ricea@chromium.org>
Date: Sat, 6 Nov 2021 18:52:26 +0000
Subject: Return undefined from UnderlyingSinkBase "type" getter
The "type" attribute of an object passed to the WritableStream
constructor is supposed to return undefined. Add a getter to
UnderlyingSinkBase to ensure it always does.
Add tests to verify that "type" is not inherited from
Object.prototype.type.
Move some methods out-of-line into a new underlying_sink_base.cc file.
Make WritableStreamDefaultController::From() more robust.
BUG=1262791
(cherry picked from commit 26564c88bc9e034cc512afd857cf303193647b9a)
Change-Id: I97f43233eef0e473fb1a22a3ea8afafe92e16266
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3252171
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#936834}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3266824
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4664@{#806}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/third_party/blink/renderer/core/streams/build.gni b/third_party/blink/renderer/core/streams/build.gni
index 57a106353bd6720bc7da88f96dce66e4332aea2a..744d47f1a1e9352cc4df56ce89635b3d6f8b5425 100644
--- a/third_party/blink/renderer/core/streams/build.gni
+++ b/third_party/blink/renderer/core/streams/build.gni
@@ -43,6 +43,7 @@ blink_core_sources_streams = [
"transform_stream_default_controller.cc",
"transform_stream_default_controller.h",
"transform_stream_transformer.h",
+ "underlying_sink_base.cc",
"underlying_sink_base.h",
"underlying_source_base.cc",
"underlying_source_base.h",
diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.cc b/third_party/blink/renderer/core/streams/underlying_sink_base.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a10d4f1865fc4e11c90f463b64ff666cce0fba69
--- /dev/null
+++ b/third_party/blink/renderer/core/streams/underlying_sink_base.cc
@@ -0,0 +1,29 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/streams/underlying_sink_base.h"
+
+#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
+#include "v8/include/v8.h"
+
+namespace blink {
+
+ScriptPromise UnderlyingSinkBase::start(ScriptState* script_state,
+ ScriptValue controller,
+ ExceptionState& exception_state) {
+ controller_ = WritableStreamDefaultController::From(script_state, controller);
+ return start(script_state, controller_, exception_state);
+}
+
+ScriptValue UnderlyingSinkBase::type(ScriptState* script_state) const {
+ auto* isolate = script_state->GetIsolate();
+ return ScriptValue(isolate, v8::Undefined(isolate));
+}
+
+void UnderlyingSinkBase::Trace(Visitor* visitor) const {
+ visitor->Trace(controller_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.h b/third_party/blink/renderer/core/streams/underlying_sink_base.h
index 3b07d87f064a26e01c4ee827d78fca005049c90a..07ba729fc3a78cf2102e2d64e527048af8be9c71 100644
--- a/third_party/blink/renderer/core/streams/underlying_sink_base.h
+++ b/third_party/blink/renderer/core/streams/underlying_sink_base.h
@@ -6,16 +6,20 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_UNDERLYING_SINK_BASE_H_
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/visitor.h"
+// Various files depend on us exporting this header.
+// TODO(ricea): Clean up the dependencies and remove this include.
+#include "third_party/blink/renderer/core/streams/writable_stream_default_controller.h"
+
namespace blink {
class ExceptionState;
-class ScriptValue;
class ScriptState;
+class WritableStreamDefaultController;
class CORE_EXPORT UnderlyingSinkBase : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
@@ -38,12 +42,8 @@ class CORE_EXPORT UnderlyingSinkBase : public ScriptWrappable {
ScriptValue reason,
ExceptionState&) = 0;
- ScriptPromise start(ScriptState* script_state,
- ScriptValue controller,
- ExceptionState& exception_state) {
- controller_ = WritableStreamDefaultController::From(controller);
- return start(script_state, controller_, exception_state);
- }
+ ScriptPromise start(ScriptState*, ScriptValue controller, ExceptionState&);
+
ScriptPromise write(ScriptState* script_state,
ScriptValue chunk,
ScriptValue controller,
@@ -52,10 +52,11 @@ class CORE_EXPORT UnderlyingSinkBase : public ScriptWrappable {
return write(script_state, chunk, controller_, exception_state);
}
- void Trace(Visitor* visitor) const override {
- visitor->Trace(controller_);
- ScriptWrappable::Trace(visitor);
- }
+ // Returns a JavaScript "undefined" value. This is required by the
+ // WritableStream Create() method.
+ ScriptValue type(ScriptState*) const;
+
+ void Trace(Visitor*) const override;
protected:
WritableStreamDefaultController* Controller() const { return controller_; }
diff --git a/third_party/blink/renderer/core/streams/underlying_sink_base.idl b/third_party/blink/renderer/core/streams/underlying_sink_base.idl
index 8351141cbc07ed32566a0006f998aab61e8fd6b5..470eb527b11e3dce355d724eaa63ec981b7788e4 100644
--- a/third_party/blink/renderer/core/streams/underlying_sink_base.idl
+++ b/third_party/blink/renderer/core/streams/underlying_sink_base.idl
@@ -14,4 +14,7 @@ interface UnderlyingSinkBase {
[CallWith=ScriptState, RaisesException] Promise<void> write(any chunk, any controller);
[CallWith=ScriptState, RaisesException] Promise<void> close();
[CallWith=ScriptState, RaisesException] Promise<void> abort(any reason);
+
+ // This only exists to prevent Object.prototype.type being accessed.
+ [CallWith=ScriptState] readonly attribute any type;
};
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
index 0b22eedcddc87b0ac695389a76ed5e353dd5f92c..bc959b6c33dbba6a367b4d247d56b67698299635 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.cc
@@ -20,10 +20,14 @@
namespace blink {
WritableStreamDefaultController* WritableStreamDefaultController::From(
+ ScriptState* script_state,
ScriptValue controller) {
- DCHECK(controller.IsObject());
- return V8WritableStreamDefaultController::ToImpl(
- controller.V8Value().As<v8::Object>());
+ CHECK(controller.IsObject());
+ auto* controller_impl =
+ V8WritableStreamDefaultController::ToImplWithTypeCheck(
+ script_state->GetIsolate(), controller.V8Value().As<v8::Object>());
+ CHECK(controller_impl);
+ return controller_impl;
}
// Only used internally. Not reachable from JavaScript.
diff --git a/third_party/blink/renderer/core/streams/writable_stream_default_controller.h b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
index 3351dcd6941360fc9fecaa8c03080da813a5b6a2..8be676421763caa911b8d003c869856675e28713 100644
--- a/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
+++ b/third_party/blink/renderer/core/streams/writable_stream_default_controller.h
@@ -27,7 +27,7 @@ class CORE_EXPORT WritableStreamDefaultController final
DEFINE_WRAPPERTYPEINFO();
public:
- static WritableStreamDefaultController* From(ScriptValue);
+ static WritableStreamDefaultController* From(ScriptState*, ScriptValue);
// The JavaScript-exposed constructor throws automatically as no constructor
// is specified in the IDL. This constructor is used internally during
diff --git a/third_party/blink/web_tests/http/tests/streams/chromium/underlying-sink-base-type-getter.html b/third_party/blink/web_tests/http/tests/streams/chromium/underlying-sink-base-type-getter.html
new file mode 100644
index 0000000000000000000000000000000000000000..fbbc26b08ea4e310ed99b7a02e1a7952e8f60921
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/streams/chromium/underlying-sink-base-type-getter.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+test(t => {
+ Object.defineProperty(Object.prototype, 'type',
+ {
+ configurable: true,
+ get() {
+ throw Error();
+ }
+ });
+ t.add_cleanup(() => {
+ delete Object.prototype.type;
+ });
+ const generator = new MediaStreamTrackGenerator('video');
+ // The WritableStream is created lazily, so access it to trigger creation.
+ generator.writable.getWriter();
+}, 'a throwing getter on Object.prototype.type should not interfere with ' +
+ 'native writable stream creation');
+
+test(t => {
+ Object.defineProperty(Object.prototype, 'type',
+ {
+ configurable: true,
+ get() {
+ this.start(0x414141);
+ }
+ });
+ t.add_cleanup(() => {
+ delete Object.prototype.type;
+ });
+ const generator = new MediaStreamTrackGenerator('video');
+ generator.writable.getWriter();
+}, 'a getter that calls start() with a number on Object.prototype.type ' +
+ 'should not interfere with native writable stream creation');
+
+test(t => {
+ Object.defineProperty(Object.prototype, 'type',
+ {
+ configurable: true,
+ get() {
+ this.start({});
+ }
+ });
+ t.add_cleanup(() => {
+ delete Object.prototype.type;
+ });
+ const generator = new MediaStreamTrackGenerator('video');
+ generator.writable.getWriter();
+}, 'a getter that calls start() with an object on Object.prototype.type ' +
+ 'should not interfere with native writable stream creation');
+
+</script>

View File

@@ -0,0 +1,195 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ravjit <ravjit@chromium.org>
Date: Thu, 16 Sep 2021 12:29:55 +0000
Subject: Show the origin of the last redirecting server in external protocol
handler dialogs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
External protocol handlers always show the initiating url's origin. This can be misleading if there are server side redirects.
Now we will show the origin of the last redirecting server (falling back to the request_initiator if there were no redirects / if the request goes straight to an external protocol).
Bug: 1197889
Change-Id: I3cf7ccf3a8bd79d161364680a1871d1c88bec813
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3113931
Commit-Queue: Ravjit Singh Uppal <ravjit@chromium.org>
Reviewed-by: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Collin Baker <collinbaker@chromium.org>
Reviewed-by: Takashi Toyoshima <toyoshim@chromium.org>
Reviewed-by: Łukasz Anforowicz <lukasza@chromium.org>
Cr-Commit-Position: refs/heads/main@{#922096}
diff --git a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
index 7e953fe89ff8dadf4da9578c0fdc6c3aada11aca..5c7e331ea4fbbcf36ac6463b37884cc9c6ca7e41 100644
--- a/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog_browsertest.cc
@@ -14,11 +14,15 @@
#include "chrome/browser/ui/test/test_browser_dialog.h"
#include "chrome/browser/ui/views/external_protocol_dialog.h"
#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
#include "ui/views/controls/button/checkbox.h"
#include "url/gurl.h"
@@ -41,6 +45,33 @@ class ExternalProtocolDialogTestApi {
} // namespace test
+namespace {
+constexpr char kInitiatingOrigin[] = "a.test";
+constexpr char kRedirectingOrigin[] = "b.test";
+
+class FakeDefaultProtocolClientWorker
+ : public shell_integration::DefaultProtocolClientWorker {
+ public:
+ explicit FakeDefaultProtocolClientWorker(const std::string& protocol)
+ : DefaultProtocolClientWorker(protocol) {}
+ FakeDefaultProtocolClientWorker(const FakeDefaultProtocolClientWorker&) =
+ delete;
+ FakeDefaultProtocolClientWorker& operator=(
+ const FakeDefaultProtocolClientWorker&) = delete;
+
+ private:
+ ~FakeDefaultProtocolClientWorker() override = default;
+ shell_integration::DefaultWebClientState CheckIsDefaultImpl() override {
+ return shell_integration::DefaultWebClientState::NOT_DEFAULT;
+ }
+
+ void SetAsDefaultImpl(base::OnceClosure on_finished_callback) override {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, std::move(on_finished_callback));
+ }
+};
+} // namespace
+
class ExternalProtocolDialogBrowserTest
: public DialogBrowserTest,
public ExternalProtocolHandler::Delegate {
@@ -71,11 +102,11 @@ class ExternalProtocolDialogBrowserTest
// ExternalProtocolHander::Delegate:
scoped_refptr<shell_integration::DefaultProtocolClientWorker>
CreateShellWorker(const std::string& protocol) override {
- return nullptr;
+ return base::MakeRefCounted<FakeDefaultProtocolClientWorker>(protocol);
}
ExternalProtocolHandler::BlockState GetBlockState(const std::string& scheme,
Profile* profile) override {
- return ExternalProtocolHandler::DONT_BLOCK;
+ return ExternalProtocolHandler::UNKNOWN;
}
void BlockRequest() override {}
void RunExternalProtocolDialog(
@@ -83,7 +114,10 @@ class ExternalProtocolDialogBrowserTest
content::WebContents* web_contents,
ui::PageTransition page_transition,
bool has_user_gesture,
- const absl::optional<url::Origin>& initiating_origin) override {}
+ const absl::optional<url::Origin>& initiating_origin) override {
+ url_did_launch_ = true;
+ launch_url_ = initiating_origin->host();
+ }
void LaunchUrlWithoutSecurityCheck(
const GURL& url,
content::WebContents* web_contents) override {
@@ -98,6 +132,12 @@ class ExternalProtocolDialogBrowserTest
blocked_state_ = state;
}
+ void SetUpOnMainThread() override {
+ DialogBrowserTest::SetUpOnMainThread();
+ host_resolver()->AddRule(kInitiatingOrigin, "127.0.0.1");
+ host_resolver()->AddRule(kRedirectingOrigin, "127.0.0.1");
+ }
+
base::HistogramTester histogram_tester_;
protected:
@@ -106,6 +146,7 @@ class ExternalProtocolDialogBrowserTest
url::Origin blocked_origin_;
BlockState blocked_state_ = BlockState::UNKNOWN;
bool url_did_launch_ = false;
+ std::string launch_url_;
private:
DISALLOW_COPY_AND_ASSIGN(ExternalProtocolDialogBrowserTest);
@@ -231,3 +272,21 @@ IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, TestFocus) {
const views::View* focused_view = focus_manager->GetFocusedView();
EXPECT_TRUE(focused_view);
}
+
+IN_PROC_BROWSER_TEST_F(ExternalProtocolDialogBrowserTest, OriginNameTest) {
+ ASSERT_TRUE(embedded_test_server()->Start());
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ EXPECT_TRUE(ui_test_utils::NavigateToURL(
+ browser(), embedded_test_server()->GetURL("a.test", "/empty.html")));
+ EXPECT_TRUE(content::ExecJs(
+ web_contents,
+ content::JsReplace("location.href = $1",
+ embedded_test_server()->GetURL(
+ "b.test", "/server-redirect?ms-calc:"))));
+ content::WaitForLoadStop(web_contents);
+ EXPECT_TRUE(url_did_launch_);
+ // The url should be the url of the last redirecting server and not of the
+ // request initiator
+ EXPECT_EQ(launch_url_, "b.test");
+}
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 4d0c1a27449d5f88a4a88c915a3d741df42d4613..8174e746f76337716cdcbf6eba4fd54cacb12a0a 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -621,6 +621,13 @@ NavigationURLLoaderImpl::PrepareForNonInterceptedRequest(
if (known_schemes_.find(resource_request_->url.scheme()) ==
known_schemes_.end()) {
mojo::PendingRemote<network::mojom::URLLoaderFactory> loader_factory;
+ absl::optional<url::Origin> initiating_origin;
+ if (url_chain_.size() > 1) {
+ initiating_origin =
+ url::Origin::Create(url_chain_[url_chain_.size() - 2]);
+ } else {
+ initiating_origin = resource_request_->request_initiator;
+ }
bool handled = GetContentClient()->browser()->HandleExternalProtocol(
resource_request_->url, web_contents_getter_,
ChildProcessHost::kInvalidUniqueID, frame_tree_node_id_,
@@ -628,8 +635,8 @@ NavigationURLLoaderImpl::PrepareForNonInterceptedRequest(
resource_request_->resource_type ==
static_cast<int>(blink::mojom::ResourceType::kMainFrame),
static_cast<ui::PageTransition>(resource_request_->transition_type),
- resource_request_->has_user_gesture,
- resource_request_->request_initiator, &loader_factory);
+ resource_request_->has_user_gesture, initiating_origin,
+ &loader_factory);
if (loader_factory) {
factory = base::MakeRefCounted<network::WrapperSharedURLLoaderFactory>(
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index e07f51020fc2139a9757b8d52bd5f5a002e1c561..db802c5a3354e10567f3ab559168965add3cd59a 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -1754,10 +1754,12 @@ class CONTENT_EXPORT ContentBrowserClient {
// Otherwise child_id will be the process id and |navigation_ui_data| will be
// nullptr.
//
- // |initiating_origin| is the origin that initiated the navigation to the
- // external protocol, and may be null, e.g. in the case of browser-initiated
- // navigations. The initiating origin is intended to help users make security
- // decisions about whether to allow an external application to launch.
+ // |initiating_origin| is the origin of the last redirecting server (falling
+ // back to the request initiator if there were no redirects / if the request
+ // goes straight to an external protocol, or null, e.g. in the case of
+ // browser-initiated navigations. The initiating origin is intended to help
+ // users make security decisions about whether to allow an external
+ // application to launch.
virtual bool HandleExternalProtocol(
const GURL& url,
base::RepeatingCallback<WebContents*()> web_contents_getter,

View File

@@ -0,0 +1,138 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Dave Tapuska <dtapuska@chromium.org>
Date: Tue, 8 Feb 2022 15:58:40 +0000
Subject: Cleanup PausablecriptExecutor usage.
Improve performance of API so we don't have to go from
WTF::String->WebString->WTF::String for execution.
Ensure the Executor is traced via the PausableScriptExecutor.
BUG=1289384
(cherry picked from commit c8231f9a89460fd8336e6c0d8e10347f52f540ec)
Change-Id: If9badab91222c49c08a983c60132ce71b183e951
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3407654
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Dave Tapuska <dtapuska@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#963010}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3443262
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4758@{#1109}
Cr-Branched-From: 4a2cf4baf90326df19c3ee70ff987960d59a386e-refs/heads/main@{#950365}
diff --git a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
index 08af6a3d5d457afa9f5ac4815f64cce1e520c9a4..8daa90b37b50f916a6ad82cefb81891acb9c4bdc 100644
--- a/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
+++ b/third_party/blink/renderer/core/frame/local_frame_mojo_handler.cc
@@ -210,15 +210,16 @@ v8::MaybeLocal<v8::Value> CallMethodOnFrame(LocalFrame* local_frame,
// A wrapper class used as the callback for JavaScript executed
// in an isolated world.
-class JavaScriptIsolatedWorldRequest
- : public GarbageCollected<JavaScriptIsolatedWorldRequest>,
- public WebScriptExecutionCallback {
+class JavaScriptIsolatedWorldRequest : public PausableScriptExecutor::Executor,
+ public WebScriptExecutionCallback {
using JavaScriptExecuteRequestInIsolatedWorldCallback =
mojom::blink::LocalFrame::JavaScriptExecuteRequestInIsolatedWorldCallback;
public:
JavaScriptIsolatedWorldRequest(
LocalFrame* local_frame,
+ int32_t world_id,
+ const String& script,
bool wants_result,
mojom::blink::LocalFrame::JavaScriptExecuteRequestInIsolatedWorldCallback
callback);
@@ -228,27 +229,53 @@ class JavaScriptIsolatedWorldRequest
const JavaScriptIsolatedWorldRequest&) = delete;
~JavaScriptIsolatedWorldRequest() override;
- // WebScriptExecutionCallback:
- void Completed(const WebVector<v8::Local<v8::Value>>& result) override;
+ // PausableScriptExecutor::Executor overrides.
+ Vector<v8::Local<v8::Value>> Execute(LocalDOMWindow*) override;
+
+ void Trace(Visitor* visitor) const override;
- void Trace(Visitor* visitor) const { visitor->Trace(local_frame_); }
+ // WebScriptExecutionCallback overrides.
+ void Completed(const WebVector<v8::Local<v8::Value>>& result) override;
private:
Member<LocalFrame> local_frame_;
+ int32_t world_id_;
+ String script_;
bool wants_result_;
JavaScriptExecuteRequestInIsolatedWorldCallback callback_;
};
JavaScriptIsolatedWorldRequest::JavaScriptIsolatedWorldRequest(
LocalFrame* local_frame,
+ int32_t world_id,
+ const String& script,
bool wants_result,
JavaScriptExecuteRequestInIsolatedWorldCallback callback)
: local_frame_(local_frame),
+ world_id_(world_id),
+ script_(script),
wants_result_(wants_result),
- callback_(std::move(callback)) {}
+ callback_(std::move(callback)) {
+ DCHECK_GT(world_id, DOMWrapperWorld::kMainWorldId);
+}
JavaScriptIsolatedWorldRequest::~JavaScriptIsolatedWorldRequest() = default;
+void JavaScriptIsolatedWorldRequest::Trace(Visitor* visitor) const {
+ PausableScriptExecutor::Executor::Trace(visitor);
+ visitor->Trace(local_frame_);
+}
+
+Vector<v8::Local<v8::Value>> JavaScriptIsolatedWorldRequest::Execute(
+ LocalDOMWindow* window) {
+ // Note: An error event in an isolated world will never be dispatched to
+ // a foreign world.
+ ClassicScript* classic_script = ClassicScript::CreateUnspecifiedScript(
+ script_, SanitizeScriptErrors::kDoNotSanitize);
+ return {classic_script->RunScriptInIsolatedWorldAndReturnValue(window,
+ world_id_)};
+}
+
void JavaScriptIsolatedWorldRequest::Completed(
const WebVector<v8::Local<v8::Value>>& result) {
base::Value value;
@@ -268,7 +295,6 @@ void JavaScriptIsolatedWorldRequest::Completed(
if (new_value)
value = base::Value::FromUniquePtrValue(std::move(new_value));
}
-
std::move(callback_).Run(std::move(value));
}
@@ -849,13 +875,16 @@ void LocalFrameMojoHandler::JavaScriptExecuteRequestInIsolatedWorld(
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
scoped_refptr<DOMWrapperWorld> isolated_world =
DOMWrapperWorld::EnsureIsolatedWorld(ToIsolate(frame_), world_id);
- ScriptSourceCode source_code = ScriptSourceCode(javascript);
- HeapVector<ScriptSourceCode> sources;
- sources.Append(&source_code, 1);
- auto* executor = MakeGarbageCollected<PausableScriptExecutor>(
- DomWindow(), std::move(isolated_world), sources, false /* user_gesture */,
+
+ // This member will be traced as the |executor| on the PausableScriptExector.
+ auto* execution_request =
MakeGarbageCollected<JavaScriptIsolatedWorldRequest>(
- frame_, wants_result, std::move(callback)));
+ frame_, world_id, javascript, wants_result, std::move(callback));
+
+ auto* executor = MakeGarbageCollected<PausableScriptExecutor>(
+ DomWindow(), ToScriptState(frame_, *isolated_world),
+ /*callback=*/execution_request,
+ /*executor=*/execution_request);
executor->Run();
}

View File

@@ -59,45 +59,42 @@ index 9aec54a3263d24491d24013a80b719dfc834ecd4..001a6cb2a5eb701351fa924109b43fab
// true if register successfully, or false if 1) the specificied |accelerator|
// has been registered by another caller or other native applications, or
diff --git a/content/browser/media/media_keys_listener_manager_impl.cc b/content/browser/media/media_keys_listener_manager_impl.cc
index 5938f75742b793868638e693a9a8c8dc686dfc46..1263d679a5174beb960265989c370dd4a58ae7b4 100644
index 5938f75742b793868638e693a9a8c8dc686dfc46..afeca1ede732543c4769fe47e5b41a6444a3bf6f 100644
--- a/content/browser/media/media_keys_listener_manager_impl.cc
+++ b/content/browser/media/media_keys_listener_manager_impl.cc
@@ -231,18 +231,24 @@ void MediaKeysListenerManagerImpl::StartListeningForMediaKeysIfNecessary() {
media::AudioManager::GetGlobalAppName());
@@ -232,18 +232,26 @@ void MediaKeysListenerManagerImpl::StartListeningForMediaKeysIfNecessary() {
#endif
- if (system_media_controls_) {
- system_media_controls_->AddObserver(this);
- system_media_controls_notifier_ =
- std::make_unique<SystemMediaControlsNotifier>(
- system_media_controls_.get());
if (system_media_controls_) {
+ // This is required for proper functioning of MediaMetadata.
system_media_controls_->AddObserver(this);
system_media_controls_notifier_ =
std::make_unique<SystemMediaControlsNotifier>(
system_media_controls_.get());
- } else {
- // If we can't access system media controls, then directly listen for media
- // key keypresses instead.
+ // This is required for proper functioning of MediaMetadata.
+ system_media_controls_->AddObserver(this);
+ system_media_controls_notifier_ =
+ std::make_unique<SystemMediaControlsNotifier>(
+ system_media_controls_.get());
+
- media_keys_listener_ = ui::MediaKeysListener::Create(
- this, ui::MediaKeysListener::Scope::kGlobal);
- DCHECK(media_keys_listener_);
}
+ // Directly listen for media key keypresses when using GlobalShortcuts.
+#if defined(OS_MACOS)
+ auto scope = media_key_handling_enabled_ ?
+ ui::MediaKeysListener::Scope::kGlobal :
+ ui::MediaKeysListener::Scope::kGlobalRequiresAccessibility;
media_keys_listener_ = ui::MediaKeysListener::Create(
- this, ui::MediaKeysListener::Scope::kGlobal);
- DCHECK(media_keys_listener_);
- }
+ media_keys_listener_ = ui::MediaKeysListener::Create(
+ this, scope);
+#else
+ media_keys_listener_ = ui::MediaKeysListener::Create(
+ this, ui::MediaKeysListener::Scope::kGlobal);
+#endif
+ DCHECK(media_keys_listener_);
+
EnsureAuxiliaryServices();
}
diff --git a/ui/base/accelerators/media_keys_listener.h b/ui/base/accelerators/media_keys_listener.h
index c2b03328c0e508995bdc135031500783f500ceba..1b6b14dc2999c99445cef6ffc04d49a7c1728a54 100644
--- a/ui/base/accelerators/media_keys_listener.h

View File

@@ -0,0 +1,420 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Marijn Kruisselbrink <mek@chromium.org>
Date: Tue, 16 Nov 2021 22:16:15 +0000
Subject: M96: [FileAPI] Move origin checks in BlobURLStore sooner.
Rather than waiting to verify if a valid origin was passed in until
register/revoke time, check if the origin is valid at the time the
mojo interface is requested. This avoids the need to pass the
delegate on to BlobURLStoreImpl, further decoupling this from
BlobRegistryImpl.
(cherry picked from commit 15cfa2bed3ce9dcdd0a06d3cd3b8330e3591acdc)
Bug: 1262183
Change-Id: I4889685d03501158abfe4f87c647dc468d005f78
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3264353
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#940015}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3285385
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/branch-heads/4664@{#1078}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/chrome/browser/chrome_security_exploit_browsertest.cc b/chrome/browser/chrome_security_exploit_browsertest.cc
index ca2f5cbbaa845d281b44e60ff93e0ba536961d24..8be1504b801e6690d94d7e68fcd4f3b0e43e9862 100644
--- a/chrome/browser/chrome_security_exploit_browsertest.cc
+++ b/chrome/browser/chrome_security_exploit_browsertest.cc
@@ -483,8 +483,8 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityExploitBrowserTestMojoBlobURLs,
// If the process is killed, this test passes.
EXPECT_EQ(
- "Received bad user message: Non committable URL passed to "
- "BlobURLStore::Register",
+ "Received bad user message: "
+ "URL with invalid origin passed to BlobURLStore::Register",
crash_observer.Wait());
}
@@ -526,7 +526,7 @@ IN_PROC_BROWSER_TEST_F(ChromeSecurityExploitBrowserTestMojoBlobURLs,
// If the process is killed, this test passes.
EXPECT_EQ(
- "Received bad user message: Non committable URL passed to "
- "BlobURLStore::Register",
+ "Received bad user message: "
+ "URL with invalid origin passed to BlobURLStore::Register",
crash_observer.Wait());
}
diff --git a/content/browser/blob_storage/blob_url_unittest.cc b/content/browser/blob_storage/blob_url_unittest.cc
index 317ce6c282abc81f472b7c911d9a2eabdb86a1d4..66360f2ab627f85935734320ab6ac402d5fe4bd5 100644
--- a/content/browser/blob_storage/blob_url_unittest.cc
+++ b/content/browser/blob_storage/blob_url_unittest.cc
@@ -184,15 +184,14 @@ class BlobURLTest : public testing::Test {
void TestRequest(const std::string& method,
const net::HttpRequestHeaders& extra_headers) {
- GURL url("blob:blah");
+ auto origin = url::Origin::Create(GURL("https://example.com"));
+ auto url = GURL("blob:" + origin.Serialize() + "/id1");
network::ResourceRequest request;
request.url = url;
request.method = method;
request.headers = extra_headers;
- storage::MockBlobRegistryDelegate delegate;
- storage::BlobURLStoreImpl url_store(blob_url_registry_.AsWeakPtr(),
- &delegate);
+ storage::BlobURLStoreImpl url_store(origin, blob_url_registry_.AsWeakPtr());
mojo::PendingRemote<blink::mojom::Blob> blob_remote;
storage::BlobImpl::Create(
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 5073d38cef7124b7ca1d0b38da2fcdc8683e45fb..eb5cb552c4e5d71cae2958c93d99645ce3d040b2 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -782,7 +782,7 @@ IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTestMojoBlobURLs,
// If the process is killed, this test passes.
EXPECT_EQ(
"Received bad user message: "
- "Non committable URL passed to BlobURLStore::Register",
+ "URL with invalid origin passed to BlobURLStore::Register",
crash_observer.Wait());
}
diff --git a/storage/browser/blob/blob_registry_impl.cc b/storage/browser/blob/blob_registry_impl.cc
index c01eb0635324a171a64c6c13b4ef7288b3f5de45..7c7686309f799f25ce30ec1dc18c75e608829ee2 100644
--- a/storage/browser/blob/blob_registry_impl.cc
+++ b/storage/browser/blob/blob_registry_impl.cc
@@ -634,13 +634,14 @@ void BlobRegistryImpl::GetBlobFromUUID(
void BlobRegistryImpl::URLStoreForOrigin(
const url::Origin& origin,
mojo::PendingAssociatedReceiver<blink::mojom::BlobURLStore> receiver) {
- // TODO(mek): Pass origin on to BlobURLStoreImpl so it can use it to generate
- // Blob URLs, and verify at this point that the renderer can create URLs for
- // that origin.
Delegate* delegate = receivers_.current_context().get();
DCHECK(delegate);
+ if (!origin.opaque() && !delegate->CanCommitURL(origin.GetURL())) {
+ mojo::ReportBadMessage(
+ "Non committable origin passed to BlobRegistryImpl::URLStoreForOrigin");
+ }
auto self_owned_associated_receiver = mojo::MakeSelfOwnedAssociatedReceiver(
- std::make_unique<BlobURLStoreImpl>(url_registry_, delegate),
+ std::make_unique<BlobURLStoreImpl>(origin, url_registry_),
std::move(receiver));
if (g_url_store_creation_hook)
g_url_store_creation_hook->Run(self_owned_associated_receiver);
diff --git a/storage/browser/blob/blob_url_store_impl.cc b/storage/browser/blob/blob_url_store_impl.cc
index b46ee60849c9b758e022d7e576de61b080fd59f5..d4edd988f5982788f5157d27fbfa31abcb1eede7 100644
--- a/storage/browser/blob/blob_url_store_impl.cc
+++ b/storage/browser/blob/blob_url_store_impl.cc
@@ -5,6 +5,7 @@
#include "storage/browser/blob/blob_url_store_impl.h"
#include "base/bind.h"
+#include "base/strings/strcat.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "storage/browser/blob/blob_impl.h"
#include "storage/browser/blob/blob_url_loader_factory.h"
@@ -58,9 +59,9 @@ class BlobURLTokenImpl : public blink::mojom::BlobURLToken {
const base::UnguessableToken token_;
};
-BlobURLStoreImpl::BlobURLStoreImpl(base::WeakPtr<BlobUrlRegistry> registry,
- BlobRegistryImpl::Delegate* delegate)
- : registry_(std::move(registry)), delegate_(delegate) {}
+BlobURLStoreImpl::BlobURLStoreImpl(const url::Origin& origin,
+ base::WeakPtr<BlobUrlRegistry> registry)
+ : origin_(origin), registry_(std::move(registry)) {}
BlobURLStoreImpl::~BlobURLStoreImpl() {
if (registry_) {
@@ -72,20 +73,9 @@ BlobURLStoreImpl::~BlobURLStoreImpl() {
void BlobURLStoreImpl::Register(mojo::PendingRemote<blink::mojom::Blob> blob,
const GURL& url,
RegisterCallback callback) {
- if (!url.SchemeIsBlob()) {
- mojo::ReportBadMessage("Invalid scheme passed to BlobURLStore::Register");
- std::move(callback).Run();
- return;
- }
- if (!delegate_->CanCommitURL(url)) {
- mojo::ReportBadMessage(
- "Non committable URL passed to BlobURLStore::Register");
- std::move(callback).Run();
- return;
- }
- if (BlobUrlUtils::UrlHasFragment(url)) {
- mojo::ReportBadMessage(
- "URL with fragment passed to BlobURLStore::Register");
+ // TODO(mek): Generate blob URLs here, rather than validating the URLs the
+ // renderer process generated.
+ if (!BlobUrlIsValid(url, "Register")) {
std::move(callback).Run();
return;
}
@@ -97,19 +87,8 @@ void BlobURLStoreImpl::Register(mojo::PendingRemote<blink::mojom::Blob> blob,
}
void BlobURLStoreImpl::Revoke(const GURL& url) {
- if (!url.SchemeIsBlob()) {
- mojo::ReportBadMessage("Invalid scheme passed to BlobURLStore::Revoke");
- return;
- }
- if (!delegate_->CanCommitURL(url)) {
- mojo::ReportBadMessage(
- "Non committable URL passed to BlobURLStore::Revoke");
+ if (!BlobUrlIsValid(url, "Revoke"))
return;
- }
- if (BlobUrlUtils::UrlHasFragment(url)) {
- mojo::ReportBadMessage("URL with fragment passed to BlobURLStore::Revoke");
- return;
- }
if (registry_)
registry_->RemoveUrlMapping(url);
@@ -144,4 +123,38 @@ void BlobURLStoreImpl::ResolveForNavigation(
new BlobURLTokenImpl(registry_, url, std::move(blob), std::move(token));
}
+bool BlobURLStoreImpl::BlobUrlIsValid(const GURL& url,
+ const char* method) const {
+ if (!url.SchemeIsBlob()) {
+ mojo::ReportBadMessage(
+ base::StrCat({"Invalid scheme passed to BlobURLStore::", method}));
+ return false;
+ }
+ url::Origin url_origin = url::Origin::Create(url);
+ // For file:// origins blink sometimes creates blob URLs with "null" as origin
+ // and other times "file://" (based on a runtime setting). On the other hand,
+ // `origin_` will always be a non-opaque file: origin for pages loaded from
+ // file:// URLs. To deal with this, we treat file:// origins and
+ // opaque origins separately from non-opaque origins.
+ bool valid_origin = true;
+ if (url_origin.scheme() == url::kFileScheme) {
+ valid_origin = origin_.scheme() == url::kFileScheme;
+ } else if (url_origin.opaque()) {
+ valid_origin = origin_.opaque() || origin_.scheme() == url::kFileScheme;
+ } else {
+ valid_origin = origin_ == url_origin;
+ }
+ if (!valid_origin) {
+ mojo::ReportBadMessage(base::StrCat(
+ {"URL with invalid origin passed to BlobURLStore::", method}));
+ return false;
+ }
+ if (BlobUrlUtils::UrlHasFragment(url)) {
+ mojo::ReportBadMessage(
+ base::StrCat({"URL with fragment passed to BlobURLStore::", method}));
+ return false;
+ }
+ return true;
+}
+
} // namespace storage
diff --git a/storage/browser/blob/blob_url_store_impl.h b/storage/browser/blob/blob_url_store_impl.h
index 6b4a738a4646f8d8e35e8bb1be5aba391e612917..5db371d7c6d50520d8b40a3b4cb6d6bbf920b570 100644
--- a/storage/browser/blob/blob_url_store_impl.h
+++ b/storage/browser/blob/blob_url_store_impl.h
@@ -11,8 +11,9 @@
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
-#include "storage/browser/blob/blob_registry_impl.h"
+#include "storage/browser/blob/blob_url_registry.h"
#include "third_party/blink/public/mojom/blob/blob_url_store.mojom.h"
+#include "url/origin.h"
namespace storage {
@@ -21,8 +22,9 @@ class BlobUrlRegistry;
class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLStoreImpl
: public blink::mojom::BlobURLStore {
public:
- BlobURLStoreImpl(base::WeakPtr<BlobUrlRegistry> registry,
- BlobRegistryImpl::Delegate* delegate);
+ BlobURLStoreImpl(const url::Origin& origin,
+ base::WeakPtr<BlobUrlRegistry> registry);
+
~BlobURLStoreImpl() override;
void Register(mojo::PendingRemote<blink::mojom::Blob> blob,
@@ -39,8 +41,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLStoreImpl
mojo::PendingReceiver<blink::mojom::BlobURLToken> token) override;
private:
+ // Checks if the passed in url is a valid blob url for this blob url store.
+ // Returns false and reports a bad mojo message if not.
+ bool BlobUrlIsValid(const GURL& url, const char* method) const;
+
+ const url::Origin origin_;
base::WeakPtr<BlobUrlRegistry> registry_;
- BlobRegistryImpl::Delegate* delegate_;
std::set<GURL> urls_;
diff --git a/storage/browser/blob/blob_url_store_impl_unittest.cc b/storage/browser/blob/blob_url_store_impl_unittest.cc
index b81232212472036878e0918523be17bb2c2a8b8a..4244890c48240769b1333492bb870420fa26b869 100644
--- a/storage/browser/blob/blob_url_store_impl_unittest.cc
+++ b/storage/browser/blob/blob_url_store_impl_unittest.cc
@@ -18,7 +18,6 @@
#include "storage/browser/blob/blob_impl.h"
#include "storage/browser/blob/blob_storage_context.h"
#include "storage/browser/blob/blob_url_registry.h"
-#include "storage/browser/test/mock_blob_registry_delegate.h"
#include "testing/gtest/include/gtest/gtest.h"
using blink::mojom::BlobURLStore;
@@ -70,9 +69,9 @@ class BlobURLStoreImplTest : public testing::Test {
mojo::PendingRemote<BlobURLStore> CreateURLStore() {
mojo::PendingRemote<BlobURLStore> result;
- mojo::MakeSelfOwnedReceiver(std::make_unique<BlobURLStoreImpl>(
- url_registry_.AsWeakPtr(), &delegate_),
- result.InitWithNewPipeAndPassReceiver());
+ mojo::MakeSelfOwnedReceiver(
+ std::make_unique<BlobURLStoreImpl>(kOrigin, url_registry_.AsWeakPtr()),
+ result.InitWithNewPipeAndPassReceiver());
return result;
}
@@ -102,15 +101,19 @@ class BlobURLStoreImplTest : public testing::Test {
}
const std::string kId = "id";
- const GURL kValidUrl = GURL("blob:id");
+ const url::Origin kOrigin = url::Origin::Create(GURL("https://example.com"));
+ const GURL kValidUrl = GURL("blob:" + kOrigin.Serialize() + "/id1");
+ const GURL kValidUrl2 = GURL("blob:" + kOrigin.Serialize() + "/id2");
const GURL kInvalidUrl = GURL("bolb:id");
- const GURL kFragmentUrl = GURL("blob:id#fragment");
+ const GURL kFragmentUrl = GURL(kValidUrl.spec() + "#fragment");
+ const url::Origin kWrongOrigin =
+ url::Origin::Create(GURL("https://test.com"));
+ const GURL kWrongOriginUrl = GURL("blob:" + kWrongOrigin.Serialize() + "/id");
protected:
base::test::TaskEnvironment task_environment_;
std::unique_ptr<BlobStorageContext> context_;
BlobUrlRegistry url_registry_;
- MockBlobRegistryDelegate delegate_;
std::vector<std::string> bad_messages_;
};
@@ -119,7 +122,7 @@ TEST_F(BlobURLStoreImplTest, BasicRegisterRevoke) {
CreateBlobFromString(kId, "hello world");
// Register a URL and make sure the URL keeps the blob alive.
- BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_);
+ BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr());
RegisterURL(&url_store, std::move(blob), kValidUrl);
blob = url_registry_.GetBlobFromUrl(kValidUrl);
@@ -147,15 +150,13 @@ TEST_F(BlobURLStoreImplTest, RegisterInvalidScheme) {
EXPECT_EQ(1u, bad_messages_.size());
}
-TEST_F(BlobURLStoreImplTest, RegisterCantCommit) {
+TEST_F(BlobURLStoreImplTest, RegisterWrongOrigin) {
mojo::PendingRemote<blink::mojom::Blob> blob =
CreateBlobFromString(kId, "hello world");
- delegate_.can_commit_url_result = false;
-
mojo::Remote<BlobURLStore> url_store(CreateURLStore());
- RegisterURL(url_store.get(), std::move(blob), kValidUrl);
- EXPECT_FALSE(url_registry_.GetBlobFromUrl(kValidUrl));
+ RegisterURL(url_store.get(), std::move(blob), kWrongOriginUrl);
+ EXPECT_FALSE(url_registry_.GetBlobFromUrl(kWrongOriginUrl));
EXPECT_EQ(1u, bad_messages_.size());
}
@@ -170,14 +171,13 @@ TEST_F(BlobURLStoreImplTest, RegisterUrlFragment) {
}
TEST_F(BlobURLStoreImplTest, ImplicitRevoke) {
- const GURL kValidUrl2("blob:id2");
mojo::Remote<blink::mojom::Blob> blob(
CreateBlobFromString(kId, "hello world"));
mojo::PendingRemote<blink::mojom::Blob> blob2;
blob->Clone(blob2.InitWithNewPipeAndPassReceiver());
auto url_store =
- std::make_unique<BlobURLStoreImpl>(url_registry_.AsWeakPtr(), &delegate_);
+ std::make_unique<BlobURLStoreImpl>(kOrigin, url_registry_.AsWeakPtr());
RegisterURL(url_store.get(), blob.Unbind(), kValidUrl);
EXPECT_TRUE(url_registry_.GetBlobFromUrl(kValidUrl));
RegisterURL(url_store.get(), std::move(blob2), kValidUrl2);
@@ -193,8 +193,8 @@ TEST_F(BlobURLStoreImplTest, RevokeThroughDifferentURLStore) {
mojo::PendingRemote<blink::mojom::Blob> blob =
CreateBlobFromString(kId, "hello world");
- BlobURLStoreImpl url_store1(url_registry_.AsWeakPtr(), &delegate_);
- BlobURLStoreImpl url_store2(url_registry_.AsWeakPtr(), &delegate_);
+ BlobURLStoreImpl url_store1(kOrigin, url_registry_.AsWeakPtr());
+ BlobURLStoreImpl url_store2(kOrigin, url_registry_.AsWeakPtr());
RegisterURL(&url_store1, std::move(blob), kValidUrl);
EXPECT_TRUE(url_registry_.GetBlobFromUrl(kValidUrl));
@@ -210,11 +210,9 @@ TEST_F(BlobURLStoreImplTest, RevokeInvalidScheme) {
EXPECT_EQ(1u, bad_messages_.size());
}
-TEST_F(BlobURLStoreImplTest, RevokeCantCommit) {
- delegate_.can_commit_url_result = false;
-
+TEST_F(BlobURLStoreImplTest, RevokeWrongOrigin) {
mojo::Remote<BlobURLStore> url_store(CreateURLStore());
- url_store->Revoke(kValidUrl);
+ url_store->Revoke(kWrongOriginUrl);
url_store.FlushForTesting();
EXPECT_EQ(1u, bad_messages_.size());
}
@@ -230,7 +228,7 @@ TEST_F(BlobURLStoreImplTest, Resolve) {
mojo::PendingRemote<blink::mojom::Blob> blob =
CreateBlobFromString(kId, "hello world");
- BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_);
+ BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr());
RegisterURL(&url_store, std::move(blob), kValidUrl);
blob = ResolveURL(&url_store, kValidUrl);
@@ -245,7 +243,7 @@ TEST_F(BlobURLStoreImplTest, Resolve) {
}
TEST_F(BlobURLStoreImplTest, ResolveNonExistentURL) {
- BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_);
+ BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr());
mojo::PendingRemote<blink::mojom::Blob> blob =
ResolveURL(&url_store, kValidUrl);
@@ -255,7 +253,7 @@ TEST_F(BlobURLStoreImplTest, ResolveNonExistentURL) {
}
TEST_F(BlobURLStoreImplTest, ResolveInvalidURL) {
- BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_);
+ BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr());
mojo::PendingRemote<blink::mojom::Blob> blob =
ResolveURL(&url_store, kInvalidUrl);
@@ -266,7 +264,7 @@ TEST_F(BlobURLStoreImplTest, ResolveAsURLLoaderFactory) {
mojo::PendingRemote<blink::mojom::Blob> blob =
CreateBlobFromString(kId, "hello world");
- BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_);
+ BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr());
RegisterURL(&url_store, std::move(blob), kValidUrl);
mojo::Remote<network::mojom::URLLoaderFactory> factory;
@@ -292,7 +290,7 @@ TEST_F(BlobURLStoreImplTest, ResolveForNavigation) {
mojo::PendingRemote<blink::mojom::Blob> blob =
CreateBlobFromString(kId, "hello world");
- BlobURLStoreImpl url_store(url_registry_.AsWeakPtr(), &delegate_);
+ BlobURLStoreImpl url_store(kOrigin, url_registry_.AsWeakPtr());
RegisterURL(&url_store, std::move(blob), kValidUrl);
mojo::Remote<blink::mojom::BlobURLToken> token_remote;

View File

@@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Austin Sullivan <asully@chromium.org>
Date: Thu, 10 Feb 2022 22:18:54 +0000
Subject: M98: FS: Fix FileUtil lifetime issue
Keeps FileSystemContext alive while while resolving a URL on an open
file system, removing the possibility of the file system being
destroyed while a URL is being resolved on it.
(cherry picked from commit 3fdf2adf11b3c716c9015597d30b59bffc7ac91b)
Bug: 1275622, 1289394
Change-Id: Ic1b97552f9d41a61163d72ff8c605699f673f55f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3373583
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Commit-Queue: Austin Sullivan <asully@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#968470}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3451059
Auto-Submit: Austin Sullivan <asully@chromium.org>
Commit-Queue: Marijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/branch-heads/4758@{#1131}
Cr-Branched-From: 4a2cf4baf90326df19c3ee70ff987960d59a386e-refs/heads/main@{#950365}
diff --git a/storage/browser/file_system/file_system_context.cc b/storage/browser/file_system/file_system_context.cc
index 4ae64d27f5ef446dca59b89b7fa8f652fb949bdc..f88aa4e0b3c0bf6c9cf25dada88d9af960409e7e 100644
--- a/storage/browser/file_system/file_system_context.cc
+++ b/storage/browser/file_system/file_system_context.cc
@@ -418,9 +418,22 @@ void FileSystemContext::OpenFileSystem(const url::Origin& origin,
return;
}
+ // Bind `this` to the callback to ensure this instance stays alive while the
+ // URL is resolving.
backend->ResolveURL(
CreateCrackedFileSystemURL(origin, type, base::FilePath()), mode,
- std::move(callback));
+ base::BindOnce(&FileSystemContext::DidResolveURLOnOpenFileSystem, this,
+ std::move(callback)));
+}
+
+void FileSystemContext::DidResolveURLOnOpenFileSystem(
+ OpenFileSystemCallback callback,
+ const GURL& filesystem_root,
+ const std::string& filesystem_name,
+ base::File::Error error) {
+ DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
+
+ std::move(callback).Run(filesystem_root, filesystem_name, error);
}
void FileSystemContext::ResolveURL(const FileSystemURL& url,
diff --git a/storage/browser/file_system/file_system_context.h b/storage/browser/file_system/file_system_context.h
index 2f9b043f15b78c8e09bb4e6675bb5ef21fdac90c..789cecb8fd69ef39b050c229fd0668b7269f352b 100644
--- a/storage/browser/file_system/file_system_context.h
+++ b/storage/browser/file_system/file_system_context.h
@@ -382,6 +382,11 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
const std::string& filesystem_name,
base::File::Error error);
+ void DidResolveURLOnOpenFileSystem(OpenFileSystemCallback callback,
+ const GURL& filesystem_root,
+ const std::string& filesystem_name,
+ base::File::Error error);
+
// Returns a FileSystemBackend, used only by test code.
SandboxFileSystemBackend* sandbox_backend() const {
return sandbox_backend_.get();

View File

@@ -0,0 +1,157 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Arthur Sonzogni <arthursonzogni@chromium.org>
Date: Wed, 3 Nov 2021 12:49:50 +0000
Subject: sandbox: Fix sandbox inheritance [M96 merge]
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This is a cherry-pick of the following patch:
https://chromium-review.googlesource.com/c/chromium/src/+/3231298
Patch description:
------------------
When creating a new frame and the initial empty document, blink was only
sending the frame's sandbox attribute, but without combining with its owner's
(=document) sandbox flags.
This patch combines frame's attribute with its document sandbox flags.
🎁 Arthur Sonzogni wishes for a better future: 🎁
-------------------------------------------------
There are no good reasons sandbox flags inheritance to be complicated.
See: content/browser/renderer_host/sandbox_flags.md
For legacy reasons, Chrome's developers were confused about what objects
have frame or document semantic. On the browser process, the
FrameTreeNode represents the frame and the RenderFrameHost is almost
(%RenderDocument) the document/execution-context.
Currently, sandbox flags is plumbed inside FramePolicy, and it is not
clear to me whether FramePolicy is a frame-scoped or document-scoped
property (or both).
The current logic speak about "pending" FramePolicy (=frame) and
"active" FramePolicy (=document) and store both type into the
FrameTreeNode and RenderFrameHost, which is not ideal.
I believe we should extract SandboxFlags outside of FramePolicy and
make a very clean implementation, parallel to the PolicyContainer logic.
In a second step it could also be integrated into PolicyContainer, if we
resolve the additional property that sandbox flags can also be further
restricted at the frame level, similar to CSP embedded enforcement.
Bug: 1256822, 1262061
Change-Id: Id38de6d7eeeb1e4fa7722ab56288666763fae838
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3231298
Commit-Queue: Antonio Sartori <antoniosartori@chromium.org>
Auto-Submit: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Antonio Sartori <antoniosartori@chromium.org>
Reviewed-by: Mike West <mkwst@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#933845}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3256558
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Cr-Commit-Position: refs/branch-heads/4664@{#695}
Cr-Branched-From: 24dc4ee75e01a29d390d43c9c264372a169273a7-refs/heads/main@{#929512}
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index 56f159a45c50e6db658ffd783bf01ea4d4e54988..de7d2cfd70fbc02499b1c3a2097f7340c2d01e0b 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -275,6 +275,11 @@ enum BadMessageReason {
MDDH_INVALID_PERMITTED_ORIGIN = 247,
MDDH_NOT_TOP_LEVEL = 248,
RFH_DID_CHANGE_IFRAME_ATTRIBUTE = 249,
+ FARI_LOGOUT_BAD_ENDPOINT = 250,
+ RFH_CHILD_FRAME_UNEXPECTED_OWNER_ELEMENT_TYPE = 251,
+ RFH_POPUP_REQUEST_WHILE_PRERENDERING = 252,
+ RFH_INTERECEPT_DOWNLOAD_WHILE_INACTIVE = 253, // Unused until 97.0.4674.0
+ RFH_CREATE_CHILD_FRAME_SANDBOX_FLAGS = 254,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc
index 7596d071d856b8b41ba8e7101f7fb032e3055334..6cf311deea370119bb1504e7f02c08c6757fa1da 100644
--- a/content/browser/renderer_host/frame_tree_node.cc
+++ b/content/browser/renderer_host/frame_tree_node.cc
@@ -472,6 +472,12 @@ bool FrameTreeNode::HasPendingCrossDocumentNavigation() const {
bool FrameTreeNode::CommitFramePolicy(
const blink::FramePolicy& new_frame_policy) {
+ // Documents create iframes, iframes host new documents. Both are associated
+ // with sandbox flags. They are required to be stricter or equal to their
+ // owner when they change, as we go down.
+ // TODO(https://crbug.com/1262061). Enforce the invariant mentioned above,
+ // once the interactions with FencedIframe has been tested and clarified.
+
bool did_change_flags = new_frame_policy.sandbox_flags !=
replication_state_->frame_policy.sandbox_flags;
bool did_change_container_policy =
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 10f34740cad12975914107a9c07bdbe9279120aa..1077dc1ef688c7dcea8dc85f006eae4560c9115a 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -3506,6 +3506,16 @@ void RenderFrameHostImpl::CreateChildFrame(
return;
}
+ // Documents create iframes, iframes host new documents. Both are associated
+ // with sandbox flags. They are required to be stricter or equal to their
+ // owner when they are created, as we go down.
+ if (frame_policy.sandbox_flags !=
+ (frame_policy.sandbox_flags | active_sandbox_flags())) {
+ bad_message::ReceivedBadMessage(
+ GetProcess(), bad_message::RFH_CREATE_CHILD_FRAME_SANDBOX_FLAGS);
+ return;
+ }
+
// TODO(crbug.com/1145708). The interface exposed to tests should
// match the mojo interface.
OnCreateChildFrame(new_routing_id, std::move(frame_remote),
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
index 1ffff24a749e37552ad771061c9cef68568df784..2be62c3b5ef9f192dd5652e432b81adf71aa067c 100644
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -2113,6 +2113,16 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame(
policy_container_receiver =
policy_container_remote.InitWithNewEndpointAndPassReceiver();
+ FramePolicy frame_policy = owner_element->GetFramePolicy();
+ // Documents create iframes, iframes host new documents. Both are associated
+ // with sandbox flags. They are required to be stricter or equal as we go
+ // down. The iframe owner element only returns the additional restrictions
+ // defined in the HTMLIFrameElement's sanbox attribute. It needs to be
+ // combined with the document's sandbox flags to get the frame's sandbox
+ // policy right.
+ frame_policy.sandbox_flags |=
+ GetFrame()->GetDocument()->GetExecutionContext()->GetSandboxFlags();
+
// FIXME: Using subResourceAttributeName as fallback is not a perfect
// solution. subResourceAttributeName returns just one attribute name. The
// element might not have the attribute, and there might be other attributes
@@ -2122,8 +2132,7 @@ LocalFrame* WebLocalFrameImpl::CreateChildFrame(
scope, name,
owner_element->getAttribute(
owner_element->SubResourceAttributeName()),
- owner_element->GetFramePolicy(), owner_properties,
- owner_element->OwnerType(),
+ std::move(frame_policy), owner_properties, owner_element->OwnerType(),
WebPolicyContainerBindParams{std::move(policy_container_receiver)}));
if (!webframe_child)
return nullptr;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 521f49669eef1ed5fe445618984c3c93fb70d786..8e8bffa245e752f0941e2419da1db0cf365d0f50 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -7589,6 +7589,11 @@ Called by update_bad_message_reasons.py.-->
<int value="247" label="MDDH_INVALID_PERMITTED_ORIGIN"/>
<int value="248" label="MDDH_NOT_TOP_LEVEL"/>
<int value="249" label="RFH_DID_CHANGE_IFRAME_ATTRIBUTE"/>
+ <int value="250" label="FARI_LOGOUT_BAD_ENDPOINT"/>
+ <int value="251" label="RFH_CHILD_FRAME_UNEXPECTED_OWNER_ELEMENT_TYPE"/>
+ <int value="252" label="RFH_POPUP_REQUEST_WHILE_PRERENDERING"/>
+ <int value="253" label="RFH_INTERECEPT_DOWNLOAD_WHILE_INACTIVE"/>
+ <int value="254" label="RFH_CREATE_CHILD_FRAME_SANDBOX_FLAGS"/>
</enum>
<enum name="BadMessageReasonExtensions">

View File

@@ -15,3 +15,7 @@ merged_cppgc_fix_marking_of_ephemerons_with_keys_in_construction.patch
cherry-pick-014e1f857c33.patch
cherry-pick-feef10137b16.patch
cherry-pick-5d2b5e7c006c.patch
merged_allow_compiled_module_invalidation_at_wasmstreaming_finish.patch
version_9_6_180_13_cherry-pick.patch
cherry-pick-418c276ef228.patch
cherry-pick-27bc67f761e6.patch

View File

@@ -0,0 +1,253 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jakob Gruber <jgruber@chromium.org>
Date: Thu, 13 Jan 2022 08:01:37 +0100
Subject: Merged: [maps] Lock map_updater_access in
CompleteInobjectSlackTracking
CompleteInobjectSlackTracking potentially shrinks multiple maps, and
the relation between these maps should be preserved in a concurrent
environment. Thus it is not enough to make each modification
atomically, but all related map modifications must be within a
critical section.
We do this by locking the map_updater_access mutex
CompleteInobjectSlackTracking, and hence moving the function to the
MapUpdater class.
(cherry picked from commit 4b8d04897cba70cac45eea33d78fa2354dfe2bd7)
No-Try: true
No-Presubmit: true
No-Treechecks: true
Bug: chromium:1274445,v8:7990
Change-Id: If99bb8b55e03180128ee397d845fa4c269c4241e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3379819
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#78597}
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3406537
Cr-Commit-Position: refs/branch-heads/9.8@{#16}
Cr-Branched-From: e218afa8473132b56a9e1532be7920dd130aeb7e-refs/heads/9.8.177@{#1}
Cr-Branched-From: 86ebfc969cde382122a4d429f2380f06175ea2a8-refs/heads/main@{#78312}
diff --git a/src/objects/js-function-inl.h b/src/objects/js-function-inl.h
index bae63f6ef9672958914ce4daaf41e948b7b0697d..7fdc6f1b93942df03d3eb61147f2c2e22e4de984 100644
--- a/src/objects/js-function-inl.h
+++ b/src/objects/js-function-inl.h
@@ -15,6 +15,7 @@
#include "src/ic/ic.h"
#include "src/init/bootstrapper.h"
#include "src/objects/feedback-cell-inl.h"
+#include "src/objects/map-updater.h"
#include "src/objects/shared-function-info-inl.h"
// Has to be the last include (doesn't have include guards):
@@ -126,7 +127,7 @@ bool JSFunction::IsInOptimizationQueue() {
void JSFunction::CompleteInobjectSlackTrackingIfActive() {
if (!has_prototype_slot()) return;
if (has_initial_map() && initial_map().IsInobjectSlackTrackingInProgress()) {
- initial_map().CompleteInobjectSlackTracking(GetIsolate());
+ MapUpdater::CompleteInobjectSlackTracking(GetIsolate(), initial_map());
}
}
diff --git a/src/objects/map-inl.h b/src/objects/map-inl.h
index d170341b9a05c7d0ae555713bcd1a671be4642e9..8afafc0a8a5b79e89a65ac286c331afecc5a5568 100644
--- a/src/objects/map-inl.h
+++ b/src/objects/map-inl.h
@@ -12,6 +12,7 @@
#include "src/objects/field-type.h"
#include "src/objects/instance-type-inl.h"
#include "src/objects/js-function-inl.h"
+#include "src/objects/map-updater.h"
#include "src/objects/map.h"
#include "src/objects/objects-inl.h"
#include "src/objects/property.h"
@@ -828,7 +829,7 @@ void Map::InobjectSlackTrackingStep(Isolate* isolate) {
int counter = construction_counter();
set_construction_counter(counter - 1);
if (counter == kSlackTrackingCounterEnd) {
- CompleteInobjectSlackTracking(isolate);
+ MapUpdater::CompleteInobjectSlackTracking(isolate, *this);
}
}
diff --git a/src/objects/map-updater.cc b/src/objects/map-updater.cc
index feb060fa5184e1533895b41989b8e35109036f6a..3ed7fa3af1a7aec18fbe77997a76f1ce01c33ebb 100644
--- a/src/objects/map-updater.cc
+++ b/src/objects/map-updater.cc
@@ -301,21 +301,50 @@ MapUpdater::State MapUpdater::Normalize(const char* reason) {
return state_; // Done.
}
-void MapUpdater::ShrinkInstanceSize(base::SharedMutex* map_updater_access,
- Map map, int slack) {
+// static
+void MapUpdater::CompleteInobjectSlackTracking(Isolate* isolate,
+ Map initial_map) {
+ DisallowGarbageCollection no_gc;
+ // Has to be an initial map.
+ DCHECK(initial_map.GetBackPointer().IsUndefined(isolate));
+
+ const int slack = initial_map.ComputeMinObjectSlack(isolate);
DCHECK_GE(slack, 0);
+
+ TransitionsAccessor transitions(isolate, initial_map, &no_gc);
+ TransitionsAccessor::TraverseCallback callback;
+ if (slack != 0) {
+ // Resize the initial map and all maps in its transition tree.
+ callback = [slack](Map map) {
#ifdef DEBUG
- int old_visitor_id = Map::GetVisitorId(map);
- int new_unused = map.UnusedPropertyFields() - slack;
+ int old_visitor_id = Map::GetVisitorId(map);
+ int new_unused = map.UnusedPropertyFields() - slack;
#endif
+ map.set_instance_size(map.InstanceSizeFromSlack(slack));
+ map.set_construction_counter(Map::kNoSlackTracking);
+ DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
+ DCHECK_EQ(new_unused, map.UnusedPropertyFields());
+ };
+ } else {
+ // Stop slack tracking for this map.
+ callback = [](Map map) {
+ map.set_construction_counter(Map::kNoSlackTracking);
+ };
+ }
{
- base::SharedMutexGuard<base::kExclusive> mutex_guard(map_updater_access);
- map.set_instance_size(map.InstanceSizeFromSlack(slack));
+ // The map_updater_access lock is taken here to guarantee atomicity of all
+ // related map changes (instead of guaranteeing only atomicity of each
+ // single map change). This is needed e.g. by InstancesNeedsRewriting,
+ // which expects certain relations between maps to hold.
+ //
+ // Note: Avoid locking the full_transition_array_access lock inside this
+ // call to TraverseTransitionTree to prevent dependencies between the two
+ // locks.
+ base::SharedMutexGuard<base::kExclusive> mutex_guard(
+ isolate->map_updater_access());
+ transitions.TraverseTransitionTree(callback);
}
- map.set_construction_counter(Map::kNoSlackTracking);
- DCHECK_EQ(old_visitor_id, Map::GetVisitorId(map));
- DCHECK_EQ(new_unused, map.UnusedPropertyFields());
}
MapUpdater::State MapUpdater::TryReconfigureToDataFieldInplace() {
diff --git a/src/objects/map-updater.h b/src/objects/map-updater.h
index c901782bf176600aa08df210d55301045d4b5e2e..2fc66d0c3709b87ea0e7aa96a2943eea4ecefc6e 100644
--- a/src/objects/map-updater.h
+++ b/src/objects/map-updater.h
@@ -80,8 +80,9 @@ class V8_EXPORT_PRIVATE MapUpdater {
Representation new_representation,
Handle<FieldType> new_field_type);
- static void ShrinkInstanceSize(base::SharedMutex* map_updater_access, Map map,
- int slack);
+ // Completes inobject slack tracking for the transition tree starting at the
+ // initial map.
+ static void CompleteInobjectSlackTracking(Isolate* isolate, Map initial_map);
private:
enum State {
diff --git a/src/objects/map.cc b/src/objects/map.cc
index 50d5728b0e13edf4f1052f2014f9e32c4056a512..84b2444ca2d61a8b4300ff30bd6ab2a93448ad60 100644
--- a/src/objects/map.cc
+++ b/src/objects/map.cc
@@ -2200,28 +2200,6 @@ int Map::ComputeMinObjectSlack(Isolate* isolate) {
return slack;
}
-void Map::CompleteInobjectSlackTracking(Isolate* isolate) {
- DisallowGarbageCollection no_gc;
- // Has to be an initial map.
- DCHECK(GetBackPointer().IsUndefined(isolate));
-
- int slack = ComputeMinObjectSlack(isolate);
- TransitionsAccessor transitions(isolate, *this, &no_gc);
- TransitionsAccessor::TraverseCallback callback;
- if (slack != 0) {
- // Resize the initial map and all maps in its transition tree.
- callback = [&](Map map) {
- MapUpdater::ShrinkInstanceSize(isolate->map_updater_access(), map, slack);
- };
- } else {
- callback = [](Map map) {
- // Stop slack tracking for this map.
- map.set_construction_counter(Map::kNoSlackTracking);
- };
- }
- transitions.TraverseTransitionTree(callback);
-}
-
void Map::SetInstanceDescriptors(Isolate* isolate, DescriptorArray descriptors,
int number_of_own_descriptors) {
set_instance_descriptors(descriptors, kReleaseStore);
diff --git a/src/objects/map.h b/src/objects/map.h
index 355d86a332412a3e1c24cdf5ad866cc8871ba4f1..16435e4a3507d93c832e0cd77cf82535d3d51938 100644
--- a/src/objects/map.h
+++ b/src/objects/map.h
@@ -352,10 +352,6 @@ class Map : public HeapObject {
int ComputeMinObjectSlack(Isolate* isolate);
inline int InstanceSizeFromSlack(int slack) const;
- // Completes inobject slack tracking for the transition tree starting at this
- // initial map.
- V8_EXPORT_PRIVATE void CompleteInobjectSlackTracking(Isolate* isolate);
-
// Tells whether the object in the prototype property will be used
// for instances created from this function. If the prototype
// property is set to a value that is not a JSObject, the prototype
diff --git a/src/runtime/runtime-object.cc b/src/runtime/runtime-object.cc
index 42bbb10d92e90640d2a7f61beba758cb752ae87b..add7cd191064686396de76912c5799d9bb3d487b 100644
--- a/src/runtime/runtime-object.cc
+++ b/src/runtime/runtime-object.cc
@@ -1002,7 +1002,7 @@ RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTrackingForMap) {
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0);
- initial_map->CompleteInobjectSlackTracking(isolate);
+ MapUpdater::CompleteInobjectSlackTracking(isolate, *initial_map);
return ReadOnlyRoots(isolate).undefined_value();
}
diff --git a/src/runtime/runtime-test.cc b/src/runtime/runtime-test.cc
index fb5949e2c90966a240ccfb1b61a01017a816f313..6c1df05ca95feb3f40db70f652a55b59450aa6aa 100644
--- a/src/runtime/runtime-test.cc
+++ b/src/runtime/runtime-test.cc
@@ -1274,7 +1274,7 @@ RUNTIME_FUNCTION(Runtime_CompleteInobjectSlackTracking) {
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
- object->map().CompleteInobjectSlackTracking(isolate);
+ MapUpdater::CompleteInobjectSlackTracking(isolate, object->map());
return ReadOnlyRoots(isolate).undefined_value();
}
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 5a12729d929a36fbcc89d0d2586c0cbfee72309c..f6373286cf99176b440db6965e657580321a6380 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -62,6 +62,7 @@
#include "src/objects/js-array-inl.h"
#include "src/objects/js-promise-inl.h"
#include "src/objects/lookup.h"
+#include "src/objects/map-updater.h"
#include "src/objects/module-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/string-inl.h"
@@ -2972,9 +2973,9 @@ TEST(InternalFieldsSubclassing) {
CHECK_LE(i_value->map().GetInObjectProperties(), kMaxNofProperties);
}
- // Make Sure we get the precise property count.
- i_value->map().FindRootMap(i_isolate).CompleteInobjectSlackTracking(
- i_isolate);
+ // Make sure we get the precise property count.
+ i::MapUpdater::CompleteInobjectSlackTracking(
+ i_isolate, i_value->map().FindRootMap(i_isolate));
// TODO(cbruni): fix accounting to make this condition true.
// CHECK_EQ(0, i_value->map()->UnusedPropertyFields());
if (in_object_only) {

View File

@@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leszek Swirski <leszeks@chromium.org>
Date: Fri, 10 Dec 2021 15:56:05 +0100
Subject: Merged: [compiler] Don't elide
ChangeTaggedToInt32->ChangeInt31ToTaggedSigned
(cherry picked from commit 4fae8b16802a416fe3aab0e7792fabe96cf1ecd8)
(cherry picked from commit f4f11c23ae2eaf9bb4525d0fac7ab842de9b0fe2)
Bug: chromium:1278387
No-Try: true
No-Presubmit: true
No-Tree-Checks: true
Change-Id: I9b89834c094510e064988aa534ec230309996034
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3329665
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Original-Commit-Position: refs/branch-heads/9.6@{#40}
Cr-Original-Branched-From: 0b7bda016178bf438f09b3c93da572ae3663a1f7-refs/heads/9.6.180@{#1}
Cr-Original-Branched-From: 41a5a247d9430b953e38631e88d17790306f7a4c-refs/heads/main@{#77244}
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3335759
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Owners-Override: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/branch-heads/9.4@{#56}
Cr-Branched-From: 3b51863bc25492549a8bf96ff67ce481b1a3337b-refs/heads/9.4.146@{#1}
Cr-Branched-From: 2890419fc8fb9bdb507fdd801d76fa7dd9f022b5-refs/heads/master@{#76233}
diff --git a/src/compiler/simplified-operator-reducer.cc b/src/compiler/simplified-operator-reducer.cc
index ea9e9f4ba5dbc89d2f9d700d1a1111b9dda83e15..33edd66b4ff43e4150895bf232d107060876ca08 100644
--- a/src/compiler/simplified-operator-reducer.cc
+++ b/src/compiler/simplified-operator-reducer.cc
@@ -77,7 +77,7 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
case IrOpcode::kChangeInt32ToTagged: {
Int32Matcher m(node->InputAt(0));
if (m.HasResolvedValue()) return ReplaceNumber(m.ResolvedValue());
- if (m.IsChangeTaggedToInt32() || m.IsChangeTaggedSignedToInt32()) {
+ if (m.IsChangeTaggedSignedToInt32()) {
return Replace(m.InputAt(0));
}
break;

View File

@@ -0,0 +1,181 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hiroshige Hayashizaki <hiroshige@chromium.org>
Date: Tue, 23 Nov 2021 22:32:18 +0900
Subject: Merged: Allow compiled module invalidation at WasmStreaming::Finish()
This CL adds `can_use_compiled_module` parameter to
WasmStreaming::Finish() that is used by Chromium
https://chromium-review.googlesource.com/c/chromium/src/+/3282643
to invalidate compiled module bytes after SetCompiledModuleBytes().
(cherry picked from commit b0c6dd86bd563672dba6256f482dc5e145f094ae)
Bug: chromium:1260939
Change-Id: I28554ed79ed56349fa38517ed03785e0c8146b4d
No-Try: true
No-Presubmit: true
No-Tree-Checks: true
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3306788
Commit-Queue: Hiroshige Hayashizaki <hiroshige@chromium.org>
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/branch-heads/9.6@{#36}
Cr-Branched-From: 0b7bda016178bf438f09b3c93da572ae3663a1f7-refs/heads/9.6.180@{#1}
Cr-Branched-From: 41a5a247d9430b953e38631e88d17790306f7a4c-refs/heads/main@{#77244}
diff --git a/include/v8.h b/include/v8.h
index 28ee5e6b673ce8f34d26a322cc83abc959f25c97..f74f1b88c01af72eb4ad6f795c48a028a1904e68 100644
--- a/include/v8.h
+++ b/include/v8.h
@@ -5165,8 +5165,12 @@ class V8_EXPORT WasmStreaming final {
* {Finish} should be called after all received bytes where passed to
* {OnBytesReceived} to tell V8 that there will be no more bytes. {Finish}
* does not have to be called after {Abort} has been called already.
+ * If {can_use_compiled_module} is true and {SetCompiledModuleBytes} was
+ * previously called, the compiled module bytes can be used.
+ * If {can_use_compiled_module} is false, the compiled module bytes previously
+ * set by {SetCompiledModuleBytes} should not be used.
*/
- void Finish();
+ void Finish(bool can_use_compiled_module = true);
/**
* Abort streaming compilation. If {exception} has a value, then the promise
@@ -5181,6 +5185,8 @@ class V8_EXPORT WasmStreaming final {
* can be used, false otherwise. The buffer passed via {bytes} and {size}
* is owned by the caller. If {SetCompiledModuleBytes} returns true, the
* buffer must remain valid until either {Finish} or {Abort} completes.
+ * The compiled module bytes should not be used until {Finish(true)} is
+ * called, because they can be invalidated later by {Finish(false)}.
*/
bool SetCompiledModuleBytes(const uint8_t* bytes, size_t size);
diff --git a/src/api/api.cc b/src/api/api.cc
index cc8a5b2a531de56daa35c6f35739401003be1f95..9b1349308d84b987efee7cca02a7b35fceb355fd 100644
--- a/src/api/api.cc
+++ b/src/api/api.cc
@@ -10074,7 +10074,7 @@ void WasmStreaming::OnBytesReceived(const uint8_t* bytes, size_t size) {
UNREACHABLE();
}
-void WasmStreaming::Finish() { UNREACHABLE(); }
+void WasmStreaming::Finish(bool can_use_compiled_module) { UNREACHABLE(); }
void WasmStreaming::Abort(MaybeLocal<Value> exception) { UNREACHABLE(); }
diff --git a/src/wasm/streaming-decoder.cc b/src/wasm/streaming-decoder.cc
index 22bc7d259a5f9ab84831bfe904fbec683c43e6de..639f4695c4df8012bc92556437e8bcd1a04e64f1 100644
--- a/src/wasm/streaming-decoder.cc
+++ b/src/wasm/streaming-decoder.cc
@@ -35,7 +35,7 @@ class V8_EXPORT_PRIVATE AsyncStreamingDecoder : public StreamingDecoder {
// The buffer passed into OnBytesReceived is owned by the caller.
void OnBytesReceived(base::Vector<const uint8_t> bytes) override;
- void Finish() override;
+ void Finish(bool can_use_compiled_module) override;
void Abort() override;
@@ -258,7 +258,7 @@ size_t AsyncStreamingDecoder::DecodingState::ReadBytes(
return num_bytes;
}
-void AsyncStreamingDecoder::Finish() {
+void AsyncStreamingDecoder::Finish(bool can_use_compiled_module) {
TRACE_STREAMING("Finish\n");
DCHECK(!stream_finished_);
stream_finished_ = true;
@@ -268,9 +268,12 @@ void AsyncStreamingDecoder::Finish() {
base::Vector<const uint8_t> wire_bytes =
base::VectorOf(wire_bytes_for_deserializing_);
// Try to deserialize the module from wire bytes and module bytes.
- if (processor_->Deserialize(compiled_module_bytes_, wire_bytes)) return;
+ if (can_use_compiled_module &&
+ processor_->Deserialize(compiled_module_bytes_, wire_bytes))
+ return;
- // Deserialization failed. Restart decoding using |wire_bytes|.
+ // Compiled module bytes are invalidated by can_use_compiled_module = false
+ // or the deserialization failed. Restart decoding using |wire_bytes|.
compiled_module_bytes_ = {};
DCHECK(!deserializing());
OnBytesReceived(wire_bytes);
diff --git a/src/wasm/streaming-decoder.h b/src/wasm/streaming-decoder.h
index 2c5e1eae3c0a13f1a86c99cfb3a8696732697f36..6f4601b9f47170175703b150007919898199da92 100644
--- a/src/wasm/streaming-decoder.h
+++ b/src/wasm/streaming-decoder.h
@@ -78,7 +78,7 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
// The buffer passed into OnBytesReceived is owned by the caller.
virtual void OnBytesReceived(base::Vector<const uint8_t> bytes) = 0;
- virtual void Finish() = 0;
+ virtual void Finish(bool can_use_compiled_module = true) = 0;
virtual void Abort() = 0;
@@ -96,6 +96,7 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
}
// Passes previously compiled module bytes from the embedder's cache.
+ // The content shouldn't be used until Finish(true) is called.
bool SetCompiledModuleBytes(
base::Vector<const uint8_t> compiled_module_bytes) {
compiled_module_bytes_ = compiled_module_bytes;
@@ -124,6 +125,8 @@ class V8_EXPORT_PRIVATE StreamingDecoder {
std::string url_;
ModuleCompiledCallback module_compiled_callback_;
+ // The content of `compiled_module_bytes_` shouldn't be used until
+ // Finish(true) is called.
base::Vector<const uint8_t> compiled_module_bytes_;
};
diff --git a/src/wasm/sync-streaming-decoder.cc b/src/wasm/sync-streaming-decoder.cc
index 73c22cb5a32655fcb0f53145a03deaa79cb3b4a8..ebe1ead525edccf23d463e3cdfe4be7b3f2100c4 100644
--- a/src/wasm/sync-streaming-decoder.cc
+++ b/src/wasm/sync-streaming-decoder.cc
@@ -32,7 +32,7 @@ class V8_EXPORT_PRIVATE SyncStreamingDecoder : public StreamingDecoder {
buffer_size_ += bytes.size();
}
- void Finish() override {
+ void Finish(bool can_use_compiled_module) override {
// We copy all received chunks into one byte buffer.
auto bytes = std::make_unique<uint8_t[]>(buffer_size_);
uint8_t* destination = bytes.get();
@@ -43,7 +43,7 @@ class V8_EXPORT_PRIVATE SyncStreamingDecoder : public StreamingDecoder {
CHECK_EQ(destination - bytes.get(), buffer_size_);
// Check if we can deserialize the module from cache.
- if (deserializing()) {
+ if (can_use_compiled_module && deserializing()) {
HandleScope scope(isolate_);
SaveAndSwitchContext saved_context(isolate_, *context_);
diff --git a/src/wasm/wasm-js.cc b/src/wasm/wasm-js.cc
index a452e51855db2e7ec335bf56975204c6299020c1..94ba36c1ec875a6a2832fadfcf191c9f9b57b9b6 100644
--- a/src/wasm/wasm-js.cc
+++ b/src/wasm/wasm-js.cc
@@ -57,7 +57,9 @@ class WasmStreaming::WasmStreamingImpl {
void OnBytesReceived(const uint8_t* bytes, size_t size) {
streaming_decoder_->OnBytesReceived(base::VectorOf(bytes, size));
}
- void Finish() { streaming_decoder_->Finish(); }
+ void Finish(bool can_use_compiled_module) {
+ streaming_decoder_->Finish(can_use_compiled_module);
+ }
void Abort(MaybeLocal<Value> exception) {
i::HandleScope scope(reinterpret_cast<i::Isolate*>(isolate_));
@@ -110,9 +112,9 @@ void WasmStreaming::OnBytesReceived(const uint8_t* bytes, size_t size) {
impl_->OnBytesReceived(bytes, size);
}
-void WasmStreaming::Finish() {
+void WasmStreaming::Finish(bool can_use_compiled_module) {
TRACE_EVENT0("v8.wasm", "wasm.FinishStreaming");
- impl_->Finish();
+ impl_->Finish(can_use_compiled_module);
}
void WasmStreaming::Abort(MaybeLocal<Value> exception) {

View File

@@ -0,0 +1,103 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leszek Swirski <leszeks@google.com>
Date: Fri, 19 Nov 2021 12:12:03 +0100
Subject: Version 9.6.180.13 (cherry-pick)
Merged 85ab0ad7789a7188b4c0b2be3cd3d758134c7de6
Reland "[runtime] Reset clobbered argument in DefineClass"
R=ishell@chromium.org
Change-Id: I892729eafe841e57b853f0d0a885e05847efe547
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3289176
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/branch-heads/9.6@{#24}
Cr-Branched-From: 0b7bda016178bf438f09b3c93da572ae3663a1f7-refs/heads/9.6.180@{#1}
Cr-Branched-From: 41a5a247d9430b953e38631e88d17790306f7a4c-refs/heads/main@{#77244}
diff --git a/include/v8-version.h b/include/v8-version.h
index 30a4182357505dcffcba3687964f6cb31942f6c9..52c772822e96104ba6dc75901d8c0eb4e3b46119 100644
--- a/include/v8-version.h
+++ b/include/v8-version.h
@@ -11,7 +11,7 @@
#define V8_MAJOR_VERSION 9
#define V8_MINOR_VERSION 3
#define V8_BUILD_NUMBER 345
-#define V8_PATCH_LEVEL 19
+#define V8_PATCH_LEVEL 20
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/execution/arguments-inl.h b/src/execution/arguments-inl.h
index 0be2325837189d48e3aae36fb611f7fa67041a31..2f69cd7adc4107e3dcc0dc012a3cffb55b9fa05e 100644
--- a/src/execution/arguments-inl.h
+++ b/src/execution/arguments-inl.h
@@ -14,6 +14,15 @@
namespace v8 {
namespace internal {
+template <ArgumentsType T>
+Arguments<T>::ChangeValueScope::ChangeValueScope(Isolate* isolate,
+ Arguments* args, int index,
+ Object value)
+ : location_(args->address_of_arg_at(index)) {
+ old_value_ = handle(Object(*location_), isolate);
+ *location_ = value.ptr();
+}
+
template <ArgumentsType T>
int Arguments<T>::smi_at(int index) const {
return Smi::ToInt(Object(*address_of_arg_at(index)));
diff --git a/src/execution/arguments.h b/src/execution/arguments.h
index 9ba80a401f78be4d90896c3ac3f5c82eaf8ea268..e1cd8d8c5f8af846fc710f8770cb349d49fd7306 100644
--- a/src/execution/arguments.h
+++ b/src/execution/arguments.h
@@ -33,6 +33,18 @@ namespace internal {
template <ArgumentsType arguments_type>
class Arguments {
public:
+ // Scope to temporarily change the value of an argument.
+ class ChangeValueScope {
+ public:
+ inline ChangeValueScope(Isolate* isolate, Arguments* args, int index,
+ Object value);
+ ~ChangeValueScope() { *location_ = old_value_->ptr(); }
+
+ private:
+ Address* location_;
+ Handle<Object> old_value_;
+ };
+
Arguments(int length, Address* arguments)
: length_(length), arguments_(arguments) {
DCHECK_GE(length_, 0);
@@ -51,10 +63,6 @@ class Arguments {
inline double number_at(int index) const;
- inline void set_at(int index, Object value) {
- *address_of_arg_at(index) = value.ptr();
- }
-
inline FullObjectSlot slot_at(int index) const {
return FullObjectSlot(address_of_arg_at(index));
}
diff --git a/src/runtime/runtime-classes.cc b/src/runtime/runtime-classes.cc
index ecdab593b20be7e39251d2a7b1f499b4c6bf84c3..bef5f88dab25754c259eea5d4c7cea9a98988257 100644
--- a/src/runtime/runtime-classes.cc
+++ b/src/runtime/runtime-classes.cc
@@ -619,7 +619,12 @@ MaybeHandle<Object> DefineClass(Isolate* isolate,
Handle<JSObject> prototype = CreateClassPrototype(isolate);
DCHECK_EQ(*constructor, args[ClassBoilerplate::kConstructorArgumentIndex]);
- args.set_at(ClassBoilerplate::kPrototypeArgumentIndex, *prototype);
+ // Temporarily change ClassBoilerplate::kPrototypeArgumentIndex for the
+ // subsequent calls, but use a scope to make sure to change it back before
+ // returning, to not corrupt the caller's argument frame (in particular, for
+ // the interpreter, to not clobber the register frame).
+ RuntimeArguments::ChangeValueScope set_prototype_value_scope(
+ isolate, &args, ClassBoilerplate::kPrototypeArgumentIndex, *prototype);
if (!InitClassConstructor(isolate, class_boilerplate, constructor_parent,
constructor, args) ||

View File

@@ -1,2 +1,3 @@
add_thread_local_to_x_error_trap_cc.patch
merge_to_94_add_direction_indicator_to_transformableframes.patch
merge_to_m96_sdp_reject_large_number_of_channels.patch

View File

@@ -0,0 +1,69 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Philipp Hancke <phancke@nvidia.com>
Date: Thu, 25 Nov 2021 08:57:54 +0100
Subject: sdp: reject large number of channels
the maximum used in practice is multiopus with
6 or 8 channels. 24 is the maximum number of channels
supported in the audio decoder.
BUG=chromium:1265806
(cherry picked from commit d58ac5adf887a2bc96d75b1c0fb6fef17889ac80)
No-Try: True
Change-Id: Iba8e3185a1f235b846fed9c154e66fb3983664ed
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/238980
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@nvidia.com>
Cr-Original-Commit-Position: refs/heads/main@{#35440}
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/239740
Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Cr-Commit-Position: refs/branch-heads/4664@{#3}
Cr-Branched-From: 40abb7d8ff6ebdb8095d372c18949940c5fcecb5-refs/heads/main@{#35164}
diff --git a/pc/webrtc_sdp.cc b/pc/webrtc_sdp.cc
index 379b2f30c2e2dfb8903da958b27af455b5431386..a5e099a70d6a2e93e4da46ebdb42490c2061fab0 100644
--- a/pc/webrtc_sdp.cc
+++ b/pc/webrtc_sdp.cc
@@ -256,6 +256,9 @@ static const char kDefaultSctpmapProtocol[] = "webrtc-datachannel";
// types.
const int kWildcardPayloadType = -1;
+// Maximum number of channels allowed.
+static const size_t kMaxNumberOfChannels = 24;
+
struct SsrcInfo {
uint32_t ssrc_id;
std::string cname;
@@ -3626,6 +3629,10 @@ bool ParseRtpmapAttribute(const std::string& line,
return false;
}
}
+ if (channels > kMaxNumberOfChannels) {
+ return ParseFailed(line, "At most 24 channels are supported.", error);
+ }
+
AudioContentDescription* audio_desc = media_desc->as_audio();
UpdateCodec(payload_type, encoding_name, clock_rate, 0, channels,
audio_desc);
diff --git a/pc/webrtc_sdp_unittest.cc b/pc/webrtc_sdp_unittest.cc
index 266fd3dfd66155dd6f545bd542dd88f80c838cb8..4c8abac0be50253fcc7f84703a2d07ed3ba75a38 100644
--- a/pc/webrtc_sdp_unittest.cc
+++ b/pc/webrtc_sdp_unittest.cc
@@ -4663,3 +4663,15 @@ TEST_F(WebRtcSdpTest, IllegalMidCharacterValue) {
Replace("a=mid:", "a=mid:[]", &sdp);
ExpectParseFailure(std::string(sdp), "a=mid:[]");
}
+
+TEST_F(WebRtcSdpTest, MaxChannels) {
+ std::string sdp =
+ "v=0\r\n"
+ "o=- 11 22 IN IP4 127.0.0.1\r\n"
+ "s=-\r\n"
+ "t=0 0\r\n"
+ "m=audio 49232 RTP/AVP 108\r\n"
+ "a=rtpmap:108 ISAC/16000/512\r\n";
+
+ ExpectParseFailure(sdp, "a=rtpmap:108 ISAC/16000/512");
+}

View File

@@ -72,11 +72,7 @@ async function circleCIcall (targetBranch, job, options) {
console.log(`Triggering CircleCI to run build job: ${job} on branch: ${targetBranch} with release flag.`);
const buildRequest = {
branch: targetBranch,
parameters: {
'run-lint': false,
'run-build-linux': false,
'run-build-mac': false
}
parameters: {}
};
if (options.ghRelease) {
buildRequest.parameters['upload-to-s3'] = '0';
@@ -121,8 +117,9 @@ async function getCircleCIWorkflowId (pipelineId) {
switch (pipelineInfo.state) {
case 'created': {
const workflows = await circleCIRequest(`${pipelineInfoUrl}/workflow`, 'GET');
if (workflows.items.length === 1) {
workflowId = workflows.items[0].id;
// The logic below expects two workflow.items: publish [0] & setup [1]
if (workflows.items.length === 2) {
workflowId = workflows.items.find(item => item.name.includes('publish')).id;
break;
}
console.log('Unxpected number of workflows, response was:', pipelineInfo);

View File

@@ -847,10 +847,10 @@ void BaseWindow::SetVisibleOnAllWorkspaces(bool visible,
gin_helper::Dictionary options;
bool visibleOnFullScreen = false;
bool skipTransformProcessType = false;
args->GetNext(&options) &&
options.Get("visibleOnFullScreen", &visibleOnFullScreen);
args->GetNext(&options) &&
options.Get("skipTransformProcessType", &skipTransformProcessType);
if (args->GetNext(&options)) {
options.Get("visibleOnFullScreen", &visibleOnFullScreen);
options.Get("skipTransformProcessType", &skipTransformProcessType);
}
return window_->SetVisibleOnAllWorkspaces(visible, visibleOnFullScreen,
skipTransformProcessType);
}

View File

@@ -210,7 +210,7 @@ void WebFrameMain::PostMessage(v8::Isolate* isolate,
}
std::vector<gin::Handle<MessagePort>> wrapped_ports;
if (transfer) {
if (transfer && !transfer.value()->IsUndefined()) {
if (!gin::ConvertFromV8(isolate, *transfer, &wrapped_ports)) {
isolate->ThrowException(v8::Exception::Error(
gin::StringToV8(isolate, "Invalid value for transfer")));

View File

@@ -65,8 +65,8 @@ bool GetProtocolLaunchPath(gin::Arguments* args, std::wstring* exe) {
// Read in optional args arg
std::vector<std::wstring> launch_args;
if (args->GetNext(&launch_args) && !launch_args.empty())
*exe = base::StringPrintf(L"\"%ls\" %ls \"%%1\"", exe->c_str(),
base::JoinString(launch_args, L" ").c_str());
*exe = base::StringPrintf(L"\"%ls\" \"%ls\" \"%%1\"", exe->c_str(),
base::JoinString(launch_args, L"\" \"").c_str());
else
*exe = base::StringPrintf(L"\"%ls\" \"%%1\"", exe->c_str());
return true;

View File

@@ -463,7 +463,8 @@ void ElectronBrowserMainParts::WillRunMainMessageLoop(
std::unique_ptr<base::RunLoop>& run_loop) {
js_env_->OnMessageLoopCreated();
exit_code_ = content::RESULT_CODE_NORMAL_EXIT;
Browser::Get()->SetMainMessageLoopQuitClosure(run_loop->QuitClosure());
Browser::Get()->SetMainMessageLoopQuitClosure(
run_loop->QuitWhenIdleClosure());
}
void ElectronBrowserMainParts::PostCreateMainMessageLoop() {

View File

@@ -322,15 +322,14 @@ NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
// Set Window style so that we get a minimize and maximize animation when
// frameless.
DWORD frame_style = WS_CAPTION | WS_OVERLAPPED;
if (resizable_)
if (resizable_ && thick_frame_)
frame_style |= WS_THICKFRAME;
if (minimizable_)
frame_style |= WS_MINIMIZEBOX;
if (maximizable_)
frame_style |= WS_MAXIMIZEBOX;
// We should not show a frame for transparent window.
if (!thick_frame_)
frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
if (!thick_frame_ || !has_frame())
frame_style &= ~WS_CAPTION;
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
}
@@ -589,14 +588,16 @@ void NativeWindowViews::Maximize() {
#endif
void NativeWindowViews::Unmaximize() {
if (IsMaximized()) {
#if defined(OS_WIN)
if (transparent()) {
SetBounds(restore_bounds_, false);
return;
}
if (transparent()) {
SetBounds(restore_bounds_, false);
return;
}
#endif
widget()->Restore();
widget()->Restore();
}
}
bool NativeWindowViews::IsMaximized() {

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 14,2,2,0
PRODUCTVERSION 14,2,2,0
FILEVERSION 14,2,7,0
PRODUCTVERSION 14,2,7,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "14.2.2"
VALUE "FileVersion", "14.2.7"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "14.2.2"
VALUE "ProductVersion", "14.2.7"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -412,9 +412,8 @@ void FileChooserDialog::OnUpdatePreview(GtkFileChooser* chooser) {
} // namespace
void ShowFileDialog(const FileChooserDialog& dialog) {
if (*supports_gtk_file_chooser_native) {
dl_gtk_native_dialog_show(static_cast<void*>(dialog.dialog()));
} else {
// gtk_native_dialog_run() will call gtk_native_dialog_show() for us.
if (!*supports_gtk_file_chooser_native) {
gtk_widget_show_all(GTK_WIDGET(dialog.dialog()));
}
}

View File

@@ -107,8 +107,9 @@ DialogResult ShowTaskDialogWstr(NativeWindow* parent,
// TaskDialogIndirect doesn't allow empty name, if we set empty title it
// will show "electron.exe" in title.
std::wstring app_name;
if (title.empty()) {
std::wstring app_name = base::UTF8ToWide(Browser::Get()->GetName());
app_name = base::UTF8ToWide(Browser::Get()->GetName());
config.pszWindowTitle = app_name.c_str();
} else {
config.pszWindowTitle = title.c_str();

View File

@@ -99,4 +99,21 @@ bool ElectronDesktopWindowTreeHostWin::GetClientAreaInsets(
return false;
}
bool ElectronDesktopWindowTreeHostWin::HandleMouseEvent(ui::MouseEvent* event) {
// Call the default implementation of this method to get the event to its
// proper handler.
bool handled = views::DesktopWindowTreeHostWin::HandleMouseEvent(event);
// On WCO-enabled windows, we need to mark non-client mouse moved events as
// handled so they don't incorrectly propogate back to the OS.
if (native_window_view_->IsWindowControlsOverlayEnabled() &&
event->type() == ui::ET_MOUSE_MOVED &&
(event->flags() & ui::EF_IS_NON_CLIENT) != 0) {
event->SetHandled();
handled = true;
}
return handled;
}
} // namespace electron

View File

@@ -30,6 +30,7 @@ class ElectronDesktopWindowTreeHostWin
bool GetDwmFrameInsetsInPixels(gfx::Insets* insets) const override;
bool GetClientAreaInsets(gfx::Insets* insets,
HMONITOR monitor) const override;
bool HandleMouseEvent(ui::MouseEvent* event) override;
private:
NativeWindowViews* native_window_view_; // weak ref

View File

@@ -21,7 +21,9 @@ WindowStateWatcher::WindowStateWatcher(NativeWindowViews* window)
x11::GetAtom("_NET_WM_STATE_MAXIMIZED_VERT")),
net_wm_state_maximized_horz_atom_(
x11::GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ")),
net_wm_state_fullscreen_atom_(x11::GetAtom("_NET_WM_STATE_FULLSCREEN")) {
net_wm_state_fullscreen_atom_(x11::GetAtom("_NET_WM_STATE_FULLSCREEN")),
was_minimized_(window_->IsMinimized()),
was_maximized_(window_->IsMaximized()) {
ui::X11EventSource::GetInstance()->connection()->AddEventObserver(this);
}
@@ -31,9 +33,6 @@ WindowStateWatcher::~WindowStateWatcher() {
void WindowStateWatcher::OnEvent(const x11::Event& x11_event) {
if (IsWindowStateEvent(x11_event)) {
const bool was_minimized_ = window_->IsMinimized();
const bool was_maximized_ = window_->IsMaximized();
std::vector<x11::Atom> wm_states;
if (GetArrayProperty(
static_cast<x11::Window>(window_->GetAcceleratedWidget()),
@@ -67,6 +66,9 @@ void WindowStateWatcher::OnEvent(const x11::Event& x11_event) {
else
window_->NotifyWindowLeaveFullScreen();
}
was_minimized_ = is_minimized;
was_maximized_ = is_maximized;
}
}
}

View File

@@ -32,6 +32,9 @@ class WindowStateWatcher : public x11::EventObserver {
const x11::Atom net_wm_state_maximized_horz_atom_;
const x11::Atom net_wm_state_fullscreen_atom_;
bool was_minimized_ = false;
bool was_maximized_ = false;
DISALLOW_COPY_AND_ASSIGN(WindowStateWatcher);
};

View File

@@ -81,7 +81,7 @@ void WebViewGuestDelegate::OnZoomLevelChanged(
api_web_contents_->GetZoomController()->SetZoomLevel(level);
}
// Change the default zoom factor to match the embedders' new zoom level.
double zoom_factor = blink::PageZoomFactorToZoomLevel(level);
double zoom_factor = blink::PageZoomLevelToZoomFactor(level);
api_web_contents_->GetZoomController()->SetDefaultZoomFactor(zoom_factor);
}
}

View File

@@ -146,7 +146,7 @@ class IPCRenderer : public gin::Wrappable<IPCRenderer>,
}
std::vector<v8::Local<v8::Object>> transferables;
if (transfer) {
if (transfer && !transfer.value()->IsUndefined()) {
if (!gin::ConvertFromV8(isolate, *transfer, &transferables)) {
thrower.ThrowTypeError("Invalid value for transfer");
return;

View File

@@ -495,6 +495,14 @@ class WebFrameRenderer : public gin::Wrappable<WebFrameRenderer>,
return gin::ConvertToV8(isolate, prefs.context_isolation);
} else if (pref_name == options::kGuestInstanceID) {
// NOTE: guestInstanceId is internal-only.
// FIXME(zcbenz): For child windows opened with window.open('') from
// webview, the WebPreferences is inherited from webview and the value
// of |guest_instance_id| is wrong.
// Please check ElectronRenderFrameObserver::DidInstallConditionalFeatures
// for the background.
auto* web_frame = render_frame->GetWebFrame();
if (web_frame->Opener())
return gin::ConvertToV8(isolate, 0);
return gin::ConvertToV8(isolate, prefs.guest_instance_id);
} else if (pref_name == options::kHiddenPage) {
// NOTE: hiddenPage is internal-only.

View File

@@ -31,6 +31,7 @@
#include "third_party/blink/public/web/web_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" // nogncheck
#include "ui/base/resource/resource_bundle.h"
namespace electron {
@@ -58,12 +59,57 @@ ElectronRenderFrameObserver::ElectronRenderFrameObserver(
}
void ElectronRenderFrameObserver::DidClearWindowObject() {
// Do a delayed Node.js initialization for child window.
// Check DidInstallConditionalFeatures below for the background.
auto* web_frame =
static_cast<blink::WebLocalFrameImpl*>(render_frame_->GetWebFrame());
if (has_delayed_node_initialization_ && web_frame->Opener() &&
web_frame->HasCommittedFirstRealLoad()) {
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::MicrotasksScope microtasks_scope(
isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Handle<v8::Context> context = web_frame->MainWorldScriptContext();
v8::Context::Scope context_scope(context);
// DidClearWindowObject only emits for the main world.
DidInstallConditionalFeatures(context, MAIN_WORLD_ID);
}
renderer_client_->DidClearWindowObject(render_frame_);
}
void ElectronRenderFrameObserver::DidInstallConditionalFeatures(
v8::Handle<v8::Context> context,
int world_id) {
// When a child window is created with window.open, its WebPreferences will
// be copied from its parent, and Chromium will intialize JS context in it
// immediately.
// Normally the WebPreferences is overriden in browser before navigation,
// but this behavior bypasses the browser side navigation and the child
// window will get wrong WebPreferences in the initialization.
// This will end up initializing Node.js in the child window with wrong
// WebPreferences, leads to problem that child window having node integration
// while "nodeIntegration=no" is passed.
// We work around this issue by delaying the child window's initialization of
// Node.js if this is the initial empty document, and only do it when the
// acutal page has started to load.
auto* web_frame =
static_cast<blink::WebLocalFrameImpl*>(render_frame_->GetWebFrame());
if (web_frame->Opener() && !web_frame->HasCommittedFirstRealLoad()) {
// FIXME(zcbenz): Chromium does not do any browser side navigation for
// window.open('about:blank'), so there is no way to override WebPreferences
// of it. We should not delay Node.js initialization as there will be no
// further loadings.
// Please check http://crbug.com/1215096 for updates which may help remove
// this hack.
GURL url = web_frame->GetDocument().Url();
if (!url.IsAboutBlank()) {
has_delayed_node_initialization_ = true;
return;
}
}
has_delayed_node_initialization_ = false;
auto* isolate = context->GetIsolate();
v8::MicrotasksScope microtasks_scope(
isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);

View File

@@ -42,6 +42,7 @@ class ElectronRenderFrameObserver : public content::RenderFrameObserver {
void OnTakeHeapSnapshot(IPC::PlatformFileForTransit file_handle,
const std::string& channel);
bool has_delayed_node_initialization_ = false;
content::RenderFrame* render_frame_;
RendererClientBase* renderer_client_;

View File

@@ -153,6 +153,7 @@ void ElectronRendererClient::WillReleaseScriptContext(
// We also do this if we have disable electron site instance overrides to
// avoid memory leaks
auto prefs = render_frame->GetBlinkPreferences();
gin_helper::MicrotasksScope microtasks_scope(env->isolate());
node::FreeEnvironment(env);
if (env == node_bindings_->uv_env())
node::FreeIsolateData(node_bindings_->isolate_data());

View File

@@ -36,6 +36,8 @@ WebWorkerObserver::WebWorkerObserver()
WebWorkerObserver::~WebWorkerObserver() {
lazy_tls.Pointer()->Set(nullptr);
gin_helper::MicrotasksScope microtasks_scope(
node_bindings_->uv_env()->isolate());
node::FreeEnvironment(node_bindings_->uv_env());
node::FreeIsolateData(node_bindings_->isolate_data());
}

View File

@@ -3417,6 +3417,29 @@ describe('BrowserWindow module', () => {
w.unmaximize();
expectBoundsEqual(w.getPosition(), initialPosition);
});
// TODO(dsanders11): Enable once minimize event works on Linux again.
// See https://github.com/electron/electron/issues/28699
ifit(process.platform !== 'linux')('should not restore a minimized window', async () => {
const w = new BrowserWindow();
const minimize = emittedOnce(w, 'minimize');
w.minimize();
await minimize;
w.unmaximize();
await delay(1000);
expect(w.isMinimized()).to.be.true();
});
it('should not change the size or position of a normal window', async () => {
const w = new BrowserWindow();
const initialSize = w.getSize();
const initialPosition = w.getPosition();
w.unmaximize();
await delay(1000);
expectBoundsEqual(w.getSize(), initialSize);
expectBoundsEqual(w.getPosition(), initialPosition);
});
});
describe('setFullScreen(false)', () => {

View File

@@ -216,6 +216,18 @@ describe('ipc module', () => {
expect(port).to.be.an.instanceOf(EventEmitter);
});
it('can sent a message without a transfer', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');
const p = emittedOnce(ipcMain, 'port');
await w.webContents.executeJavaScript(`(${function () {
require('electron').ipcRenderer.postMessage('port', 'hi');
}})()`);
const [ev, msg] = await p;
expect(msg).to.equal('hi');
expect(ev.ports).to.deep.equal([]);
});
it('can communicate between main and renderer', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, contextIsolation: false } });
w.loadURL('about:blank');

View File

@@ -811,6 +811,17 @@ describe('chromium features', () => {
expect(typeofProcessGlobal).to.equal('undefined');
});
it('can disable node integration when it is enabled on the parent window with nativeWindowOpen: true', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true, nativeWindowOpen: true } });
w.loadURL('about:blank');
w.webContents.executeJavaScript(`
{ b = window.open('about:blank', '', 'nodeIntegration=no,show=no'); null }
`);
const [, contents] = await emittedOnce(app, 'web-contents-created');
const typeofProcessGlobal = await contents.executeJavaScript('typeof process');
expect(typeofProcessGlobal).to.equal('undefined');
});
it('disables JavaScript when it is disabled on the parent window', async () => {
const w = new BrowserWindow({ show: false, webPreferences: { nodeIntegration: true } });
w.webContents.loadURL('about:blank');

View File

@@ -1,10 +1,12 @@
<html>
<body>
<script>
// `setImmediate` schedules a function to be run on the next UV tick, which
// ensures that `window.open` is run from `UvRunOnce()`.
setImmediate(async () => {
if (!location.hash) {
if (location.hash) {
window.opener.postMessage('foo', '*');
} else {
// `setImmediate` schedules a function to be run on the next UV tick, which
// ensures that `window.open` is run from `UvRunOnce()`.
setImmediate(async () => {
const p = new Promise(resolve => {
window.addEventListener('message', resolve, { once: true });
});
@@ -12,10 +14,8 @@ setImmediate(async () => {
const e = await p;
window.close();
} else {
window.opener.postMessage('foo', '*');
}
});
});
}
</script>
</body>
</html>

View File

@@ -227,7 +227,8 @@ describe('<webview> tag', function () {
});
});
it('loads devtools extensions registered on the parent window', async () => {
// This test is flaky on WOA, so skip it there.
ifit(process.platform !== 'win32' || process.arch !== 'arm64')('loads devtools extensions registered on the parent window', async () => {
const w = new BrowserWindow({
show: false,
webPreferences: {

View File

@@ -8,7 +8,7 @@ const ChildProcess = require('child_process');
const { ipcRenderer } = require('electron');
const { emittedOnce, waitForEvent } = require('./events-helpers');
const { resolveGetters } = require('./expect-helpers');
const { ifdescribe, delay } = require('./spec-helpers');
const { ifit, ifdescribe, delay } = require('./spec-helpers');
const features = process._linkedBinding('electron_common_features');
/* Most of the APIs here don't use standard callbacks */
@@ -81,7 +81,8 @@ describe('chromium feature', () => {
expect(event.data).to.equal(`size: ${width} ${height}`);
});
it('disables node integration when it is disabled on the parent window', async () => {
// FIXME(zcbenz): This test is making the spec runner hang on exit on Windows.
ifit(process.platform !== 'win32')('disables node integration when it is disabled on the parent window', async () => {
const windowUrl = require('url').format({
pathname: `${fixtures}/pages/window-opener-no-node-integration.html`,
protocol: 'file',
@@ -154,16 +155,6 @@ describe('chromium feature', () => {
});
});
describe('window.postMessage', () => {
it('throws an exception when the targetOrigin cannot be converted to a string', () => {
const b = window.open('');
expect(() => {
b.postMessage('test', { toString: null });
}).to.throw('Cannot convert object to primitive value');
b.close();
});
});
describe('window.opener.postMessage', () => {
it('sets source and origin correctly', async () => {
const message = waitForEvent(window, 'message');

View File

@@ -1693,16 +1693,16 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colors@1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
colors@^1.1.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.3.3.tgz#39e005d546afe01e01f9c4ca8fa50f686a01205d"
integrity sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==
colors@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
combined-stream@^1.0.6, combined-stream@~1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"