js/src/jsapi-tests/testChromeBuffer.cpp

changeset 0
6474c204b198
     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, &paramName,
    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, &paramName,
   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, &paramName,
   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, &paramName,
   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, &paramName,
   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)

mercurial