about:newtab wallpaper is decoded in the parent process
Categories
(Firefox :: New Tab Page, defect)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox-esr115 | --- | unaffected |
| firefox-esr140 | --- | unaffected |
| firefox150 | --- | wontfix |
| firefox151 | --- | wontfix |
| firefox152 | --- | fixed |
People
(Reporter: tschuster, Assigned: tschuster)
References
Details
(Keywords: ai-involved, sec-want, Whiteboard: [prefs-checked][adv-main152-])
Attachments
(2 files, 1 obsolete file)
|
13.69 KB,
patch
|
Details | Diff | Splinter Review | |
|
48 bytes,
text/x-phabricator-request
|
Details | Review |
Chain
| Step | File:Line | What happens |
|---|---|---|
| 1 | browser/actors/AboutNewTabParent.sys.mjs:116 |
ActivityStream:ContentToMain forwarded unvalidated |
| 2 | browser/extensions/newtab/lib/ActivityStreamMessageChannel.sys.mjs:391 |
Object.assign(action, msg.data) β content controls action.type |
| 3 | browser/extensions/newtab/lib/Store.sys.mjs:46-53 |
dispatched to EVERY feed's onAction |
| 4 | browser/extensions/newtab/lib/Wallpapers/WallpaperFeed.sys.mjs:346 |
case at.WALLPAPER_UPLOAD: this.wallpaperUpload(action.data.file) β no gate |
| 5 | browser/extensions/newtab/lib/Wallpapers/WallpaperFeed.sys.mjs:246-249 |
customWallpaperThemeWorker.post("calculateTheme", [file]) |
| 6 | browser/extensions/newtab/lib/Wallpapers/WallpaperTheme.worker.mjs:25 |
createImageBitmap(blob) in parent-process ChromeWorker |
| 7 | dom/canvas/ImageBitmap.cpp:2139 |
imgtool->DecodeImageAsync(...) on parent main thread |
Gate status
feeds.wallpaperfeeddefaults totrue(ActivityStream.sys.mjs:1636)WALLPAPER_UPLOADcase has no check onnewtabWallpapers.enabledorcustomWallpaper.enabled- Actor matches
about:newtab*/about:home*inprivilegedaboutremote type β ALWAYS present
Impact
Any bug in nsPNGDecoder/nsJPEGDecoder/nsGIFDecoder2/nsWebPDecoder/nsBMPDecoder/nsICODecoder/nsAVIFDecoder
becomes a direct parent-process compromise. Image decoding is deliberately isolated
to content processes everywhere else in Firefox; this path bypasses that.
Fix
WallpaperFeed.onAction should gate WALLPAPER_UPLOAD on the feature prefs
(newtabWallpapers.enabled && customWallpaper.enabled). Even with the gate,
the primitive exists when the feature is enabled β decoding should be moved
to a sandboxed utility process, or at minimum the blob should be validated
(magic-byte sniff + size check) before passing to the worker.
Note: Could we instead already calculate the luminance in the (privileged) content process?
Updated•6 months ago
|
Updated•5 months ago
|
Comment 1•5 months ago
|
||
Comment 2•5 months ago
|
||
Patch moves the createImageBitmap/luminance calculation from the parent-process ChromeWorker (WallpaperTheme.worker.mjs) into the privileged about:newtab content process. WallpaperCategories.handleUpload now computes the dark/light theme client-side (inline WCAG luminance, no Color.sys.mjs dep) and dispatches WALLPAPER_UPLOAD with {file, theme}.
The parent WallpaperFeed.wallpaperUpload now:
- validates
Blob.isInstance(file)andtheme β {"dark","light"}before doing anything, - writes the file bytes to the profile verbatim (no decode),
- stores the theme as a string pref.
The now-dead WallpaperTheme.worker.mjs and its browser test are removed so the parent-side decode primitive can't be reintroduced by accident. xpcshell test_WallpaperFeed adjusted for the new signature.
This eliminates the IPC path described in comment 0 β image-decoder bugs reachable via about:newtab no longer become parent-process compromises, regardless of whether the feature prefs are on.
This is the analysis tool's suggested fix. Feel welcome to adopt it as a starting point and evolve it as needed to meet our coding standards.
Comment 3•5 months ago
|
||
Prefs check: newtabWallpapers.enabled, newtabWallpapers.customWallpaper.enabled and feeds.wallpaperfeed all default to true on all supported channels, and WallpaperFeed.onAction doesn't gate WALLPAPER_UPLOAD on any of them β supported config, marked [prefs-checked].
Attached patch moves the createImageBitmap/luminance calculation out of the parent-process ChromeWorker into the (privileged) about:newtab content process, so image decoding never happens in the parent. The parent's wallpaperUpload now only validates inputs (Blob.isInstance, theme β {dark,light}), writes the file bytes verbatim, and stores the theme as a string pref. The dead WallpaperTheme.worker.mjs and its browser test are removed so the parent-side decode primitive can't be reintroduced by accident.
This is an automated analysis result. If this result is incorrect please add a needinfo and feel free to correct the error.
| Assignee | ||
Comment 4•5 months ago
|
||
I read through the attached patch and the approach seems quite reasonable to me. Probably the only thing that might be missing, is test coverage for theme (light/dark) calculation.
Nathan, I see you worked on the WallpaperTheme.worker.mjs. Do you want to shepherd this patch through review or should I give it a try?
Comment 5•5 months ago
|
||
Hey Tom - If you could give it a try that would be great - Irene or Maxx are probably the best people to assist since i was recently moved to the growth team and not sure i'll have bandwidth to help.
| Assignee | ||
Updated•5 months ago
|
Comment 6•5 months ago
|
||
Tom - I'm happy to help / review / etc. Please let me know how I can help!
Updated•5 months ago
|
| Assignee | ||
Comment 7•5 months ago
|
||
Comment 8•5 months ago
|
||
Thanks, this works well.
I'm a bit curious on the time sensitivity on this?
Also wondering if we can get it moved into a content process worker?
| Assignee | ||
Comment 9•5 months ago
|
||
(In reply to Scott [:thecount] Downe from comment #8)
Thanks, this works well.
Cool, thanks for looking.
I'm a bit curious on the time sensitivity on this?
This isn't really time sensitive. While we would like this change for security hardening, for now we can assume about:newtab is mostly trusted.
Also wondering if we can get it moved into a content process worker?
Mike pointed this out as well. I will add Worker support back soon.
| Assignee | ||
Comment 10•5 months ago
•
|
||
This new Worker(new URL("./WallpaperTheme.worker.js", import.meta.url)); doesn't work:
Security Error: Content at about:home may not load or link to resource://newtab/lib/Wallpapers/WallpaperTheme.worker.js.
Is there some other way of referencing files in this code?
Comment 11•5 months ago
|
||
(In reply to Tom Schuster from comment #10)
This
new Worker(new URL("./WallpaperTheme.worker.js", import.meta.url));doesn't work:Security Error: Content at about:home may not load or link to resource://newtab/lib/Wallpapers/WallpaperTheme.worker.js.
Is there some other way of referencing files in this code?
Hm. We're able to load resource:// and chrome:// using <script> tags, but I have noticed that we're unable to (for example) load them as modules. We kind of exist in this weird liminal state that's kind of like an unprivileged web site and also very much not.
One thing you might need to do is add worker-src to the CSP here: https://searchfox.org/firefox-main/rev/8332a06d47ce7d66623d807068b3410061cd29d3/browser/extensions/newtab/bin/render-activity-stream-html.js#58
and then re-generate the HTML files with ./mach newtab bundle.
That might only get you so far though - when Scott tried that recently, the error became a CheckSameOriginError at https://searchfox.org/firefox-main/rev/8332a06d47ce7d66623d807068b3410061cd29d3/caps/BasePrincipal.cpp#678-682.
| Assignee | ||
Comment 12•5 months ago
|
||
Comment 13•5 months ago
|
||
In about:memory I see Extension(id=newtab@mozilla.org, name="New Tab", baseURL=moz-extension://631f3d57-2943-48c6-bed1-7a1cb9b15ef9/), can we serve the file off the extension? Note that bug 1767455 tracks a concerning longstanding flaw where a web-exposed webextension resource can bypass the same-origin constraint, so we wouldn't want to depend on/do that, but if you can make sure your page that's creating the worker is itself using the moz-extension scheme, possibly via using an iframe, you could then load the worker from there.
Comment 14•5 months ago
|
||
I think this would require a static UUID for the WebExtension which, at least for the moment, we don't have (but should probably get) - see bug 1985137.
Comment 15•5 months ago
|
||
The webext infra allows dynamically knowing your/the UUID though, so if an iframe was used perhaps it could be okay?
| Assignee | ||
Comment 16•5 months ago
•
|
||
I say let's just remove the Worker. Even when using a 4017 Γ 2683 px image the whole decoding process takes ~340ms for me. But what's even more surprising, it looks like we are internally always decoding the image on the main thread anyway (213ms of jank). Calculating the the luminance in JS takes only 25ms on the other hand, because the image was already down-scaled so much.
Profiler link: https://share.firefox.dev/4vxc92f (Fair warning: I extracted the code to a normal HTML/JS file for easier testing)
Comment 18•5 months ago
|
||
If the Worker is not workable under these conditions, updating the background image is an infrequent enough action that I'd be okay with it happening on the main thread, if there's no better way.
Updated•5 months ago
|
Comment 19•5 months ago
|
||
Comment 20•5 months ago
|
||
Comment 21•5 months ago
|
||
TEST-UNEXPECTED-ERROR | browser/components/backup/tests/marionette/test_backup.py BackupTest.test_backup | FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpu4456mhc.recoverFromBackupArchiveTest-newProfileRoot/wallpaper'
| Assignee | ||
Updated•5 months ago
|
Comment 22•5 months ago
|
||
Comment 23•5 months ago
|
||
Updated•4 months ago
|
Updated•4 months ago
|
Updated•4 months ago
|
Description
•