Commit 1b70812e authored by dcarney@chromium.org's avatar dcarney@chromium.org

filter out .caller from other worlds

R=verwaest@chromium.org

BUG=

Review URL: https://codereview.chromium.org/261103002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21366 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 83576f23
...@@ -1201,6 +1201,7 @@ class V8_EXPORT StackTrace { ...@@ -1201,6 +1201,7 @@ class V8_EXPORT StackTrace {
kIsConstructor = 1 << 5, kIsConstructor = 1 << 5,
kScriptNameOrSourceURL = 1 << 6, kScriptNameOrSourceURL = 1 << 6,
kScriptId = 1 << 7, kScriptId = 1 << 7,
kExposeFramesAcrossSecurityOrigins = 1 << 8,
kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName, kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName,
kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL
}; };
......
...@@ -1124,22 +1124,33 @@ Handle<AccessorInfo> Accessors::FunctionArgumentsInfo( ...@@ -1124,22 +1124,33 @@ Handle<AccessorInfo> Accessors::FunctionArgumentsInfo(
// //
static inline bool AllowAccessToFunction(Context* current_context,
JSFunction* function) {
return current_context->HasSameSecurityTokenAs(function->context());
}
class FrameFunctionIterator { class FrameFunctionIterator {
public: public:
FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise) FrameFunctionIterator(Isolate* isolate, const DisallowHeapAllocation& promise)
: frame_iterator_(isolate), : isolate_(isolate),
frame_iterator_(isolate),
functions_(2), functions_(2),
index_(0) { index_(0) {
GetFunctions(); GetFunctions();
} }
JSFunction* next() { JSFunction* next() {
if (functions_.length() == 0) return NULL; while (true) {
JSFunction* next_function = functions_[index_]; if (functions_.length() == 0) return NULL;
index_--; JSFunction* next_function = functions_[index_];
if (index_ < 0) { index_--;
GetFunctions(); 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'. // Iterate through functions until the first occurence of 'function'.
...@@ -1164,6 +1175,7 @@ class FrameFunctionIterator { ...@@ -1164,6 +1175,7 @@ class FrameFunctionIterator {
frame_iterator_.Advance(); frame_iterator_.Advance();
index_ = functions_.length() - 1; index_ = functions_.length() - 1;
} }
Isolate* isolate_;
JavaScriptFrameIterator frame_iterator_; JavaScriptFrameIterator frame_iterator_;
List<JSFunction*> functions_; List<JSFunction*> functions_;
int index_; int index_;
...@@ -1211,6 +1223,10 @@ MaybeHandle<JSFunction> FindCaller(Isolate* isolate, ...@@ -1211,6 +1223,10 @@ MaybeHandle<JSFunction> FindCaller(Isolate* isolate,
if (caller->shared()->strict_mode() == STRICT) { if (caller->shared()->strict_mode() == STRICT) {
return MaybeHandle<JSFunction>(); return MaybeHandle<JSFunction>();
} }
// Don't return caller from another security context.
if (!AllowAccessToFunction(isolate->context(), caller)) {
return MaybeHandle<JSFunction>();
}
return Handle<JSFunction>(caller); return Handle<JSFunction>(caller);
} }
......
...@@ -2115,6 +2115,9 @@ Local<StackTrace> StackTrace::CurrentStackTrace( ...@@ -2115,6 +2115,9 @@ Local<StackTrace> StackTrace::CurrentStackTrace(
StackTraceOptions options) { StackTraceOptions options) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8(i_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::Handle<i::JSArray> stackTrace =
i_isolate->CaptureCurrentStackTrace(frame_limit, options); i_isolate->CaptureCurrentStackTrace(frame_limit, options);
return Utils::StackTraceToLocal(stackTrace); return Utils::StackTraceToLocal(stackTrace);
......
...@@ -449,6 +449,11 @@ class Context: public FixedArray { ...@@ -449,6 +449,11 @@ class Context: public FixedArray {
return map == map->GetHeap()->global_context_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. // A native context holds a list of all functions with optimized code.
void AddOptimizedFunction(JSFunction* function); void AddOptimizedFunction(JSFunction* function);
void RemoveOptimizedFunction(JSFunction* function); void RemoveOptimizedFunction(JSFunction* function);
......
...@@ -388,13 +388,15 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, ...@@ -388,13 +388,15 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
iter.Advance()) { iter.Advance()) {
StackFrame* raw_frame = iter.frame(); StackFrame* raw_frame = iter.frame();
if (IsVisibleInStackTrace(raw_frame, *caller, &seen_caller)) { if (IsVisibleInStackTrace(raw_frame, *caller, &seen_caller)) {
frames_seen++;
JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame); JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
// Set initial size to the maximum inlining level + 1 for the outermost // Set initial size to the maximum inlining level + 1 for the outermost
// function. // function.
List<FrameSummary> frames(FLAG_max_inlining_levels + 1); List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
frame->Summarize(&frames); frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0; i--) { 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()) { if (cursor + 4 > elements->length()) {
int new_capacity = JSObject::NewElementsCapacity(elements->length()); int new_capacity = JSObject::NewElementsCapacity(elements->length());
Handle<FixedArray> new_elements = Handle<FixedArray> new_elements =
...@@ -407,7 +409,6 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, ...@@ -407,7 +409,6 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
ASSERT(cursor + 4 <= elements->length()); ASSERT(cursor + 4 <= elements->length());
Handle<Object> recv = frames[i].receiver(); Handle<Object> recv = frames[i].receiver();
Handle<JSFunction> fun = frames[i].function();
Handle<Code> code = frames[i].code(); Handle<Code> code = frames[i].code();
Handle<Smi> offset(Smi::FromInt(frames[i].offset()), this); Handle<Smi> offset(Smi::FromInt(frames[i].offset()), this);
// The stack trace API should not expose receivers and function // The stack trace API should not expose receivers and function
...@@ -426,6 +427,7 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object, ...@@ -426,6 +427,7 @@ Handle<JSArray> Isolate::CaptureSimpleStackTrace(Handle<JSObject> error_object,
elements->set(cursor++, *code); elements->set(cursor++, *code);
elements->set(cursor++, *offset); elements->set(cursor++, *offset);
} }
frames_seen++;
} }
} }
elements->set(0, Smi::FromInt(sloppy_frames)); elements->set(0, Smi::FromInt(sloppy_frames));
...@@ -480,10 +482,14 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace( ...@@ -480,10 +482,14 @@ Handle<JSArray> Isolate::CaptureCurrentStackTrace(
List<FrameSummary> frames(FLAG_max_inlining_levels + 1); List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
frame->Summarize(&frames); frame->Summarize(&frames);
for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) { 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. // Create a JSObject to hold the information for the StackFrame.
Handle<JSObject> stack_frame = factory()->NewJSObject(object_function()); Handle<JSObject> stack_frame = factory()->NewJSObject(object_function());
Handle<JSFunction> fun = frames[i].function();
Handle<Script> script(Script::cast(fun->shared()->script())); Handle<Script> script(Script::cast(fun->shared()->script()));
if (options & StackTrace::kLineNumber) { if (options & StackTrace::kLineNumber) {
......
// 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);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment