[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] Proposed change to WebGL spec section 4.2 (Security Origin Restrictions)



I assure you that recreating all of the resources of the scene is very slow. In fact, the graphics card may not have enough memory for two copies of all of the resources.

Can you give me an example of how this decreases security? Is the concern that implementors will have bugs in their code that will cause the origin to be marked as clean when it is not supposed to be? Otherwise it seems the only functions that would have to change are bindTexture and bindFramebuffer. bindTexture simply needs to check if the texture being bound is unclean, and if so do the same thing as if texImage2D were called with an other-origin image. bindFramebuffer simply needs to iterate through the bound textures and do the same, and afterwards copy its clean state to the canvas. There is never a transition from unclean to clean for either textures or framebuffers, only the canvas can become clean after being unclean, and only by having a clean framebuffer bound to it.

The only additional complexity I can see is that marking the framebuffer as unclean also means that the underlying data store for that framebuffer (renderbuffers, textures, etc) needs to also be marked as unclean, and framebufferTexture and framebufferRenderbuffer also need to mark the framebuffer as unclean if the underlying storage is unclean.

So it becomes:

texImage2d with unclean:
  texture.clean = false
  makeFramebufferUnclean

bindTexture:
  if unclean:
    makeFramebufferUnclean

bindFrameBuffer:
  for each bound texture
    if texture unclean:
      makeFramebufferUnclean
  for each texture binding to framebuffer:
    if texture unclean:
      makeFramebufferUnclean
  for each renderbuffer binding to framebuffer:
    if renderbuffer unclean:
      makeFramebufferUnclean
  canvas.clean = framebuffer.clean

makeFramebufferUnclean:
  framebuffer.clean = false
  for each texture binding to framebuffer:
    texture.clean = false
  for each renderbuffer binding to framebuffer:
    renderbuffer.clean = false
  canvas.clean = false

framebufferRenderbuffer:
  if renderbuffer unclean:
    makeFramebufferUnclean

framebufferTexture:
  if texture unclean:
    makeFramebufferUnclean

Note that there is no way to set framebuffer.clean to true. The only way to get image data into that framebuffer is through a bound texture, texture binding, or renderbuffer binding. Changing any of those bindings to something that is not clean permanently dirties the framebuffer and the storage it may draw into. Even something convoluted like drawing a dirty image into a framebuffer with an attached renderbuffer, attaching that renderbuffer to a clean framebuffer, and trying to read pixels from that framebuffer will not work because the renderbuffer would be dirtied by binding the dirty image, and the new framebuffer would be dirtied by binding the renderbuffer to it.

The trick is that any operation with anything dirty always dirties the currently attached framebuffer and anything attached to it, and changing the attached framebuffer checks all attached or bound resources and will only let the framebuffer be clean if everything is.

Can you find any security flaws with this?

Can you think of any better way to allow an application to get any form of data back from the graphics card for a canvas that has used images from another origin, without the incredibly slow and memory wasting operation of putting all of the data into a new context?

-Brian

On Mon, Oct 4, 2010 at 3:44 PM, Chris Marrin <cmarrin@apple.com> wrote:

On Oct 4, 2010, at 2:23 PM, Brian Cornell wrote:

> Currently section 4.2 of the specification provides a sufficient but not necessary restriction on readPixels to prevent reading data from other origins. Greater functionality could be given to application developers by slightly increasing the complexity here, while still maintaining the desired security.
>
> I propose that rather than texImage2D from a different origin or unclean resource causing the canvas to be marked as unclean, it would set a flag marking that texture as unclean, and also set a flag marking the current framebuffer as unclean. Binding a texture would set the flag marking the framebuffer as unclean if the bound texture is marked as unclean. Changing the attached framebuffer would set the flag marking the new framebuffer as unclean if any bound texture is marked as unclean. The origin-clean flag of the canvas would reflect the status of the currently bound framebuffer.
>
> This would allow developers to read the contents of a framebuffer from a context where different origin images were used, but only in certain same circumstances, such as the following pseudocode:
>
> create texture A
> bind texture A
> texImage2D into A with different origin data // canvas, default framebuffer, and texture are all now unclean
> draw some stuff using texture A and cached buffers
> bind null in place of texture A // canvas and default framebuffer are still marked as unclean
> create framebuffer B // framebuffer B is clean
> bind framebuffer B // canvas and framebuffer B are marked as clean
> draw some stuff using same cached buffers but not texture A
> readPixels // this can now succeed because the unclean data has never been connected to framebuffer B
> bind default framebuffer // canvas now back to unclean because default framebuffer is unclean
> bind texture A
> draw
> ...
>
>
> This is a significant win over using separate canvases for the two operations if the unclean drawing and the clean drawing share a significant amount of buffered data or clean textures.
>
> As an example of how this could be used, say you had a 3d game that showed ads on billboards in the game. The ads are served as images by some other domain. You want to include a way to take screenshots in the game. For a screenshot, you use a different framebuffer and don't bind the images for ads, you render a black box or an ad placeholder image from the clean origin instead. You want to reuse all of the buffered data and clean textures for the screenshot, so using a different canvas would be painful and slow. Using this proposed change you would be able to read the pixels from the alternate framebuffer as long as no ad textures were ever bound at the same time as that framebuffer.
>
> Thoughts?

This seems like enough added complexity that it will be hard to maintain security. There are many places where a hole might be discovered to give an author access to the other's origin's pixels. Seems like it would be easier if, in your use case, you simply created a new canvas, initialized it and loaded it with resources, skipping the undesired textures. That keeps things clean and lets you get your screen shot. That's more work and more resource allocation, but keeps the system simple and easier to keep secure.

-----
~Chris
cmarrin@apple.com