ES1-3 eval-created function bindings can be used to destroy caller bindings

Brendan Eich brendan at mozilla.com
Thu Feb 12 11:45:31 PST 2009


ES3 10.1.3 says:

"For each FunctionDeclaration in the code, in source text order,  
create a property of the variable object whose name is the Identifier  
in the FunctionDeclaration, whose value is the result returned by  
creating a Function object as described in section 13, and whose  
attributes are determined by the type of code. If the variable object  
already has a property with this name, replace its value and  
attributes. Semantically, this step must follow the creation of  
FormalParameterList properties."

But in eval code this is a botch, since it requires

function foo(a, s) {
   var x = a * a;
   eval(s);
   return x;
}
alert(foo(2, "function x() { return 'ha ha!'; }"));

to alert the function x's toString results.

Still, the spec is clear enough, and Firefox 3 (not 2 or earlier),  
Safari, and Opera all agree (I can't test IE atm).

ES3.1 changes the rules to use CreateMutableBinding when entering the  
eval execution context only if x is not already bound, and in any case  
then to call SetMutableBinding (10.2.1.2.3 in the feb09 draft).  
SetMutableBinding calls [[ThrowingPut]]. Strict mode adds value in its  
own way but let's assume it's not used in the following.

The change in spec between 3 and 3.1 does not affect the outcome for  
the example above, but changing the attributes of x before the eval  
call, or giving it a setter somehow (the native implementation might  
use some kind of internal setter, depending on how it handles eval and  
function activations), would make a big difference: the old spec says  
to blow away any pre-existing x including its attributes, getter, and  
setter.

The new 3.1 language would respect the attributes and call the setter.  
And 3.1 Object.defineProperty, etc., lets users define setters on  
objects they can reference.

Since the activation object is censored, the issue becomes function  
foo in global code, not var or function x in function code. Code on  
the web today can count on a function declaration being processed from  
global code (and possibly from eval from global code, depending on the  
implementation) so that any pre-existing writable binding of the same  
name is destroyed. This gives some integrity that otherwise can't be  
recovered.

With ES3.1, programmers will have to use  
Object.getOwnPropertyDescriptor(this, 'foo') and check first to avoid  
spoofing and luring attacks via setters. If an unwanted foo pre- 
exists, the code can work around the name conflict or try to delete  
that foo.

A pre-existing non-writable (const) property is not a threat (except  
of the trivial DOS kind), and indeed Firefox throws an error given  
const foo = 42; (in its own script tag or earlier in the same one as  
function foo shown above) and then function foo(){...}. Silent failure  
to update foo would be inferior, but better than recreating foo and  
violating the integrity of const.

The problem is setters (and getters) on the global object combined  
with the change to function binding, from re-creation to conditional  
creation followed by assignment. I can't prove this is going to burn  
programmers in the future, but I suspect it will. Anway, it is a big  
enough change from ES3 and implementation behavior -- for global code  
at least -- that I wanted to bring it up for discussion here.

/be


More information about the Es-discuss mailing list