1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsapi-tests/testChromeBuffer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,191 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "jsapi-tests/tests.h" 1.11 + 1.12 +static TestJSPrincipals system_principals(1); 1.13 + 1.14 +static const JSClass global_class = { 1.15 + "global", 1.16 + JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS, 1.17 + JS_PropertyStub, 1.18 + JS_DeletePropertyStub, 1.19 + JS_PropertyStub, 1.20 + JS_StrictPropertyStub, 1.21 + JS_EnumerateStub, 1.22 + JS_ResolveStub, 1.23 + JS_ConvertStub, 1.24 + nullptr, 1.25 + nullptr, 1.26 + nullptr, 1.27 + nullptr, 1.28 + JS_GlobalObjectTraceHook 1.29 +}; 1.30 + 1.31 +static JS::Heap<JSObject *> trusted_glob; 1.32 +static JS::Heap<JSObject *> trusted_fun; 1.33 + 1.34 +static bool 1.35 +CallTrusted(JSContext *cx, unsigned argc, jsval *vp) 1.36 +{ 1.37 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.38 + 1.39 + if (!JS_SaveFrameChain(cx)) 1.40 + return false; 1.41 + 1.42 + bool ok = false; 1.43 + { 1.44 + JSAutoCompartment ac(cx, trusted_glob); 1.45 + JS::RootedValue funVal(cx, JS::ObjectValue(*trusted_fun)); 1.46 + ok = JS_CallFunctionValue(cx, JS::NullPtr(), funVal, JS::HandleValueArray::empty(), args.rval()); 1.47 + } 1.48 + JS_RestoreFrameChain(cx); 1.49 + return ok; 1.50 +} 1.51 + 1.52 +BEGIN_TEST(testChromeBuffer) 1.53 +{ 1.54 + JS_SetTrustedPrincipals(rt, &system_principals); 1.55 + 1.56 + trusted_glob = JS_NewGlobalObject(cx, &global_class, &system_principals, JS::FireOnNewGlobalHook); 1.57 + CHECK(trusted_glob); 1.58 + 1.59 + if (!JS::AddNamedObjectRoot(cx, &trusted_glob, "trusted-global")) 1.60 + return false; 1.61 + 1.62 + JS::RootedFunction fun(cx); 1.63 + 1.64 + /* 1.65 + * Check that, even after untrusted content has exhausted the stack, code 1.66 + * compiled with "trusted principals" can run using reserved trusted-only 1.67 + * buffer space. 1.68 + */ 1.69 + { 1.70 + { 1.71 + JSAutoCompartment ac(cx, trusted_glob); 1.72 + const char *paramName = "x"; 1.73 + const char *bytes = "return x ? 1 + trusted(x-1) : 0"; 1.74 + JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet()); 1.75 + JS::CompileOptions options(cx); 1.76 + options.setFileAndLine("", 0); 1.77 + CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, ¶mName, 1.78 + bytes, strlen(bytes), options)); 1.79 + trusted_fun = JS_GetFunctionObject(fun); 1.80 + if (!JS::AddNamedObjectRoot(cx, &trusted_fun, "trusted-function")) 1.81 + return false; 1.82 + } 1.83 + 1.84 + JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun)); 1.85 + CHECK(JS_WrapValue(cx, &v)); 1.86 + 1.87 + const char *paramName = "trusted"; 1.88 + const char *bytes = "try { " 1.89 + " return untrusted(trusted); " 1.90 + "} catch (e) { " 1.91 + " try { " 1.92 + " return trusted(100); " 1.93 + " } catch(e) { " 1.94 + " return -1; " 1.95 + " } " 1.96 + "} "; 1.97 + JS::CompileOptions options(cx); 1.98 + options.setFileAndLine("", 0); 1.99 + CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, ¶mName, 1.100 + bytes, strlen(bytes), options)); 1.101 + 1.102 + JS::RootedValue rval(cx); 1.103 + CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, v, &rval)); 1.104 + CHECK(JSVAL_TO_INT(rval) == 100); 1.105 + } 1.106 + 1.107 + /* 1.108 + * Check that content called from chrome in the reserved-buffer space 1.109 + * immediately ooms. 1.110 + */ 1.111 + { 1.112 + { 1.113 + JSAutoCompartment ac(cx, trusted_glob); 1.114 + const char *paramName = "untrusted"; 1.115 + const char *bytes = "try { " 1.116 + " untrusted(); " 1.117 + "} catch (e) { " 1.118 + " return 'From trusted: ' + e; " 1.119 + "} "; 1.120 + JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet()); 1.121 + JS::CompileOptions options(cx); 1.122 + options.setFileAndLine("", 0); 1.123 + CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, ¶mName, 1.124 + bytes, strlen(bytes), options)); 1.125 + trusted_fun = JS_GetFunctionObject(fun); 1.126 + } 1.127 + 1.128 + JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun)); 1.129 + CHECK(JS_WrapValue(cx, &v)); 1.130 + 1.131 + const char *paramName = "trusted"; 1.132 + const char *bytes = "try { " 1.133 + " return untrusted(trusted); " 1.134 + "} catch (e) { " 1.135 + " return trusted(untrusted); " 1.136 + "} "; 1.137 + JS::CompileOptions options(cx); 1.138 + options.setFileAndLine("", 0); 1.139 + CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, ¶mName, 1.140 + bytes, strlen(bytes), options)); 1.141 + 1.142 + JS::RootedValue rval(cx); 1.143 + CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, v, &rval)); 1.144 + bool match; 1.145 + CHECK(JS_StringEqualsAscii(cx, JSVAL_TO_STRING(rval), "From trusted: InternalError: too much recursion", &match)); 1.146 + CHECK(match); 1.147 + } 1.148 + 1.149 + /* 1.150 + * Check that JS_SaveFrameChain called on the way from content to chrome 1.151 + * (say, as done by XPCJSContextSTack::Push) works. 1.152 + */ 1.153 + { 1.154 + { 1.155 + JSAutoCompartment ac(cx, trusted_glob); 1.156 + const char *bytes = "return 42"; 1.157 + JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet()); 1.158 + JS::CompileOptions options(cx); 1.159 + options.setFileAndLine("", 0); 1.160 + CHECK(fun = JS_CompileFunction(cx, global, "trusted", 0, nullptr, 1.161 + bytes, strlen(bytes), options)); 1.162 + trusted_fun = JS_GetFunctionObject(fun); 1.163 + } 1.164 + 1.165 + JS::RootedFunction fun(cx, JS_NewFunction(cx, CallTrusted, 0, 0, global, "callTrusted")); 1.166 + JS::RootedObject callTrusted(cx, JS_GetFunctionObject(fun)); 1.167 + 1.168 + const char *paramName = "f"; 1.169 + const char *bytes = "try { " 1.170 + " return untrusted(trusted); " 1.171 + "} catch (e) { " 1.172 + " return f(); " 1.173 + "} "; 1.174 + JS::CompileOptions options(cx); 1.175 + options.setFileAndLine("", 0); 1.176 + CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, ¶mName, 1.177 + bytes, strlen(bytes), options)); 1.178 + 1.179 + JS::RootedValue arg(cx, JS::ObjectValue(*callTrusted)); 1.180 + JS::RootedValue rval(cx); 1.181 + CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, arg, &rval)); 1.182 + CHECK(JSVAL_TO_INT(rval) == 42); 1.183 + } 1.184 + 1.185 + return true; 1.186 +} 1.187 +virtual void uninit() { 1.188 + trusted_glob = nullptr; 1.189 + trusted_fun = nullptr; 1.190 + JS::RemoveObjectRoot(cx, &trusted_glob); 1.191 + JS::RemoveObjectRoot(cx, &trusted_fun); 1.192 + JSAPITest::uninit(); 1.193 +} 1.194 +END_TEST(testChromeBuffer)