js/src/jsapi-tests/testChromeBuffer.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #include "jsapi-tests/tests.h"
michael@0 8
michael@0 9 static TestJSPrincipals system_principals(1);
michael@0 10
michael@0 11 static const JSClass global_class = {
michael@0 12 "global",
michael@0 13 JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS,
michael@0 14 JS_PropertyStub,
michael@0 15 JS_DeletePropertyStub,
michael@0 16 JS_PropertyStub,
michael@0 17 JS_StrictPropertyStub,
michael@0 18 JS_EnumerateStub,
michael@0 19 JS_ResolveStub,
michael@0 20 JS_ConvertStub,
michael@0 21 nullptr,
michael@0 22 nullptr,
michael@0 23 nullptr,
michael@0 24 nullptr,
michael@0 25 JS_GlobalObjectTraceHook
michael@0 26 };
michael@0 27
michael@0 28 static JS::Heap<JSObject *> trusted_glob;
michael@0 29 static JS::Heap<JSObject *> trusted_fun;
michael@0 30
michael@0 31 static bool
michael@0 32 CallTrusted(JSContext *cx, unsigned argc, jsval *vp)
michael@0 33 {
michael@0 34 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
michael@0 35
michael@0 36 if (!JS_SaveFrameChain(cx))
michael@0 37 return false;
michael@0 38
michael@0 39 bool ok = false;
michael@0 40 {
michael@0 41 JSAutoCompartment ac(cx, trusted_glob);
michael@0 42 JS::RootedValue funVal(cx, JS::ObjectValue(*trusted_fun));
michael@0 43 ok = JS_CallFunctionValue(cx, JS::NullPtr(), funVal, JS::HandleValueArray::empty(), args.rval());
michael@0 44 }
michael@0 45 JS_RestoreFrameChain(cx);
michael@0 46 return ok;
michael@0 47 }
michael@0 48
michael@0 49 BEGIN_TEST(testChromeBuffer)
michael@0 50 {
michael@0 51 JS_SetTrustedPrincipals(rt, &system_principals);
michael@0 52
michael@0 53 trusted_glob = JS_NewGlobalObject(cx, &global_class, &system_principals, JS::FireOnNewGlobalHook);
michael@0 54 CHECK(trusted_glob);
michael@0 55
michael@0 56 if (!JS::AddNamedObjectRoot(cx, &trusted_glob, "trusted-global"))
michael@0 57 return false;
michael@0 58
michael@0 59 JS::RootedFunction fun(cx);
michael@0 60
michael@0 61 /*
michael@0 62 * Check that, even after untrusted content has exhausted the stack, code
michael@0 63 * compiled with "trusted principals" can run using reserved trusted-only
michael@0 64 * buffer space.
michael@0 65 */
michael@0 66 {
michael@0 67 {
michael@0 68 JSAutoCompartment ac(cx, trusted_glob);
michael@0 69 const char *paramName = "x";
michael@0 70 const char *bytes = "return x ? 1 + trusted(x-1) : 0";
michael@0 71 JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
michael@0 72 JS::CompileOptions options(cx);
michael@0 73 options.setFileAndLine("", 0);
michael@0 74 CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
michael@0 75 bytes, strlen(bytes), options));
michael@0 76 trusted_fun = JS_GetFunctionObject(fun);
michael@0 77 if (!JS::AddNamedObjectRoot(cx, &trusted_fun, "trusted-function"))
michael@0 78 return false;
michael@0 79 }
michael@0 80
michael@0 81 JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
michael@0 82 CHECK(JS_WrapValue(cx, &v));
michael@0 83
michael@0 84 const char *paramName = "trusted";
michael@0 85 const char *bytes = "try { "
michael@0 86 " return untrusted(trusted); "
michael@0 87 "} catch (e) { "
michael@0 88 " try { "
michael@0 89 " return trusted(100); "
michael@0 90 " } catch(e) { "
michael@0 91 " return -1; "
michael@0 92 " } "
michael@0 93 "} ";
michael@0 94 JS::CompileOptions options(cx);
michael@0 95 options.setFileAndLine("", 0);
michael@0 96 CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
michael@0 97 bytes, strlen(bytes), options));
michael@0 98
michael@0 99 JS::RootedValue rval(cx);
michael@0 100 CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, v, &rval));
michael@0 101 CHECK(JSVAL_TO_INT(rval) == 100);
michael@0 102 }
michael@0 103
michael@0 104 /*
michael@0 105 * Check that content called from chrome in the reserved-buffer space
michael@0 106 * immediately ooms.
michael@0 107 */
michael@0 108 {
michael@0 109 {
michael@0 110 JSAutoCompartment ac(cx, trusted_glob);
michael@0 111 const char *paramName = "untrusted";
michael@0 112 const char *bytes = "try { "
michael@0 113 " untrusted(); "
michael@0 114 "} catch (e) { "
michael@0 115 " return 'From trusted: ' + e; "
michael@0 116 "} ";
michael@0 117 JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
michael@0 118 JS::CompileOptions options(cx);
michael@0 119 options.setFileAndLine("", 0);
michael@0 120 CHECK(fun = JS_CompileFunction(cx, global, "trusted", 1, &paramName,
michael@0 121 bytes, strlen(bytes), options));
michael@0 122 trusted_fun = JS_GetFunctionObject(fun);
michael@0 123 }
michael@0 124
michael@0 125 JS::RootedValue v(cx, JS::ObjectValue(*trusted_fun));
michael@0 126 CHECK(JS_WrapValue(cx, &v));
michael@0 127
michael@0 128 const char *paramName = "trusted";
michael@0 129 const char *bytes = "try { "
michael@0 130 " return untrusted(trusted); "
michael@0 131 "} catch (e) { "
michael@0 132 " return trusted(untrusted); "
michael@0 133 "} ";
michael@0 134 JS::CompileOptions options(cx);
michael@0 135 options.setFileAndLine("", 0);
michael@0 136 CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
michael@0 137 bytes, strlen(bytes), options));
michael@0 138
michael@0 139 JS::RootedValue rval(cx);
michael@0 140 CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, v, &rval));
michael@0 141 bool match;
michael@0 142 CHECK(JS_StringEqualsAscii(cx, JSVAL_TO_STRING(rval), "From trusted: InternalError: too much recursion", &match));
michael@0 143 CHECK(match);
michael@0 144 }
michael@0 145
michael@0 146 /*
michael@0 147 * Check that JS_SaveFrameChain called on the way from content to chrome
michael@0 148 * (say, as done by XPCJSContextSTack::Push) works.
michael@0 149 */
michael@0 150 {
michael@0 151 {
michael@0 152 JSAutoCompartment ac(cx, trusted_glob);
michael@0 153 const char *bytes = "return 42";
michael@0 154 JS::HandleObject global = JS::HandleObject::fromMarkedLocation(trusted_glob.unsafeGet());
michael@0 155 JS::CompileOptions options(cx);
michael@0 156 options.setFileAndLine("", 0);
michael@0 157 CHECK(fun = JS_CompileFunction(cx, global, "trusted", 0, nullptr,
michael@0 158 bytes, strlen(bytes), options));
michael@0 159 trusted_fun = JS_GetFunctionObject(fun);
michael@0 160 }
michael@0 161
michael@0 162 JS::RootedFunction fun(cx, JS_NewFunction(cx, CallTrusted, 0, 0, global, "callTrusted"));
michael@0 163 JS::RootedObject callTrusted(cx, JS_GetFunctionObject(fun));
michael@0 164
michael@0 165 const char *paramName = "f";
michael@0 166 const char *bytes = "try { "
michael@0 167 " return untrusted(trusted); "
michael@0 168 "} catch (e) { "
michael@0 169 " return f(); "
michael@0 170 "} ";
michael@0 171 JS::CompileOptions options(cx);
michael@0 172 options.setFileAndLine("", 0);
michael@0 173 CHECK(fun = JS_CompileFunction(cx, global, "untrusted", 1, &paramName,
michael@0 174 bytes, strlen(bytes), options));
michael@0 175
michael@0 176 JS::RootedValue arg(cx, JS::ObjectValue(*callTrusted));
michael@0 177 JS::RootedValue rval(cx);
michael@0 178 CHECK(JS_CallFunction(cx, JS::NullPtr(), fun, arg, &rval));
michael@0 179 CHECK(JSVAL_TO_INT(rval) == 42);
michael@0 180 }
michael@0 181
michael@0 182 return true;
michael@0 183 }
michael@0 184 virtual void uninit() {
michael@0 185 trusted_glob = nullptr;
michael@0 186 trusted_fun = nullptr;
michael@0 187 JS::RemoveObjectRoot(cx, &trusted_glob);
michael@0 188 JS::RemoveObjectRoot(cx, &trusted_fun);
michael@0 189 JSAPITest::uninit();
michael@0 190 }
michael@0 191 END_TEST(testChromeBuffer)

mercurial