Archive for September 12th, 2012

Security Checks and enablePrivilege in Gecko, part 1

September 12th, 2012 | Category: enableprivilege

Who cares?

The imminent death of enablePrivilege has brought a few angry web application developers into Bugzilla, and they’re quite rightly demanding to know why we’re removing a very powerful tool from their toolbox. While Jonas has responded to them, I thought it might be interesting to expound on the performance aspect of enablePrivilege removal. In order to understand the impact, let’s take a walk down the history of how security checks were implemented in Gecko.

First, bindings

The history of JS security checks in Gecko is very tightly coupled with the history of the bindings that allow JS to C++ communication. The first DOM bindings in Gecko were auto generated from the IDL for each element type by a program that only ran on Windows. The generated bindings would then do the proper forwarding to C++ and automatically convert the result to JS. Because there was no single point of entry going from JS to C++, the code generator had to insert security checks (more on that later) at each entry point. As a side note, looking at the old generated code, we actually forgot to security check accesses to unknown properties (called “expandos”), which would be considered a serious security bug these days. In addition to the security check that verified that a given method call was allowed at all, each DOM method had to check that the operation was permitted on all of the arguments passed to it as well.

In 2001, jst, jband, and peterv landed a massive project called “XPCDOM.” This got rid of the megabytes worth of generated code in favor of using XPConnect’s generic JS to C++ bridge. Because XPConnect has a single point of transit between JS and C++, this allowed us to have a single security check guarding all calls from JS to C++. This single check was, as before, supplemented by additional checks in C++ to verify the validity of the arguments passed in as well as additional checks in the JS engine to catch tricky edge cases that didn’t go directly through C++, but instead stayed in JS (and the engine).

So, what are these “security checks”

I believe that Gecko’s original security model was designed with Java 1’s security model in mind. The main idea of this model is that, at any point in time, it must be possible to inspect the currently running code to ask it what permissions it has and to assign a permission level for every object in the system. In order to perform the former operation, the JS engine exposed a “stack walking” API, which allowed us to write code that walked up the JS stack, asking each stack frame what permissions it had. For the latter operation, we had another (expensive) method of asking every object what permissions it had. Comparing the two permissions gave us our result.

What does this have to do with enablePrivilege?

The semantics of enablePrivilege seen without this context are odd: given a JS stack frame, a call to enablePrivilege elevates the privileges of that stack frame (and any functions it calls) and then returns to normal privileges once that stack frame returns. Knowing how security checks were implemented, however, it makes complete sense. Because the ability to assign privileges to running code depended on the ability to walk the JS stack, annotating stack frames with the information “has called enablePrivilege” and then later (if a security check was about to fail) asking “by the way, do any stack frames have this additional privilege?” was a natural and easy implementation.

Up next: the problems

We’re currently in the process of changing how all of this works, so clearly the solutions presented here were found lacking. So, up next: what’s happening now, and why.

Comments are off for this post