Revision: 21366
Author: [email protected]
Date: Mon May 19 13:45:45 2014 UTC
Log: filter out .caller from other worlds
[email protected]
BUG=
Review URL: https://codereview.chromium.org/261103002
http://code.google.com/p/v8/source/detail?r=21366
Added:
/branches/bleeding_edge/test/mjsunit/cross-realm-filtering.js
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/accessors.cc
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/contexts.h
/branches/bleeding_edge/src/isolate.cc
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/cross-realm-filtering.js Mon May
19 13:45:45 2014 UTC
@@ -0,0 +1,72 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var realms = [Realm.current(), Realm.create()];
+
+// Check stack trace filtering across security contexts.
+var thrower_script =
+ "(function () { Realm.eval(Realm.current(), 'throw Error()') })";
+Realm.shared = {
+ thrower_0: Realm.eval(realms[0], thrower_script),
+ thrower_1: Realm.eval(realms[1], thrower_script),
+};
+
+var script
= " \
+ Error.prepareStackTrace = function(a, b) { return b;
}; \
+ try
{ \
+
Realm.shared.thrower_0(); \
+ } catch (e)
{ \
+ Realm.shared.error_0 =
e.stack; \
+
}
\
+ try
{ \
+
Realm.shared.thrower_1(); \
+ } catch (e)
{ \
+ Realm.shared.error_1 =
e.stack; \
+
}
\
+";
+
+function assertNotIn(thrower, error) {
+ for (var i = 0; i < error.length; i++) {
+ assertFalse(false === error[i].getFunction());
+ }
+}
+
+Realm.eval(realms[1], script);
+assertSame(3, Realm.shared.error_0.length);
+assertSame(4, Realm.shared.error_1.length);
+
+assertTrue(Realm.shared.thrower_1 ===
Realm.shared.error_1[2].getFunction());
+assertNotIn(Realm.shared.thrower_0, Realm.shared.error_0);
+assertNotIn(Realm.shared.thrower_0, Realm.shared.error_1);
+
+Realm.eval(realms[0], script);
+assertSame(5, Realm.shared.error_0.length);
+assertSame(4, Realm.shared.error_1.length);
+
+assertTrue(Realm.shared.thrower_0 ===
Realm.shared.error_0[2].getFunction());
+assertNotIn(Realm.shared.thrower_1, Realm.shared.error_0);
+assertNotIn(Realm.shared.thrower_1, Realm.shared.error_1);
+
+
+// Check .caller filtering across security contexts.
+var caller_script = "(function (f) { f(); })";
+Realm.shared = {
+ caller_0 : Realm.eval(realms[0], caller_script),
+ caller_1 : Realm.eval(realms[1], caller_script),
+}
+
+script
= " \
+ function f_0() { Realm.shared.result_0 = arguments.callee.caller;
}; \
+ function f_1() { Realm.shared.result_1 = arguments.callee.caller;
}; \
+
Realm.shared.caller_0(f_0);
\
+
Realm.shared.caller_1(f_1);
\
+";
+
+Realm.eval(realms[1], script);
+assertSame(null, Realm.shared.result_0);
+assertSame(Realm.shared.caller_1, Realm.shared.result_1);
+
+Realm.eval(realms[0], script);
+assertSame(Realm.shared.caller_0, Realm.shared.result_0);
+assertSame(null, Realm.shared.result_1);
=======================================
--- /branches/bleeding_edge/include/v8.h Wed May 14 10:44:34 2014 UTC
+++ /branches/bleeding_edge/include/v8.h Mon May 19 13:45:45 2014 UTC
@@ -1201,6 +1201,7 @@
kIsConstructor = 1 << 5,
kScriptNameOrSourceURL = 1 << 6,
kScriptId = 1 << 7,
+ kExposeFramesAcrossSecurityOrigins = 1 << 8,
kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName,
kDetailed = kOverview | kIsEval | kIsConstructor |
kScriptNameOrSourceURL
};
=======================================
--- /branches/bleeding_edge/src/accessors.cc Wed May 14 08:34:05 2014 UTC
+++ /branches/bleeding_edge/src/accessors.cc Mon May 19 13:45:45 2014 UTC
@@ -1122,24 +1122,35 @@
//
// Accessors::FunctionCaller
//
+
+
+static inline bool AllowAccessToFunction(Context* current_context,
+ JSFunction* function) {
+ return current_context->HasSameSecurityTokenAs(function->context());
+}
class FrameFunctionIterator {
public:
FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation&
promise)
- : frame_iterator_(isolate),
+ : isolate_(isolate),
+ frame_iterator_(isolate),
functions_(2),
index_(0) {
GetFunctions();
}
JSFunction* next() {
- if (functions_.length() == 0) return NULL;
- JSFunction* next_function = functions_[index_];
- index_--;
- if (index_ < 0) {
- GetFunctions();
+ while (true) {
+ if (functions_.length() == 0) return NULL;
+ JSFunction* next_function = functions_[index_];
+ index_--;
+ if (index_ < 0) {
+ GetFunctions();
+ }
+ // Skip functions from other origins.
+ if (!AllowAccessToFunction(isolate_->context(), next_function))
continue;
+ return next_function;
}
- return next_function;
}
// Iterate through functions until the first occurence of 'function'.
@@ -1164,6 +1175,7 @@
frame_iterator_.Advance();
index_ = functions_.length() - 1;
}
+ Isolate* isolate_;
JavaScriptFrameIterator frame_iterator_;
List<JSFunction*> functions_;
int index_;
@@ -1211,6 +1223,10 @@
if (caller->shared()->strict_mode() == STRICT) {
return MaybeHandle<JSFunction>();
}
+ // Don't return caller from another security context.
+ if (!AllowAccessToFunction(isolate->context(), caller)) {
+ return MaybeHandle<JSFunction>();
+ }
return Handle<JSFunction>(caller);
}
=======================================
--- /branches/bleeding_edge/src/api.cc Mon May 19 07:57:04 2014 UTC
+++ /branches/bleeding_edge/src/api.cc Mon May 19 13:45:45 2014 UTC
@@ -2115,6 +2115,9 @@
StackTraceOptions options) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8(i_isolate);
+ // TODO(dcarney): remove when ScriptDebugServer is fixed.
+ options = static_cast<StackTraceOptions>(
+ static_cast<int>(options) | kExposeFramesAcrossSecurityOrigins);
i::Handle<i::JSArray> stackTrace =
i_isolate->CaptureCurrentStackTrace(frame_limit, options);
return Utils::StackTraceToLocal(stackTrace);
=======================================
--- /branches/bleeding_edge/src/contexts.h Mon May 19 07:57:04 2014 UTC
+++ /branches/bleeding_edge/src/contexts.h Mon May 19 13:45:45 2014 UTC
@@ -448,6 +448,11 @@
Map* map = this->map();
return map == map->GetHeap()->global_context_map();
}
+
+ bool HasSameSecurityTokenAs(Context* that) {
+ return this->global_object()->native_context()->security_token() ==
+ that->global_object()->native_context()->security_token();
+ }
// A native context holds a list of all functions with optimized code.
void AddOptimizedFunction(JSFunction* function);
=======================================
--- /branches/bleeding_edge/src/isolate.cc Mon May 19 08:36:56 2014 UTC
+++ /branches/bleeding_edge/src/isolate.cc Mon May 19 13:45:45 2014 UTC
@@ -388,13 +388,15 @@
iter.Advance()) {
StackFrame* raw_frame = iter.frame();
if (IsVisibleInStackTrace(raw_frame, *caller, &seen_caller)) {
- frames_seen++;
JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
// Set initial size to the maximum inlining level + 1 for the
outermost
// function.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) {
+ Handle<JSFunction> fun = frames[i].function();
+ // Filter out frames from other security contexts.
+ if (!this->context()->HasSameSecurityTokenAs(fun->context()))
continue;
if (cursor + 4 > elements->length()) {
int new_capacity =
JSObject::NewElementsCapacity(elements->length());
Handle<FixedArray> new_elements =
@@ -407,7 +409,6 @@
ASSERT(cursor + 4 <= elements->length());
Handle<Object> recv = frames[i].receiver();
- Handle<JSFunction> fun = frames[i].function();
Handle<Code> code = frames[i].code();
Handle<Smi> offset(Smi::FromInt(frames[i].offset()), this);
// The stack trace API should not expose receivers and function
@@ -426,6 +427,7 @@
elements->set(cursor++, *code);
elements->set(cursor++, *offset);
}
+ frames_seen++;
}
}
elements->set(0, Smi::FromInt(sloppy_frames));
@@ -480,10 +482,14 @@
List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
+ Handle<JSFunction> fun = frames[i].function();
+ // Filter frames from other security contexts.
+ if (!(options & StackTrace::kExposeFramesAcrossSecurityOrigins) &&
+ !this->context()->HasSameSecurityTokenAs(fun->context()))
continue;
+
// Create a JSObject to hold the information for the StackFrame.
Handle<JSObject> stack_frame =
factory()->NewJSObject(object_function());
- Handle<JSFunction> fun = frames[i].function();
Handle<Script> script(Script::cast(fun->shared()->script()));
if (options & StackTrace::kLineNumber) {
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.