w3c / webcodecs

WebCodecs is a flexible web API for encoding and decoding audio and video.

Home Page:https://w3c.github.io/webcodecs/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

https://w3c.github.io/webcodecs/#dom-videoframe-videoframe could check origin-clean sooner

youennf opened this issue · comments

The VideoFrame constructor is first checking usability (and will throw as needed) and then check origin-clean.
Chrome apparently does it as per spec.
Safari checks origin-clean first then checks usability.

It seems slightly preferable to check origin-clean first, to prevent any potential information leak.
One edge case where it might be useful is if the image is not origin-clean and is only partially decodable or if its natural width or height is zero.

Chrome uses a standard helper (blink::ToCanvasImageSource()) to coerce the V8 object into a blink type, then immediately does the origin check before using it in any way. Looking at that helper though, it does check the size of a <canvas> and verify that the value is not detached.

I agree that the size check is surprising, but this is also the same code pattern used for drawImage() so I am reluctant to change it before comparing with the canvas specification and experts.

My feeling here is that there is no reason that JS can't check the size of a tainted canvas, nor can a detached value be tainted. Assuming that is accurate, I'm most concerned in matching the canvas spec.

I think the principle for canvas is to make it not origin clean when actually drawing some pixels to it, hence why it happens at the end.
But this makes canvas probably somehow leaking that info by throwing (or not throwing) when getting image data from it.
We might indeed want to check with some canvas experts here.

@sandersdan I'm not sure I understand. drawImage() doesn't throw. It taints the canvas. And in particular https://html.spec.whatwg.org/#check-the-usability-of-the-image-argument does not check tainting in any way.

Most places that end up checking whether the canvas is tainted when it is not done in order to propagate the tainted bit do check that first and throw immediately. E.g., canvas.toBlob(). One exception I found is getImageData() which validates its sw and sh arguments first, but that doesn't leak any information as those arguments are provided by the "attacker".

The way HTML is structured it seems perfectly reasonable to call "is not origin-clean" first and "check the usability of the image argument" second. That Chromium has these coupled in some way seems more like an implementation detail of Chromium.

Now whether it leaks any information if you do these in the opposite order I'm not sure. Spectre-wise most image formats are already hosed so that's hard to say. And even without Spectre dimensions are definitely revealed, though other aspects such as orientation and actual data are not.

Thanks, I see that checking the origin is the last step of drawImage(), which explains why the existing code paths check these properties early.

We don't have a concept of tainted VideoFrames, so we do have to throw at some point (or add tainting). Note that we originally decided against doing so because the underlying VideoFrame resource may not have origin information, so there were risks at API boundaries. I think those boundaries are at least better-understood now.

It doesn't sound like there is either a disclosure risk or any existing algorithm we need to remain consistent with. I am willing to move the check earlier if that is preferred.

Right, and the drawImage() check is really a matter of propagating the bit and not using it as a reason to throw.

Checking and throwing for tainting first will give us more flexibility later if anything ends up changing around tainted/opaque images.