|
ArgumentsExposesCaller
Reflective call stack traversal leaks references.
arguments Array and function object expose callerEffectAn untrusted function can steal a reference to a trusted caller function which it can later invoke. Backgroundhttp://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Function:call describes both caller and the caller property of Functions. The members of function objects are described in EcnaScript 262 Section 15.3.5. In addition to these, many implementations expose properties caller, and __caller__. Many implementations also expose caller as part of the arguments Array. AssumptionsUntrusted code can call a trusted function to escalate privileges if it holds a reference to it. Untrusted code can access the currently executing function. This can normally be done at runtime via arguments.callee. Calls of untrusted functions are not passed through a launderer function which recurses to itself as in function launderer(fn, varargs) {
if (arguments.caller !== arguments.callee) {
arguments.callee.apply(this, arguments);
} else {
arguments[0].apply(
this, [].splice.call(arguments, 1, arguments.length));
}
}This laundering scheme does not work if __caller__ is exposed. __caller__ was removed from Firefox. VersionsAt least on FF and IE. Only old versions of Firefox expose __caller__ Examplefunction untrusted() {
alert('got function ' + untrusted.caller + ' : '
+ arguments.callee.caller.arguments[0]);
}
(function trusted() { untrusted(); })(4);
|
Sign in to add a comment
The second instance was probably meant to be "callee".
Actually, the second "caller" was supposed to be __caller__ (note the underscores), but wiki markup uses underscores to delimit italicized regions.
Thanks for pointing that out.
I do not see why exposing caller is any different than exposing caller. Certainly using array access to object data will allow access to a "caller" field.
The launderer makes sure that the caller of the function is itself, so if you try to follow arguments.callee.caller.caller.caller... you get stuck in an infinite loop.
I believe the difference between __caller__ and caller is that the former is an "activation object" (a proxy fr a call-stack frame) whereas the latter is a function.