Open Bug 1939291 Opened 2 months ago Updated 8 days ago

Incorrect canvas SecurityError thrown in extension context with second canvas

Categories

(WebExtensions :: Untriaged, defect, P3)

Firefox 133
defect

Tracking

(firefox134 affected, firefox135 affected, firefox136 affected)

Tracking Status
firefox134 --- affected
firefox135 --- affected
firefox136 --- affected

People

(Reporter: hicallmeal, Unassigned)

References

(Depends on 1 open bug)

Details

Attachments

(2 files)

994 bytes, application/x-zip-compressed
Details
731 bytes, application/x-zip-compressed
Details

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0

Steps to reproduce:

user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0

In an extension content_script context. a canvas B that uses canvas A's surface is marked as tainted, despite canvas A having only drawn a dataUri.

So in practical terms: my browser extension sends the output of captureVisibleTab to the content_script, which then runs some canvas operations, and if needed, creates a second canvas (performance reasons) to make any adjustments, such as scaling or transparency filling, etc.

I have attached an extension for reproducing -

  1. Load it
  2. go to 'example.com'

Actual results:

In firefox, I get a securityError when trying to output the second canvas's data, despite all pixels being local, and both canvas's running in an isolated content_script context.

Expected results:

Per the above, I shouldn't be getting a securityError, as it's all same-origin and local/isolated.

This occurs contrary to the spec and documentation.
In chrome it works fine.

I will provide more detailed info and resources in a comment

The Bugbug bot thinks this bug should belong to the 'Core::Graphics: Canvas2D' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.

Component: Untriaged → Graphics: Canvas2D
Product: Firefox → Core

This is related to this bug and the patch applied from it, and what I believe is happening, is that the second canvas's principal does not subsume the first one's but this is where I have fallen short.

But to step through the code, here's the following:
(this is during the canvas2.drawImage and canvas2.toDataURL)

  • When the pixels are drawn, a security check occurs, and the canvas is marked as writeOnly (aka tainted(?)), but a reference to the original is stored (ExpandedReader)
  • When toDataUrl (or similar) is called, to check whether it can be run, a check whether it's WriteOnly or can read the pixels is run
  • Since it fails the first condition, the callerCanRead check runs and
    • First check fails (as it's writeOnly)
    • But the second, fails as well
    • this is despite the fact that both originate in the content_script, isolated context, so my understand is that the principal's should be equal, thus B should subsume A.
    • Check 3 fails if the extension doesn't have ["<all_urls>"] host_permissions (temporary or permanent).

I can't figure out why the second check fails, I was unable to inspect the principals during runtime, and I don't know where they are first set.

I would like to say that I'm not sure why there are exceptional add-on conditions, as Chrome does not have this (at least these days), but as per Chesterton's Fence, I'm sure there is/was once a reason!
I suppose it's so that the global world context cannot access it, which makes sense, but I guess it's just differing architectural decisions (totally beyond me and I am not making assessments!!)

But due to that I don't have any suggestions for remedy, sorry!

MDN Doc
WHATWG Spec

Here's the last CallerCanRead patch, and it looks like the above really shouldn't be happening (as this scenario matches the comment) and bug

Hope this all helps!

Component: Graphics: Canvas2D → Untriaged
Product: Core → Firefox

I should add, I tested on nightly as well.

Product: Firefox → WebExtensions

Hello,

I reproduced the issue on the latest Nightly (136.0a1/20250107165124), Beta (135.0b1/20250106170344) and Release (134.0/20241230151726) on Windows 10 and Ubuntu 24.04 LTS.

As soon a I access https://example.com/ I get a popup with SecurityError: The operation is insecure.

Status: UNCONFIRMED → NEW
Ever confirmed: true

The severity field is not set for this bug.
:zombie, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(tomica)

It looks like the issue may stem from the ImageData interface itself.
I've written and attached a reproduction that demonstrates that:

  • you can read ImageData data and write it to an array
  • you cannot write to an ImageData's data array

Meaning, if you create an ImageData object, you can't write to it after that!
e.g.

let imageData = new ImageData(100, 100)
imageData.data.set([1,2,3,4], 0) // doesn't work!

This subsequently affects imageData retrieved from the canvas causing the issues reported above (likely).
At one point I got a perm error when testing with createImageBitmap, but I cannot reproduce.

To repro, as before, load the attached "firefox-imagedata..." ext, and navigate to example.com.

  • You can also proceed to additional tests (confirm() dialog) and check the console for more.

I've had a look through (what I think is) the ImageData code, but nothing stands out to me. I think it's some principal security issue.
Maybe the ImageData isn't given the expanded principal, or the content script doesn't subsume the ImageData's base principal.
(I'm reaching - this is far beyond me. I'd love to help/solve, but I don't know where to look).

As a last note - for comparison, all the code works in the Firefox MAIN world environment and in Chrome MAIN & ISOLATED.

Note: I haven't looked at this in detail, but if not caused by the principal (e.g. expanded principal vs content principal) this can also be an Xray issue.

For visibility, I'm also linking this to bug 1939294.

See Also: → 1939294

(In reply to Rob Wu [:robwu] from comment #8)

Note: I haven't looked at this in detail, but if not caused by the principal (e.g. expanded principal vs content principal) this can also be an Xray issue.

For visibility, I'm also linking this to bug 1939294.

I can't rule Xray out as I'm not familiar with it, so it's certainly possible. I don't believe expanded principals play a role here, as I believe expandedreader is merely a reference to the sourceSurface to be drawn on the canvas. Meaning, if it were an expanded principal, then per the article, it shouldn't work per docs. (if that's what you were referring to). Of course, acknowledging you've had a cursory look (and my limited knowledge on this!).

I did want to just update my findings - I'm now convinced it's a principal subsumption issue, i.e. the Canvas principal not being able to subsume the surface. I'm still not sure why. I just can't understand it, or observe at run time, for that matter. Perhaps it's an Xray thing, since they're related.

I don't believe it's related to ImageData, per #6, anymore, that's like a separate issue - happy to log that if needed.

This sounds exactly like bug 1939294. Alex, could you please verify once that's fixed and close if I'm correct?

Severity: -- → S3
Depends on: 1939294
Flags: needinfo?(tomica)
Priority: -- → P3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: