Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

To wrap or not to wrap

11 views
Skip to first unread message

Blake Kaplan

unread,
Feb 17, 2009, 7:09:10 PM2/17/09
to
Ever since the advent of XOWs (cross origin wrappers), there's been an
undercurrent of grumbling whenever I mention wrappers. This grumbling comes to
the surface mostly when I suggest adding new wrappers, but none of the
grumbling has really come to the surface. We've recently hit a point where
we're looking at adding another type of wrapper for real and I wanted to both
give the grumbling a chance to actually turn into a useful conversation and to
get explicit approval on taking the wrapper path.

Using wrappers for security has several benefits and problems, here are the
benefits that I can see:

*) Optimizing for the common case: In most cases, we don't need to do
security checks or do any special handling outside of XPConnect. By
putting the security checks in wrappers, we move the expensive checks
into cases where we're pretty sure they're needed (the explicit window
object is one case where this breaks down a little).

*) Centralization of security code: By sharing code between wrappers, we
reduce the number of places in the codebase that have to do security
operations.

*) Easy layering: Since wrappers wrap things, we can layer them on top of
optimizations like DOM quickstubs and still preserve the win we get out
of quickstubs.

Here are the main disadvantages that I see:

*) Layering: Since wrappers are basically a type of aspect (as in, aspect
oriented programming) they come with the same problem where we have to
wonder what happens if there's a SJOW around a XOW around an XPNW, etc.
This adds complexity.

*) Ensuring we wrap where we need to: Showing that we're wrapping everywhere
that we have to is not easy and can be tricky to get right.

I'm sure there are more of both. I think that the advantages outweigh the
disadvantages and further, wrappers already have their foot in the door. If we
decide that they're not worth it, then we'll have to find another strategy,
including one that preserves optimizations like quickstubs and allows us to
(eventually) trace into the DOM.

One alternative that I noticed was to set a bit on XPCWrappedNatives when
they're touched from more than one scope that causes us to do security checks
everywhere, but then it's hard to have subtilely different behaviors (e.g.
where XOWs act like XPCNativeWrappers when they're used cross-origin).

For reference, the two wrappers we're looking at adding now are (the names are
up for grabs):

*) XPCUnsafeJSObjectWrapper: The opposite of XPCSafeJSObjectWrapper, this
would by used by chrome to insert an object safely into content.
Currently, doing so is fraught with peril.

*) XPCChromeOnlyWrapper: This will (for now) wrap native anonymous content
nodes that only chrome is allowed to touch.
--
Blake Kaplan

John J Barton

unread,
Feb 17, 2009, 8:25:35 PM2/17/09
to
Blake Kaplan wrote:
...

> Using wrappers for security has several benefits and problems, here are the
> benefits that I can see:
>...

>
> Here are the main disadvantages that I see:
>
> *) Layering: Since wrappers are basically a type of aspect (as in, aspect
> oriented programming) they come with the same problem where we have to
> wonder what happens if there's a SJOW around a XOW around an XPNW, etc.
> This adds complexity.
>
> *) Ensuring we wrap where we need to: Showing that we're wrapping everywhere
> that we have to is not easy and can be tricky to get right.
>...

From the extension developers point of view the main disadvantages are

1) Asymmetry: if you have a wrapped object you can read properties and
write properties, but only the read will actually turn out for you.

2) Unpredictability: is your object a wrapper or not? Sometimes you have
to resort to if (obj.wrappedJSObject)... because you can't predict.

3) Anxiety: the wrapping is clearly important, so what happens if you do
object.wrappedJSObject.foo?

I guess I've had more experience than most developers and I still don't
get it. Most of the docs are written from the wrapper-creators' point
of view and make little sense to the wrapper-consumer.

>
> For reference, the two wrappers we're looking at adding now are (the names are
> up for grabs):
>
> *) XPCUnsafeJSObjectWrapper: The opposite of XPCSafeJSObjectWrapper, this
> would by used by chrome to insert an object safely into content.
> Currently, doing so is fraught with peril.

You mean you might obsolete Firebug's console injector code? You should
definitely list that under the advantages!

jjb

Blake Kaplan

unread,
Feb 17, 2009, 9:30:32 PM2/17/09
to
John J Barton <johnj...@johnjbarton.com> wrote:
> 1) Asymmetry: if you have a wrapped object you can read properties and
> write properties, but only the read will actually turn out for you.

What do you mean by "turn out?" This depends mostly on the wrapper. If you
have an XPCNativeWrapper, then writing to an expando (non-IDL) property will
only affect the wrapper but if you have an XPCSafeJSObjectWrapper (i.e.
someXPCNW.wrappedJSObject) then reads and writes do exactly what you think
they will.

> 2) Unpredictability: is your object a wrapper or not? Sometimes you have
> to resort to if (obj.wrappedJSObject)... because you can't predict.

Wrappers should be predictable, actually. If you are getting wrappers for some
property access some times but not others, that's a bug. In a way, wrappers
become part of the API and we have to announce changes to the API when we
change it.

> 3) Anxiety: the wrapping is clearly important, so what happens if you do
> object.wrappedJSObject.foo?

This can be solved by reading the documentation (or if it isn't clear enough,
then asking). I'll see if I can clarify that on the XPConnect wrappers page at
some point in the near future. The short answer to your example is that even
when you use .wrappedJSObject on an XPCNativeWrapper, you get a wrapper back,
but a different one that allows you to access the object more directly (but
still (mostly, as you know, setting untrusted objects' properties to trusted
objects is still a bug, XPCUnsafeJSObjectWrapper will hopefully come to the
rescue) safely!).

> I guess I've had more experience than most developers and I still don't
> get it. Most of the docs are written from the wrapper-creators' point
> of view and make little sense to the wrapper-consumer.

This is my fault, but I do need guidance. Writing good documentation is hard
and I'm not well versed in doing so. I'll see if I can extend it.

Also, this isn't a problem with wrappers, per se; it has to do with
documenting the security system we use better. We'll have to document any
solution we come up with.

> You mean you might obsolete Firebug's console injector code? You should
> definitely list that under the advantages!

Yep, that is one of the use-cases that we see for it.
--
Blake Kaplan

John J. Barton

unread,
Feb 18, 2009, 12:31:49 AM2/18/09
to
Blake Kaplan wrote:
> John J Barton <johnj...@johnjbarton.com> wrote:
>> 1) Asymmetry: if you have a wrapped object you can read properties and
>> write properties, but only the read will actually turn out for you.
>
> What do you mean by "turn out?" This depends mostly on the wrapper. If you
> have an XPCNativeWrapper, then writing to an expando (non-IDL) property will
> only affect the wrapper but if you have an XPCSafeJSObjectWrapper (i.e.
> someXPCNW.wrappedJSObject) then reads and writes do exactly what you think
> they will.

I'm reminded of this old Gary Larson 'Far Side' cartoon of a dog
listening to a man: "blah, blah, blah, *biscuit*, blah, blah,...".

From the extension developers point of view, there are none of those
things you describe. We never see an XPCNativeWrapper or an expando or a
XPCSafe whatever. We just make a function call and something comes back.

So what I meant was: some objects you can write on but they don't cause
the effect you want. They write on the wrapper but not the real deal, no
warning or error. But when you read them you get the values of the real
object. Results are asymmetric. I would much rather get a write error,
since the outcome is erroneous.

>
>> 2) Unpredictability: is your object a wrapper or not? Sometimes you have
>> to resort to if (obj.wrappedJSObject)... because you can't predict.
>
> Wrappers should be predictable, actually. If you are getting wrappers for some
> property access some times but not others, that's a bug. In a way, wrappers
> become part of the API and we have to announce changes to the API when we
> change it.

Well we certainly get wrappers sometimes and sometimes not. I think you
are dividing the world up in a way that we cannot. We have a big pile of
objects and we operate on them. Sometimes the operation is close to
where we make platform API call so we know to expect wrapperishness. But
other times we've stored, rename, passed the objects around. Then
somethings not working: could it be a wrapper issue? 99/100 not, but the
100th time you remember to blame wrappers.

>
>> 3) Anxiety: the wrapping is clearly important, so what happens if you do
>> object.wrappedJSObject.foo?
>
> This can be solved by reading the documentation (or if it isn't clear enough,
> then asking). I'll see if I can clarify that on the XPConnect wrappers page at
> some point in the near future. The short answer to your example is that even
> when you use .wrappedJSObject on an XPCNativeWrapper, you get a wrapper back,
> but a different one that allows you to access the object more directly (but

That explanation makes more sense than others, I kinda understand it.
But, then you ended the good news with "but...", now I'm anxious again ;-)

> still (mostly, as you know, setting untrusted objects' properties to trusted
> objects is still a bug, XPCUnsafeJSObjectWrapper will hopefully come to the
> rescue) safely!).
>
>> I guess I've had more experience than most developers and I still don't
>> get it. Most of the docs are written from the wrapper-creators' point
>> of view and make little sense to the wrapper-consumer.
>
> This is my fault, but I do need guidance. Writing good documentation is hard
> and I'm not well versed in doing so. I'll see if I can extend it.

I think my best advice is to try to write the documentation without ever
using any word that starts with a capital 'X', because we don't see
those when working in javascript. (Except in the error messages, but I
won't go there).


jjb

Neil

unread,
Feb 18, 2009, 5:41:00 AM2/18/09
to
Blake Kaplan wrote:

>John J Barton <johnj...@johnjbarton.com> wrote:
>
>
>>1) Asymmetry: if you have a wrapped object you can read properties and write properties, but only the read will actually turn out for you.
>>
>>
>What do you mean by "turn out?" This depends mostly on the wrapper. If you have an XPCNativeWrapper, then writing to an expando (non-IDL) property will only affect the wrapper but if you have an XPCSafeJSObjectWrapper (i.e. someXPCNW.wrappedJSObject) then reads and writes do exactly what you think they will.
>
>

And if you have an XPCWrappedNative then you can't set expando
properties at all, but if you have an XPCNativeWrapper for that
XPCWrappedNative then you can ;-)

>>2) Unpredictability: is your object a wrapper or not? Sometimes you have to resort to if (obj.wrappedJSObject)... because you can't predict.
>>
>>
>Wrappers should be predictable, actually. If you are getting wrappers for some property access some times but not others, that's a bug. In a way, wrappers become part of the API and we have to announce changes to the API when we change it.
>
>

When the login manager calls back into navigator.js it passes us an
[XPCNativeWrapper [object Window]] but when the login manager's tests
call us they only have an [object Window] so we have to deal...

--
Warning: May contain traces of nuts.

Boris Zbarsky

unread,
Feb 18, 2009, 10:06:55 AM2/18/09
to
Neil wrote:
> And if you have an XPCWrappedNative then you can't set expando
> properties at all

Er... that's not true. What makes you say that? I bet you set expando
properties on XPCWrappedNatives for DOMNodes all the time!

> When the login manager calls back into navigator.js it passes us an
> [XPCNativeWrapper [object Window]] but when the login manager's tests
> call us they only have an [object Window] so we have to deal...

That sounds odd. Why is that happening? Is one window chrome while the
other is content?

-Boris

Mike Shaver

unread,
Feb 18, 2009, 10:58:15 AM2/18/09
to Blake Kaplan, dev-pl...@lists.mozilla.org
Must the XPC prefix be present? It's visible to developers, alas, and
I think contributes only noise and confusion -- nobody should care
that it's part of XPConnect, especially since these wrappers will
remain even as we root XPConnect out of various paths.

> _______________________________________________
> dev-platform mailing list
> dev-pl...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-platform
>

--
Sent from Gmail for mobile | mobile.google.com

Boris Zbarsky

unread,
Feb 18, 2009, 11:11:30 AM2/18/09
to
Mike Shaver wrote:
> Must the XPC prefix be present? It's visible to developers, alas

I see no obvious reason why the toString() needs to match the C++ class
name. I'm all for dropping XPC from the former!

-Boris

Benjamin Smedberg

unread,
Feb 18, 2009, 11:35:43 AM2/18/09
to
On 2/17/09 7:09 PM, Blake Kaplan wrote:

> *) Ensuring we wrap where we need to: Showing that we're wrapping everywhere
> that we have to is not easy and can be tricky to get right.

Although proving we wrap everywhere might be hard, it seems that fuzzing and
then checking for the correct wrapper types might be better in general.

> For reference, the two wrappers we're looking at adding now are (the names are
> up for grabs):
>
> *) XPCUnsafeJSObjectWrapper: The opposite of XPCSafeJSObjectWrapper, this
> would by used by chrome to insert an object safely into content.
> Currently, doing so is fraught with peril.
>
> *) XPCChromeOnlyWrapper: This will (for now) wrap native anonymous content
> nodes that only chrome is allowed to touch.

Can you give an example of how a chrome-only wrapper would come into play?

I think the big problem with wrappers for extension authors is that it's
confusing to figure out what they're or whether it does what they want. I
think we should probably pick better defaults:

* By default, chrome acessing content should see the safe JS object wrapper:
this gives chrome the same view of the DOM as content gets by default.

* Make an explicit API to turn a safe JS object wrapper into a native
wrapper (that is, give a way for chrome to ignore expando properties)

* Make it illegal/impossible to set expando properties on a native wrapper.

I have a question that's been nagging me about cross-origin wrappers: the
docs say "If a XOW wrapper happens to wrap an object that is from the same
origin as the running code, it acts like the Safe JSObject wrapper and it is
possible to do anything to the XOW that you would do with any JS object. If
the underlying object is not accessible, then it acts like an
XPCNativeWrapper, meaning that it allows access to all APIs and behaviors
provided by idl, overriding whatever the other site might have done." Don't
you know whether the object is accessible at the time it is accessed? And in
that case, can't you avoid creating the XOW and just return the regular JS
object? Is there a case where an object can some change from accessible to
inaccessible dynamically?

--BDS

Boris Zbarsky

unread,
Feb 18, 2009, 11:46:04 AM2/18/09
to
Benjamin Smedberg wrote:
> * By default, chrome acessing content should see the safe JS object wrapper:
> this gives chrome the same view of the DOM as content gets by default.
>
> * Make an explicit API to turn a safe JS object wrapper into a native
> wrapper (that is, give a way for chrome to ignore expando properties)

We sort of used to have this setup. It turns out, people largely forgot
to use the explicit native wrapper when they needed to (basically when
relying on ANY DOM property get off a content object to return something
resembling what the DOM specifies). That's why we added implicit
XPCNativeWrapper automation. Without it, half our chrome could be made
to behave in weird ways, and the situation was even worse for extensions.

> * Make it illegal/impossible to set expando properties on a native wrapper.

The reason we allowed this was to allow chrome to "flag" content nodes
the way content can. This still works, last I checked... What are the
issues people run into with this, exactly?

I do think making it impossible to set expandods on "non-persistent"
XPCNativeWrappers is probably a good idea.

> I have a question that's been nagging me about cross-origin wrappers: the
> docs say "If a XOW wrapper happens to wrap an object that is from the same
> origin as the running code, it acts like the Safe JSObject wrapper and it is
> possible to do anything to the XOW that you would do with any JS object. If
> the underlying object is not accessible, then it acts like an
> XPCNativeWrapper, meaning that it allows access to all APIs and behaviors
> provided by idl, overriding whatever the other site might have done." Don't
> you know whether the object is accessible at the time it is accessed?

Yes, but some objects are accessible even if they're from a different
origin (e.g. Window objects, Location objects).

> Is there a case where an object can some change from accessible to
> inaccessible dynamically?

Yes, Window objects, Location objects. Probably others that I'm not
thinking of right now. It sucks that this can happen, and if we had
immutable per-object origins I would be ecstatic, but that's life. :(

-Boris

Benjamin Smedberg

unread,
Feb 18, 2009, 11:48:59 AM2/18/09
to
On 2/18/09 11:46 AM, Boris Zbarsky wrote:

> Yes, but some objects are accessible even if they're from a different
> origin (e.g. Window objects, Location objects).
>
>> Is there a case where an object can some change from accessible to
>> inaccessible dynamically?
>
> Yes, Window objects, Location objects. Probably others that I'm not
> thinking of right now. It sucks that this can happen, and if we had
> immutable per-object origins I would be ecstatic, but that's life. :(

I thought that the inner/outer window split was done precisely for this
reason, so that each "window" was in fact a different object... is this not
how it works?

--BDS

Boris Zbarsky

unread,
Feb 18, 2009, 12:10:19 PM2/18/09
to
Benjamin Smedberg wrote:
> I thought that the inner/outer window split was done precisely for this
> reason, so that each "window" was in fact a different object... is this not
> how it works?

The split was done so we could preserve a script's global scope even
though a new page had loaded in the window.

The inner window nowadays more or less has an immutable principal.

But the outer window has the principal of whatever window is inside it.
The outer window is the one scripts always see when they're explicitly
looking at a Window object.

-Boris

Blake Kaplan

unread,
Feb 18, 2009, 1:25:38 PM2/18/09
to
John J. Barton <johnj...@johnjbarton.com> wrote:
> From the extension developers point of view, there are none of those
> things you describe. We never see an XPCNativeWrapper or an expando or a
> XPCSafe whatever. We just make a function call and something comes back.

Okay, that's fair. But it is useful to have a vocabulary to talk about the
different types of wrappers. The names themselves are not important. It's
useful for me to be able to say, "well, if you touch this object, by default
you'll get wrapper X, but if you use the .wrappedJSObject property on it,
you'll have wrapper Y, which acts differently." More to the point, though,
you make a function call on some object. If that object is a content object,
then you'll get some type of protective wrapper back (if you're using
xpcnativewrapers=no, then you'll get a different type of wrapper). I suppose
if you lose track in different parts of your code where you're touching
content or more of your own objects, you can get lost.

> So what I meant was: some objects you can write on but they don't cause
> the effect you want. They write on the wrapper but not the real deal, no
> warning or error. But when you read them you get the values of the real
> object. Results are asymmetric. I would much rather get a write error,
> since the outcome is erroneous.

As Boris said in another message to this thread, the reason for this is to
allow extensions to tag content objects for their own use. Unfortunately, we
can't go back on this without breaking existing extensions. I'll file a bug on
trying to do something about it.

> Well we certainly get wrappers sometimes and sometimes not. I think you
> are dividing the world up in a way that we cannot. We have a big pile of
> objects and we operate on them. Sometimes the operation is close to
> where we make platform API call so we know to expect wrapperishness. But

I can't really help you here. I think that in an ideal world, you have a
finite set of places where foreign values flow into your system. If not, then
figuring out what bugs are bugs in wrappers is hard and requires more work.

> That explanation makes more sense than others, I kinda understand it.
> But, then you ended the good news with "but...", now I'm anxious again ;-)

You're dealing with security here, you're supposed to be anxious :-).

> I think my best advice is to try to write the documentation without ever
> using any word that starts with a capital 'X', because we don't see
> those when working in javascript. (Except in the error messages, but I
> won't go there).

I'll give this a shot, but as I've said, I think that having a vocabulary for
talking about the different types of wrappers is useful.
--
Blake Kaplan

Blake Kaplan

unread,
Feb 18, 2009, 1:31:27 PM2/18/09
to
Neil <ne...@parkwaycc.co.uk> wrote:
>>>
>>Wrappers should be predictable, actually. If you are getting wrappers for some property access some times but not others, that's a bug. In a way, wrappers become part of the API and we have to announce changes to the API when we change it.
>>
>>
> When the login manager calls back into navigator.js it passes us an
> [XPCNativeWrapper [object Window]] but when the login manager's tests
> call us they only have an [object Window] so we have to deal...

So this is a bug, then. Please file it so we can figure out what's going on?
--
Blake Kaplan

Blake Kaplan

unread,
Feb 18, 2009, 1:36:22 PM2/18/09
to
Mike Shaver <mike....@gmail.com> wrote:
> Must the XPC prefix be present? It's visible to developers, alas, and
> I think contributes only noise and confusion -- nobody should care
> that it's part of XPConnect, especially since these wrappers will
> remain even as we root XPConnect out of various paths.

Of course not. The least planned out part of this operation was the names of
the wrappers. If people think that it's worth it, I can file a bug to rename
the wrappers. The old names will have to stay to preserve old code, but we can
inroduce new names to phase out the old ones.
--
Blake Kaplan

John J. Barton

unread,
Feb 18, 2009, 1:54:30 PM2/18/09
to
Blake Kaplan wrote:
> John J. Barton <johnj...@johnjbarton.com> wrote:...

>> Well we certainly get wrappers sometimes and sometimes not. I think you
>> are dividing the world up in a way that we cannot. We have a big pile of
>> objects and we operate on them. Sometimes the operation is close to
>> where we make platform API call so we know to expect wrapperishness. But
>
> I can't really help you here. I think that in an ideal world, you have a
> finite set of places where foreign values flow into your system. If not, then
> figuring out what bugs are bugs in wrappers is hard and requires more work.

We are very careful with values that come from the web. But for the
rest of the platform API having such a limitation isn't practical.


>
>> I think my best advice is to try to write the documentation without ever
>> using any word that starts with a capital 'X', because we don't see
>> those when working in javascript. (Except in the error messages, but I
>> won't go there).
>
> I'll give this a shot, but as I've said, I think that having a vocabulary for
> talking about the different types of wrappers is useful.

So another suggestion: start with the things we have rather than the
wrappers. It would be great to have a chart with the first column being
API group (eg. "all interfaces derived from nsISupports"), and the
operations that can move you to different wrappers (.wrappedJSObject),
and the consequences. Using the X words to group and refer to aspects of
the chart would be fine. But this way the X words are defined in terms
of objects we have, rather than vice versa (which we can't see).

jjb

Blake Kaplan

unread,
Feb 18, 2009, 1:44:22 PM2/18/09
to
Benjamin Smedberg <benj...@smedbergs.us> wrote:
> Can you give an example of how a chrome-only wrapper would come into play?

Native anonymous content is the only example I have right now. We could also
further extend the native anonymous content wrappers to allow modifying
certain properties.
--
Blake Kaplan

Dan Mosedale

unread,
Feb 18, 2009, 2:23:34 PM2/18/09
to
On 2/18/09 10:54 AM, John J. Barton wrote:
> Blake Kaplan wrote:
>> John J. Barton <johnj...@johnjbarton.com> wrote:...
>>
>>> I think my best advice is to try to write the documentation without
>>> ever using any word that starts with a capital 'X', because we don't
>>> see those when working in javascript. (Except in the error messages,
>>> but I won't go there).
>>
>> I'll give this a shot, but as I've said, I think that having a
>> vocabulary for
>> talking about the different types of wrappers is useful.
>
> So another suggestion: start with the things we have rather than the
> wrappers. It would be great to have a chart with the first column being
> API group (eg. "all interfaces derived from nsISupports"), and the
> operations that can move you to different wrappers (.wrappedJSObject),
> and the consequences. Using the X words to group and refer to aspects of
> the chart would be fine. But this way the X words are defined in terms
> of objects we have, rather than vice versa (which we can't see).

This feels like it might be useful. To me the real issue is that it
feels like there's quite a lot of complexity here, and as soon as I wade
into wrapper territory, I feel like in order to really understand all
the details, a fair amount of investment of time would be required. Now
maybe this is actually a good thing, in the sense that we've got a
complex system here, and pretending that it's simple could provide a
false sense of security/control. That said, perhaps there are ways to
factor the complexity so that it's easier to think about more coarsely.

Dan

Blake Kaplan

unread,
Feb 18, 2009, 3:21:23 PM2/18/09
to
Dan Mosedale <dm...@mozilla.org> wrote:
> This feels like it might be useful. To me the real issue is that it
> feels like there's quite a lot of complexity here, and as soon as I wade
> into wrapper territory, I feel like in order to really understand all
> the details, a fair amount of investment of time would be required. Now

Where does this complexity come in? My hope with the wrappers that we have was
that for most uses, they would do the Right Thing (TM). Namely, if you have
some content DOM object and want to manipulate it in some way (add children,
remove children, etc) then the default wrapper (XPCNativeWrapper) would be the
right thing. Then, if you want to interact with the underlying object (call
some content-defined function), there's an escape valve in the form of
.wrappedJSObject that still doesn't open you to attack.

> maybe this is actually a good thing, in the sense that we've got a
> complex system here, and pretending that it's simple could provide a
> false sense of security/control. That said, perhaps there are ways to
> factor the complexity so that it's easier to think about more coarsely.

No matter what, there will be complexity here. Security is hard, no matter
what system you're using and we're using a system based on JavaScript, which
has very few real invariants that hold in the face of an attacker.

For what it's worth, I think of our security system like this:

In JS, there are a set of scopes with different privileges (principals). If
two scopes that have different privileges want to touch each other, then we
have to create wrapper objects to meter the access between the scopes. In
principal, we care about two different types of scopes:

1. chrome (browser, extensions)
2. content (web pages)

Content cannot touch chrome. Currently (without what I called
XPCUnsafeJSObjectWrapper) this must always hold true.

When chrome
--
Blake Kaplan

Blake Kaplan

unread,
Feb 18, 2009, 4:06:31 PM2/18/09
to
Oops, hit the wrong button.

Blake Kaplan <mrb...@gmail.com> wrote:
> For what it's worth, I think of our security system like this:
>
> In JS, there are a set of scopes with different privileges (principals). If
> two scopes that have different privileges want to touch each other, then we
> have to create wrapper objects to meter the access between the scopes. In
> principal, we care about two different types of scopes:
>
> 1. chrome (browser, extensions)
> 2. content (web pages)
>
> Content cannot touch chrome. Currently (without what I called
> XPCUnsafeJSObjectWrapper) this must always hold true.
>
> When chrome

... touches content, it starts out at a boundary that goes through an
IDL-interface (usually nsIDOMWindow or kin). From there, it wants one of two
things:

1. The behavior of the object that it has corresponds to the IDL interface.
So window.open() opens a new window, or document.title corresponds to the
document's title. [This corresponds to XPCNativeWrapper].
2. The web page has modified its objects in some way (adding properties,
objects, functions) and the extension wants to use those properties.
[This corresponds to XPCSafeJSObjectWrapper (i.e.
XPCNativeWrapper.wrappedJSObject)].

In both of those cases, the extension should be able to access the properties
without worry that the content page can simply execute code using the
extension's privileges.

Now, it's still possible for an extension to shoot itself in the foot. If it
does |eval(contentWindow.document.title)| then if the title contains
"alert(Components.stack)", the extension will be exploited.

The reason that I tell people to be careful when using .wrappedJSObject is
because something as simple as |var x =
contentWindow.wrappedJSObject.document.location| could throw or return any
string (not even necessarily a valid URL). Your only guarantee is that the
simple act of accessing the document and its location won't exploit your
extension.

XPConnect takes care of the wrapping for you, so chrome code touching content
should be able to make the decision about whether it wants case 1 or 2 and
proceed from there.

Does this make sense? Is it helpful? What am I missing that could make this
more clear?
--
Blake Kaplan

John J Barton

unread,
Feb 18, 2009, 4:17:06 PM2/18/09
to
Blake Kaplan wrote:
...

> For what it's worth, I think of our security system like this:
>
> In JS, there are a set of scopes with different privileges (principals). If

But here again we have the problem that in JS code we don't have access
to these things you talk about. We don't have a set of scopes,
privileges or principals. We have a 'window' and some function calls
that give us access to other window object, typically through a long and
puzzling change of calls. Given that starting point it is very difficult
to make connection to discussions that talk about principals etc.

It would be great if the platform API revealed the principal/privileges
of a scope.

jjb

Boris Zbarsky

unread,
Feb 18, 2009, 4:21:26 PM2/18/09
to
John J Barton wrote:
> It would be great if the platform API revealed the principal/privileges
> of a scope.

We expose the nodePrincipal on documents and elements. I suppose we
could support something like that (or even just that property name too)
on Windows, when accessed from chrome.

-Boris

Blake Kaplan

unread,
Feb 18, 2009, 5:34:04 PM2/18/09
to
John J Barton <johnj...@johnjbarton.com> wrote:
> It would be great if the platform API revealed the principal/privileges
> of a scope.

I don't think this API would be nearly as useful as you think. At the end of
the day, you'll still have a window object and a bunch of function calls.

There isn't really an explicit place where you will say "that is in another
scope, give me a wrapper for it," it's more of a situation where you'll access
a property on some object and the returned object will happen to be from
another scope (good things to look out for are "contentWindow" and "content",
but there might be other names that end up crossing scopes).
--
Blake Kaplan

Johnny Stenback

unread,
Feb 18, 2009, 6:57:00 PM2/18/09
to
I know I'm to blame for some of the grumbling, and I'm also probably
largely to be blamed for at least some of the reasons behind the
grumbling :). I think most of this is rooted in two things, those being
wrapper naming and implementation complexity. Naming of these wrappers
started out bad and only got worse (and I certainly did my share to get
us where we are), and I honestly don't know if we can do much about that
any more, as I can see extensions might depend on what toString()
returns etc for various reasons. And by implementation complexity I mean
the complexity in intermally ensuring they do what they need to do and
they're created where they need to be used. The biggest part of that
burden has of course been on your shoulders. As for that complexity, I
think it's largely unavoidable, whether we use wrappers or something
else. It's a hard thing to get right w/o sacraficing plenty no matter
what approach you take.

As for some of the other complexity related issues that have been
discussed in this thread, some of that is probably bugs, other parts are
hard or goofy due to historic reasons, especially wrt XPCNativeWrapper
(whose name is most confusing of all, and also carries the largest
history burden of all wrappers).

But I will say that I can't think of a single case where a web developer
has complained that our XOWs have interoduced any complexity at all. And
while XOWs are no trivial thing under the covers, their benefits
outwheigh their complexity by orders of magnitude IMNSHO.

All n' all, I say keep wrapping! :)


--
jst

Jonas Sicking

unread,
Feb 18, 2009, 10:06:43 PM2/18/09
to
I largely agree with jst. Based on my own experience, and the ones I
hear in these threads it sounds like the following things are problems:

1. Documentation!
We can probably do a lot better here. However I think just telling
mrbkap to write better docs are going to do little to improve them. We
need the input from the people that are reading the docs.

If anything is unclear, ask for clarification and then update the docs.
This is why we have wikis. If the problems are on an "architectural"
level, such as being written from the point of view of the wrapper
developer rather than the wrapper user, suggest improvements.

I don't think this problem is specific to wrappers. It's entirely
possible that whatever we'd do to replace wrappers would end up with
exactly the same API, so this is unaffected by the fact that we're using
wrappers.

2. Complexity
In some cases I think we've made things unnecessarily hard on ourselves.
I think we should be less afraid of breaking existing code for the
purpose of simplifying the world for everyone. One example might be the
ability to opt out of XPCNativeWrappers which is causing headaches in
the implementation and documentation. Another is getting rid of the
UniversalXPConnect mess.

3. Too many wrappers
If we really need all these types of wrappers there's not much to do.
This sort of comes back to the same root as 2; we shouldn't be afraid to
break stuff, or not support stuff, if it adds too many wrappers that
introduce too much complexity.

Another thing that we might want to consider is if changes can be done
to the JS engine to remove the need for some types of wrappers, or allow
them to do less.


In general I feel like wrappers is in general the way to go. Reducing
complexity is always something we should keep an eye out for. Even when
that means breaking existing code or making architectural changes, such
as to the JS engine. But as long as we're doing that (and I think we
are), I think we're on the right track.


Just don't touch nested <script> parsing again!

/ Jonas

sayrer

unread,
Feb 18, 2009, 11:11:22 PM2/18/09
to
On Feb 18, 4:06 pm, Blake Kaplan <mrb...@gmail.com> wrote:
>
> Now, it's still possible for an extension to shoot itself in the foot. If it
> does |eval(contentWindow.document.title)| then if the title contains
> "alert(Components.stack)", the extension will be exploited.
>
> The reason that I tell people to be careful when using .wrappedJSObject is
> because something as simple as |var x =
> contentWindow.wrappedJSObject.document.location| could throw or return any
> string (not even necessarily a valid URL). Your only guarantee is that the
> simple act of accessing the document and its location won't exploit your
> extension.

I fully support any modifications or additions to wrappers that you
want to do in the short term. In the long term, the model you describe
above must be improved.

It looks to me like "wrappers" could be a poor abstraction for the
task at hand, and making harmless looking JS safe in extensions calls
for disjoint JS heaps and scope chains.

- Rob

John J. Barton

unread,
Feb 19, 2009, 12:02:26 AM2/19/09
to
Blake Kaplan wrote:
...

>
> The reason that I tell people to be careful when using .wrappedJSObject is
> because something as simple as |var x =
> contentWindow.wrappedJSObject.document.location| could throw or return any
> string (not even necessarily a valid URL). Your only guarantee is that the
> simple act of accessing the document and its location won't exploit your
> extension.

This part I don't get. What is the significance of "any string"? Why
should I be careful?

>
> Does this make sense? Is it helpful? What am I missing that could make this
> more clear?

Much clearer. The part that is less clear is
When chrome touches content
How can we know? I guess there are only a few calls that give you the
outermost "touches content", eg window object from certain API calls. It
would be very helpful to know exactly what that list was.

jjb

John J. Barton

unread,
Feb 19, 2009, 12:07:32 AM2/19/09
to
Blake Kaplan wrote:
> John J Barton <johnj...@johnjbarton.com> wrote:
>> It would be great if the platform API revealed the principal/privileges
>> of a scope.
>
> I don't think this API would be nearly as useful as you think. At the end of
> the day, you'll still have a window object and a bunch of function calls.

Actually we have two window objects in all of these cases, 'window' and
some object, say 'win' from a call. So is 'win' mine or no? If I have
win and context.windows[] is win the same principal as any windows[i]?
When I get a security error, how do I diagnose it?

These are the cases were principal would help.

jjb

Boris Zbarsky

unread,
Feb 19, 2009, 12:03:21 AM2/19/09
to
John J. Barton wrote:
>> The reason that I tell people to be careful when using
>> .wrappedJSObject is
>> because something as simple as |var x =
>> contentWindow.wrappedJSObject.document.location| could throw or return
>> any
>> string (not even necessarily a valid URL).
>
> This part I don't get. What is the significance of "any string"? Why
> should I be careful?

If you expect to actually get back the document's location, then the
above code does NOT guarantee that. It allows the site loaded in
contentWindow to completely control the string you get, and as Blake
points out the getter could also just throw, completely under the
control of the site.

How careful you then need to be depends on what you're using the string
for. If you're using it for security checks, say, you just lost.

> Much clearer. The part that is less clear is
> When chrome touches content
> How can we know? I guess there are only a few calls that give you the
> outermost "touches content", eg window object from certain API calls. It
> would be very helpful to know exactly what that list was.

That's an unanswerable question given the levels of indirection
involved... There are various tabbrowser/browser APIs that hand back
content objects in various ways. There's window.content. There's
examining the target of context menus or tooltips. There are various
functions people might be using which might call any of the above.
There are event targets and originalTargets of events that propagate
into chrome.

To a first approximation, assuming you never rely on any code but
standard XBL bindings, the above list is it. I think. I bet I missed
something.

-Boris

Mook

unread,
Feb 19, 2009, 2:12:04 AM2/19/09
to
As a consumer of the platform, please:

Let us know!

Most importantly, please _announce_ these things! I don't recall any
mentions of XOWs coming into existence, that it's now magically safe to
use .wrappedJSObject (it used to be completely unsafe; now at least it's
just don't trust your inputs). If we don't know about it, we can't
usefully comment on anything, except to complain about why things no
longer work (possibly because it now works better but we didn't know
about it) and if it's related to this odd-looking toString(). Blog it;
have it on devnews; have announcements right here. (Do all three, not
just one.)

These wrappers are a key part of the API (since everybody who ever does
anything use them); even if the documentation isn't clear, knowing that
something changed means we can at least know to ask questions. People
can adapt to API changes when it's clear what they are. Mostly while
grumbling, of course :)

The fact that this thread exists is a very good sign :) I wish all
other API changes had at least that...

--
Mook
(eyes glazing up as the word "wrapper" shows up way too often...)

Neil

unread,
Feb 19, 2009, 6:01:44 AM2/19/09
to
Boris Zbarsky wrote:

> Neil wrote:
>
>> And if you have an XPCWrappedNative then you can't set expando
>> properties at all
>
> Er... that's not true. What makes you say that? I bet you set
> expando properties on XPCWrappedNatives for DOMNodes all the time!

Yeah, OK, so I overlooked that special case...

>> When the login manager calls back into navigator.js it passes us an
>> [XPCNativeWrapper [object Window]] but when the login manager's tests
>> call us they only have an [object Window] so we have to deal...
>
> That sounds odd. Why is that happening? Is one window chrome while
> the other is content?

Well, login manager is a component; I'm not sure how the tests run, but
probably a chrome or privileged URL in a content docshell, yes.

--
Warning: May contain traces of nuts.

Neil

unread,
Feb 19, 2009, 6:06:50 AM2/19/09
to
Blake Kaplan wrote:

>Writing good documentation is hard
>
Sounds like a job for a PhD student; it would be their wrapping paper ;-)

Boris Zbarsky

unread,
Feb 19, 2009, 9:25:34 AM2/19/09
to
Neil wrote:
> Well, login manager is a component; I'm not sure how the tests run, but
> probably a chrome or privileged URL in a content docshell, yes.

What are the test filenames?

-Boris

Neil

unread,
Feb 19, 2009, 10:29:52 AM2/19/09
to
Boris Zbarsky wrote:

I think the first one that failed was
toolkit/components/passwordmgr/test/test_notifications.html

Boris Zbarsky

unread,
Feb 19, 2009, 10:56:56 AM2/19/09
to
Neil wrote:
> I think the first one that failed was
> toolkit/components/passwordmgr/test/test_notifications.html

OK. This test is just badly written. It's running as a mochitest, but
depending on details of the Firefox chrome, and running code that would
normally run as chrome with UniversalXPConnect from content.

Don't do that.

-Boris

John J. Barton

unread,
Feb 19, 2009, 12:02:53 PM2/19/09
to
Mook wrote:
...

> Most importantly, please _announce_ these things! I don't recall any
> mentions of XOWs coming into existence, that it's now magically safe to
> use .wrappedJSObject (it used to be completely unsafe; now at least it's
> just don't trust your inputs). If we don't know about it, we can't ...

+1. We made a significant design decision in part because we thought
along these lines:
wrappers give you security,
wrapper.wrappedJSObject means you are unwrapped,
unwrapped is insecure.
Thus: you can't manipulate web pages based on wrapper.wrappedJSObject
jjb

0 new messages