XPConnect Chrome Object Wrappers: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(simplified explanation)
m (__exposedProps__ should use colon, not equal sign)
 
(19 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{draft}}
== Current Status ==
COWs landed on mozilla-central at the end of September 2009. They were also approved for Gecko 1.9.2 (Firefox 3.6) and landed on its trunk on October 6, 2009.
As of October 16, 2009, however, it is still not possible for chrome-privileged script to create COWs—that is, COWs still need to be automatically created when passing through a trust boundary.  Furthermore, there are a number of TODOs in this specification that are still in the process of being resolved. All of these are currently considered bugs in the implementation, and any fixes to them will automatically propagate to Firefox 3.6.
== Introduction ==
== Introduction ==


Line 7: Line 15:
== Usage ==
== Usage ==


COWs are always created automatically whenever an object passes through a trust boundary. For instance, assume the following chrome-privileged code:
COWs are always created automatically as necessary whenever an object passes through a trust boundary. This is in keeping with the philosophy that "the default should be secure": if writing secure code is optional, developers are burdened because they always need to ''remember'' how to write securely.
 
Also in keeping with this philosophy, however, is the notion that we don't want to expose chrome data or functionality to untrusted code unless the developer explicitly provides permission to do so. This is lexically enforced through the use of metadata, as will be shown shortly.
 
=== COWing Functions ===
 
Assume the following chrome-privileged code:


<pre class="brush:js;">
<pre class="brush:js;">
const Cu = Components.utils;
const Cu = Components.utils;
function foo(obj) {
  /* Do something here that requires chrome privileges. */
}


var sandbox = Cu.Sandbox("http://www.mozilla.org");
var sandbox = Cu.Sandbox("http://www.mozilla.org");
sandbox.foo = Cu.exposeToContent(function foo(x) { /* ... */ });
sandbox.foo = foo;
var result = Cu.evalInSandbox("foo({bar: 5});");
var result = Cu.evalInSandbox("foo({bar: 5});", sandbox);
</pre>
</pre>


In the above example, <tt>foo()</tt> is wrapped by a COW when accessed by sandboxed code executed via <tt>Components.utils.evalInSandbox()</tt>.  The object <tt>{bar: 5}</tt> is wrapped in an <tt>XPCSafeJSObjectWrapper</tt> before being passed into <tt>foo()</tt>.
In the above example, <tt>foo()</tt> is wrapped by a COW when accessed by sandboxed code executed via <tt>Components.utils.evalInSandbox()</tt>.  The object <tt>{bar: 5}</tt> is wrapped in an <tt>XPCSafeJSObjectWrapper</tt> before being passed into <tt>foo()</tt>.
=== COWing Objects ===
By default, non-function Chrome objects passed into content space are completely opaque: no information can be accessed from them, and no properties can be defined on them.
When a non-writable property is written to, a security exception will be raised. However, when a non-readable property is accessed, its value is <tt>undefined</tt>: a security exception isn't thrown because we don't want to break code that relies on [http://en.wikipedia.org/wiki/Duck_typing duck typing].
To bypass this default behavior, individual properties can be exposed by defining a <tt>__exposedProps__</tt> property on the object, like so:
<pre class="brush:js;">
const Cu = Components.utils;
var MyObj = {
  __exposedProps__: {foo: "r", bar: "rw"},
  foo: function foo(obj) {
    /* Do something here that requires chrome privileges. */
  },
  bar: "supdog",
  baz: "I am protected information"
}
</pre>
In the above example, <tt>MyObj.foo()</tt> can be accessed but not assigned to, <tt>foo()</tt> itself is callable from content, and <tt>MyObj.bar</tt> is both readable and writable, while <tt>MyObj.baz</tt> can't be accessed at all.
All properties that are exposed to content are enumerable by content as well.
Getters and setters on exposed properties are automatically called as necessary.
If an exposed property is writable by content, it is deletable by content as well.
'''TODO:''' What should the default <tt>toString()</tt> method of a COW'ed object with no metadata yield?
'''TODO:''' Discuss what to do with native objects that get exposed (like the Sidebar object).
== Compliance Tests ==
A suite of compliance tests for the metadata functionality of COWs can be found at:
  http://hg.mozilla.org/users/avarma_mozilla.com/cow-exposed-info/
This suite uses the JSAPI, and is independent of XPCOM and XPConnect.
== Related Patches ==
A Mercurial patch queue containing an in-progress COW test suite that patches against mozilla-central can be found here:
  http://hg.mozilla.org/users/avarma_mozilla.com/cow-patches/
== Related Bugzilla Bugs ==
* [https://bugzilla.mozilla.org/show_bug.cgi?id=518991 518991 - COWs should only expose certain properties]
* [https://bugzilla.mozilla.org/show_bug.cgi?id=522764 522764 - COWs need tests]

Latest revision as of 19:15, 20 August 2012

Draft-template-image.png THIS PAGE IS A WORKING DRAFT Pencil-emoji U270F-gray.png
The page may be difficult to navigate, and some information on its subject might be incomplete and/or evolving rapidly.
If you have any questions or ideas, please add them as a new topic on the discussion page.

Current Status

COWs landed on mozilla-central at the end of September 2009. They were also approved for Gecko 1.9.2 (Firefox 3.6) and landed on its trunk on October 6, 2009.

As of October 16, 2009, however, it is still not possible for chrome-privileged script to create COWs—that is, COWs still need to be automatically created when passing through a trust boundary. Furthermore, there are a number of TODOs in this specification that are still in the process of being resolved. All of these are currently considered bugs in the implementation, and any fixes to them will automatically propagate to Firefox 3.6.

Introduction

Chrome Object Wrappers, or COWs for short, allow privileged code to securely expose some subset of its functionality to untrusted or semi-trusted content.

The COW is actually the final step in an epic quest to make the interaction between chrome and content as natural and secure as possible by encasing JavaScript objects in "membranes" that mediate access between their object and the outside world. Before reading the rest of this document, you should be familiar with the story so far, which is explained in detail at XPConnect wrappers.

Usage

COWs are always created automatically as necessary whenever an object passes through a trust boundary. This is in keeping with the philosophy that "the default should be secure": if writing secure code is optional, developers are burdened because they always need to remember how to write securely.

Also in keeping with this philosophy, however, is the notion that we don't want to expose chrome data or functionality to untrusted code unless the developer explicitly provides permission to do so. This is lexically enforced through the use of metadata, as will be shown shortly.

COWing Functions

Assume the following chrome-privileged code:

const Cu = Components.utils;

function foo(obj) {
  /* Do something here that requires chrome privileges. */
}

var sandbox = Cu.Sandbox("http://www.mozilla.org");
sandbox.foo = foo;
var result = Cu.evalInSandbox("foo({bar: 5});", sandbox);

In the above example, foo() is wrapped by a COW when accessed by sandboxed code executed via Components.utils.evalInSandbox(). The object {bar: 5} is wrapped in an XPCSafeJSObjectWrapper before being passed into foo().

COWing Objects

By default, non-function Chrome objects passed into content space are completely opaque: no information can be accessed from them, and no properties can be defined on them.

When a non-writable property is written to, a security exception will be raised. However, when a non-readable property is accessed, its value is undefined: a security exception isn't thrown because we don't want to break code that relies on duck typing.

To bypass this default behavior, individual properties can be exposed by defining a __exposedProps__ property on the object, like so:

const Cu = Components.utils;

var MyObj = {
  __exposedProps__: {foo: "r", bar: "rw"},

  foo: function foo(obj) {
    /* Do something here that requires chrome privileges. */
  },

  bar: "supdog",

  baz: "I am protected information"
}

In the above example, MyObj.foo() can be accessed but not assigned to, foo() itself is callable from content, and MyObj.bar is both readable and writable, while MyObj.baz can't be accessed at all.

All properties that are exposed to content are enumerable by content as well.

Getters and setters on exposed properties are automatically called as necessary.

If an exposed property is writable by content, it is deletable by content as well.

TODO: What should the default toString() method of a COW'ed object with no metadata yield?

TODO: Discuss what to do with native objects that get exposed (like the Sidebar object).

Compliance Tests

A suite of compliance tests for the metadata functionality of COWs can be found at:

 http://hg.mozilla.org/users/avarma_mozilla.com/cow-exposed-info/

This suite uses the JSAPI, and is independent of XPCOM and XPConnect.

Related Patches

A Mercurial patch queue containing an in-progress COW test suite that patches against mozilla-central can be found here:

 http://hg.mozilla.org/users/avarma_mozilla.com/cow-patches/

Related Bugzilla Bugs