Last Comment Bug 363891 - Indirect use of eval can run code with the wrong principal.
: Indirect use of eval can run code with the wrong principal.
Status: RESOLVED FIXED
[sg:critical]
: arch, testcase, verified1.8.1.13
Product: Core
Classification: Components
Component: JavaScript Engine (show other bugs)
: Trunk
: All All
: -- normal (vote)
: ---
Assigned To: Blake Kaplan (:mrbkap)
:
Mentors:
Depends on: 382509
Blocks: 369211 js1.8
  Show dependency treegraph
 
Reported: 2006-12-14 16:12 PST by Johnny Stenback (:jst, jst@mozilla.com)
Modified: 2013-03-26 08:02 PDT (History)
18 users (show)
mconnor: blocking1.9+
dveditz: blocking1.8.1.13+
dveditz: wanted1.8.1.x+
asac: blocking1.8.0.next+
dveditz: wanted1.8.0.x+
choller: in‑testsuite-
See Also:
Crash Signature:
(edit)
QA Whiteboard:
Iteration: ---
Points: ---
Has Regression Range: ---
Has STR: ---


Attachments
Patch per initial comment. (1.93 KB, patch)
2006-12-14 16:15 PST, Johnny Stenback (:jst, jst@mozilla.com)
no flags Details | Diff | Splinter Review
More like this (1.79 KB, patch)
2007-04-10 13:28 PDT, Blake Kaplan (:mrbkap)
brendan: review-
Details | Diff | Splinter Review
Updated patch (2.65 KB, patch)
2007-04-10 19:36 PDT, Blake Kaplan (:mrbkap)
no flags Details | Diff | Splinter Review
Best fix yet (5.73 KB, patch)
2007-05-24 15:53 PDT, Blake Kaplan (:mrbkap)
brendan: review+
Details | Diff | Splinter Review
What's ready to be checked in (4.57 KB, patch)
2007-05-30 11:31 PDT, Blake Kaplan (:mrbkap)
no flags Details | Diff | Splinter Review

Comment 1 Johnny Stenback (:jst, jst@mozilla.com) 2006-12-14 16:15:37 PST
Created attachment 248695 [details] [diff] [review]
Patch per initial comment.
Comment 2 Brendan Eich [:brendan] 2006-12-14 16:18:11 PST
Man, I want to ban indirect eval (except for w.eval(s) for a window object w, or whatever the global class is in a non-DOM embedding).

/be
Comment 5 chris hofmann 2007-03-01 13:44:45 PST
is the patch any good, or should we be going with brendan's idea in comment 2 ?
Comment 6 Johnny Stenback (:jst, jst@mozilla.com) 2007-03-27 17:30:16 PDT
The patch is no good (or not good enough), so we'll need to go with brendan's idea.

IOW, we'll want to limit eval to being callable on global objects, and ideally also to being only callable directly (i.e. window.foo = window.eval; window.foo() should fail, at least from chrome). Brendan says the JS 2 spec already limits eval() similarly to this.

I'll be out of the country for a week starting tomorrow and won't be of much help on this issue right now. mrbkap or brendan, can you guys have a stab at this problem?
Comment 7 Blake Kaplan (:mrbkap) 2007-03-27 17:47:36 PDT
I could take a stab at this on Friday.
Comment 8 Blake Kaplan (:mrbkap) 2007-04-10 13:28:46 PDT
Created attachment 261181 [details] [diff] [review]
More like this

So, does this do the trick?
Comment 9 Blake Kaplan (:mrbkap) 2007-04-10 16:20:37 PDT
(In reply to comment #6)
> IOW, we'll want to limit eval to being callable on global objects, and ideally
> also to being only callable directly (i.e. window.foo = window.eval;
> window.foo() should fail, at least from chrome). Brendan says the JS 2 spec
> already limits eval() similarly to this.

So, what about cases like bug 320172, where eval is being used (mildly incorrectly) as an argument to Array.forEach. Granted, this is an edge case, but it is out there in the wild (or, at least, it was). If we do want to enforce this, then I think the easiest way would be to disallow using "eval" in a non-call context.
Comment 10 Brendan Eich [:brendan] 2007-04-10 18:05:36 PDT
Comment on attachment 261181 [details] [diff] [review]
More like this

>+    uintN flags;

Block local and initialized.

>     fp = cx->fp;
>     caller = JS_GetScriptedCaller(cx, fp);
>     JS_ASSERT(!caller || caller->pc);
>     indirectCall = (caller && *caller->pc != JSOP_EVAL);

We talked about fixing the emitter to choose JSOP_EVAL for o.eval as well as eval (pn_arity == PN_NAME instead of pn_op == JSOP_NAME before the pn_atom == evalAtom test). We must allow o.eval if o is a window object, which the OBJ_GET_PARENT(cx, obj) != NULL below allows -- but that also allows w.evil = eval, which we don't want to support.

So use JSOP_EVAL as the first filter, to throw out any calls to a function or method named anything but eval.

The second filter is to make any obj_eval activation whose |obj| (|this|) parameter is not a global object be an indirectCall.

mrbkap pointed out the good use-case of Array.map(arraylike, eval). To make that work, we must stop using JS_GetScriptedCaller, and add special-case code to recognize good native trampoline frames such as the one for array_extra.

/be
Comment 11 Blake Kaplan (:mrbkap) 2007-04-10 19:36:01 PDT
Created attachment 261207 [details] [diff] [review]
Updated patch

So, this fixes brendan's comments, but see the big XXX. We can't allow seemingly benign Array.map(..., eval) because it undoes the advantage of the rest of the fix. brendan says he'll take the issue up with ECMA.
Comment 12 Igor Bukanov 2007-04-11 02:28:58 PDT
This bug reminds about a similar problem with Java and its ClassLoader (Java version of eval). There was bug at least until JDK 1.4 that effectively allowed to gain all permissions as long as code was allowed to use ClassLoader. The reason was that the runtime did not impose dynamic restrictions according to the current stack on the code generated using ClassLoader. So when the generated code was called with only system code on the stack, it run with all permissions.
Comment 13 Johnny Stenback (:jst, jst@mozilla.com) 2007-04-19 18:22:13 PDT
Since we're making eval() not callable off of a non-global object, shouldn't we then also make it so that obj.eval is only defined on global objects as well? I mean what's the point of exposing that function (which IE never exposed) if it's never callable? If we'd remove eval from non-global objects then an unqualified eval() call scoped at a non-global object would continue to work, whereas if we don't do that we'd find eval() in the current scope and we'd fail to do the eval, no?
Comment 14 Blake Kaplan (:mrbkap) 2007-04-20 22:18:08 PDT
Ah, true. I wonder if we should resolve it in JS_ResolveStandardClass and take it off of Object.prototype.
Comment 15 Brendan Eich [:brendan] 2007-04-20 22:26:21 PDT
Take it out of Object.prototype, make it a global function only.

/be
Comment 16 Blake Kaplan (:mrbkap) 2007-05-24 15:53:07 PDT
Created attachment 266004 [details] [diff] [review]
Best fix yet

With this patch applied:

js> ["print('a')", "print('b')"].forEach(eval)
a
b
js> this.eval
function eval() {
    [native code]
}
js> ({}).eval
js> eval.call({}, "")
typein:3: EvalError: function eval must be called directly, and not by way of a function of another name
Comment 17 Brendan Eich [:brendan] 2007-05-29 22:38:59 PDT
Comment on attachment 266004 [details] [diff] [review]
Best fix yet

>Index: jsapi.c
>===================================================================
>RCS file: /cvsroot/mozilla/js/src/jsapi.c,v
>retrieving revision 3.322
>diff -p -U8 -r3.322 jsapi.c
>--- jsapi.c	18 May 2007 20:55:06 -0000	3.322
>+++ jsapi.c	24 May 2007 22:50:35 -0000
>@@ -1395,16 +1395,17 @@ static JSStdName object_prototype_names[
>     {js_InitObjectClass,        EAGER_ATOM(parent), NULL},
>     {js_InitObjectClass,        EAGER_ATOM(count), NULL},
> #if JS_HAS_TOSOURCE
>     {js_InitObjectClass,        EAGER_ATOM(toSource), NULL},
> #endif
>     {js_InitObjectClass,        EAGER_ATOM(toString), NULL},
>     {js_InitObjectClass,        EAGER_ATOM(toLocaleString), NULL},
>     {js_InitObjectClass,        EAGER_ATOM(valueOf), NULL},
>+    {js_InitObjectClass,        EAGER_ATOM(eval), NULL},

Why add this to object_prototype_names if this patch removes Object.prototype.eval? The entry in standard_class_names should suffice.


>+    /*
>+     * Note: This restriction allows for Array.map(array, eval), but does not
>+     * allow the user to pass a this parameter that isn't a global object.
>+     */
>+    if (indirectCall || OBJ_GET_PARENT(c, obj)) {
>+        uintN flags = (OBJ_GET_PARENT(cx, obj) != NULL)

Nit: house style eschews != NULL tests except when nesting assignment in a loop condition. Outer parens in the ?: condition can be avoided too, thereby.

Looks great otherwise. We are close to the promised land... r=me with these changes.

/be
Comment 18 Blake Kaplan (:mrbkap) 2007-05-29 23:06:49 PDT
(In reply to comment #17)
> Why add this to object_prototype_names if this patch removes
> Object.prototype.eval? The entry in standard_class_names should suffice.

Oops, I didn't see that when I wrote the patch.
Comment 19 Blake Kaplan (:mrbkap) 2007-05-30 11:18:05 PDT
So, should we try this for a6? Or should this wait until after 1.9 has branched (based on bug 380236 comment 14)?
Comment 20 Blake Kaplan (:mrbkap) 2007-05-30 11:31:03 PDT
Created attachment 266637 [details] [diff] [review]
What's ready to be checked in
Comment 21 Blake Kaplan (:mrbkap) 2007-05-30 13:37:21 PDT
James, Neil, do you know if any extensions are depending on indirect eval on something that isn't the window object (Brendan and I seem to remember Venkman using the 2-parameter form, but don't remember if it also uses the indirect form)?
Comment 22 neil@parkwaycc.co.uk 2007-05-30 15:16:20 PDT
(In reply to comment #21)
>James, Neil, do you know if any extensions are depending on indirect eval on
>something that isn't the window object (Brendan and I seem to remember Venkman
>using the 2-parameter form, but don't remember if it also uses the indirect form)?
Are you perhaps thinking of evalInTargetScope in venkman-static.js?
Comment 23 Blake Kaplan (:mrbkap) 2007-05-30 15:39:50 PDT
Argh, this got wacky. Jeff, this bug ended up being about removing indirect eval, we can use bug 382509 as a cover bug. Perhaps the discussion about Venkman should move there.
Comment 24 Blake Kaplan (:mrbkap) 2007-06-04 14:42:16 PDT
This was checked into trunk.
Comment 25 Daniel Veditz [:dveditz] 2007-06-26 17:42:53 PDT
Does this have too much potential for extension-breaking, or could we safely take this on the 1.8 branch?
Comment 26 Blake Kaplan (:mrbkap) 2007-06-27 17:08:57 PDT
I think I've seen spurious errors caused by this checkin (including one in chrome code!), which makes me wary to check this in on branches.
Comment 27 Daniel Veditz [:dveditz] 2007-06-28 11:17:41 PDT
alright, let's wait at least another cycle to see what the trunk fall-out is and then reconsider taking it on the branch.
Comment 28 Daniel Veditz [:dveditz] 2007-09-27 16:33:21 PDT
Still don't see regressions from this on trunk, can we take it now? 1.8.1.9?
Comment 29 Daniel Veditz [:dveditz] 2008-01-15 16:04:14 PST
The branch has waited a long time for this, is there any objection to me just checking it in?
Comment 30 Daniel Veditz [:dveditz] 2008-01-24 13:56:01 PST
After 2.0.0.11 I'm too scared to check this in without explicit approval from the patch author, will have to wait yet again.
Comment 31 Samuel Sidler (old account; do not CC) 2008-03-07 10:28:10 PST
Fixed on the branch in bug 382509.
Comment 34 Al Billings [:abillings] 2008-03-15 10:05:07 PDT
All right. Marking as verified for this release then.

Note You need to log in before you can comment on or make changes to this bug.