js/ipc/JavaScriptChild.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=4 sw=4 et tw=80:
     3  *
     4  * This Source Code Form is subject to the terms of the Mozilla Public
     5  * License, v. 2.0. If a copy of the MPL was not distributed with this
     6  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     8 #include "JavaScriptChild.h"
     9 #include "mozilla/dom/ContentChild.h"
    10 #include "mozilla/dom/BindingUtils.h"
    11 #include "nsContentUtils.h"
    12 #include "xpcprivate.h"
    13 #include "jsfriendapi.h"
    14 #include "nsCxPusher.h"
    16 using namespace JS;
    17 using namespace mozilla;
    18 using namespace mozilla::jsipc;
    20 using mozilla::AutoSafeJSContext;
    22 JavaScriptChild::JavaScriptChild(JSRuntime *rt)
    23   : lastId_(0),
    24     rt_(rt)
    25 {
    26 }
    28 static void
    29 Trace(JSTracer *trc, void *data)
    30 {
    31     reinterpret_cast<JavaScriptChild *>(data)->trace(trc);
    32 }
    34 JavaScriptChild::~JavaScriptChild()
    35 {
    36     JS_RemoveExtraGCRootsTracer(rt_, Trace, this);
    37 }
    39 void
    40 JavaScriptChild::trace(JSTracer *trc)
    41 {
    42     objects_.trace(trc);
    43     ids_.trace(trc);
    44 }
    46 bool
    47 JavaScriptChild::init()
    48 {
    49     if (!JavaScriptShared::init())
    50         return false;
    51     if (!ids_.init())
    52         return false;
    54     JS_AddExtraGCRootsTracer(rt_, Trace, this);
    55     return true;
    56 }
    58 bool
    59 JavaScriptChild::RecvDropObject(const ObjectId &objId)
    60 {
    61     JSObject *obj = findObject(objId);
    62     if (obj) {
    63         ids_.remove(obj);
    64         objects_.remove(objId);
    65     }
    66     return true;
    67 }
    69 bool
    70 JavaScriptChild::makeId(JSContext *cx, JSObject *obj, ObjectId *idp)
    71 {
    72     if (!obj) {
    73         *idp = 0;
    74         return true;
    75     }
    77     ObjectId id = ids_.find(obj);
    78     if (id) {
    79         *idp = id;
    80         return true;
    81     }
    83     id = ++lastId_;
    84     if (id > MAX_CPOW_IDS) {
    85         JS_ReportError(cx, "CPOW id limit reached");
    86         return false;
    87     }
    89     id <<= OBJECT_EXTRA_BITS;
    90     if (JS_ObjectIsCallable(cx, obj))
    91         id |= OBJECT_IS_CALLABLE;
    93     if (!objects_.add(id, obj))
    94         return false;
    95     if (!ids_.add(cx, obj, id))
    96         return false;
    98     *idp = id;
    99     return true;
   100 }
   102 JSObject *
   103 JavaScriptChild::unwrap(JSContext *cx, ObjectId id)
   104 {
   105     JSObject *obj = findObject(id);
   106     MOZ_ASSERT(obj);
   107     return obj;
   108 }
   110 bool
   111 JavaScriptChild::fail(JSContext *cx, ReturnStatus *rs)
   112 {
   113     // By default, we set |undefined| unless we can get a more meaningful
   114     // exception.
   115     *rs = ReturnStatus(ReturnException(JSVariant(void_t())));
   117     // Note we always return true from this function, since this propagates
   118     // to the IPC code, and we don't want a JS failure to cause the death
   119     // of the child process.
   121     RootedValue exn(cx);
   122     if (!JS_GetPendingException(cx, &exn))
   123         return true;
   125     // If we don't clear the pending exception, JS will try to wrap it as it
   126     // leaves the current compartment. Since there is no previous compartment,
   127     // that would crash.
   128     JS_ClearPendingException(cx);
   130     if (JS_IsStopIteration(exn)) {
   131         *rs = ReturnStatus(ReturnStopIteration());
   132         return true;
   133     }
   135     // If this fails, we still don't want to exit. Just return an invalid
   136     // exception.
   137     (void) toVariant(cx, exn, &rs->get_ReturnException().exn());
   138     return true;
   139 }
   141 bool
   142 JavaScriptChild::ok(ReturnStatus *rs)
   143 {
   144     *rs = ReturnStatus(ReturnSuccess());
   145     return true;
   146 }
   148 bool
   149 JavaScriptChild::AnswerPreventExtensions(const ObjectId &objId, ReturnStatus *rs)
   150 {
   151     AutoSafeJSContext cx;
   152     JSAutoRequest request(cx);
   154     RootedObject obj(cx, findObject(objId));
   155     if (!obj)
   156         return false;
   158     JSAutoCompartment comp(cx, obj);
   159     if (!JS_PreventExtensions(cx, obj))
   160         return fail(cx, rs);
   162     return ok(rs);
   163 }
   165 static void
   166 EmptyDesc(PPropertyDescriptor *desc)
   167 {
   168     desc->objId() = 0;
   169     desc->attrs() = 0;
   170     desc->value() = void_t();
   171     desc->getter() = 0;
   172     desc->setter() = 0;
   173 }
   175 bool
   176 JavaScriptChild::AnswerGetPropertyDescriptor(const ObjectId &objId, const nsString &id,
   177                                              ReturnStatus *rs, PPropertyDescriptor *out)
   178 {
   179     AutoSafeJSContext cx;
   180     JSAutoRequest request(cx);
   182     EmptyDesc(out);
   184     RootedObject obj(cx, findObject(objId));
   185     if (!obj)
   186         return false;
   188     JSAutoCompartment comp(cx, obj);
   190     RootedId internedId(cx);
   191     if (!convertGeckoStringToId(cx, id, &internedId))
   192         return fail(cx, rs);
   194     Rooted<JSPropertyDescriptor> desc(cx);
   195     if (!JS_GetPropertyDescriptorById(cx, obj, internedId, &desc))
   196         return fail(cx, rs);
   198     if (!desc.object())
   199         return ok(rs);
   201     if (!fromDescriptor(cx, desc, out))
   202         return fail(cx, rs);
   204     return ok(rs);
   205 }
   207 bool
   208 JavaScriptChild::AnswerGetOwnPropertyDescriptor(const ObjectId &objId, const nsString &id,
   209                                                 ReturnStatus *rs, PPropertyDescriptor *out)
   210 {
   211     AutoSafeJSContext cx;
   212     JSAutoRequest request(cx);
   214     EmptyDesc(out);
   216     RootedObject obj(cx, findObject(objId));
   217     if (!obj)
   218         return false;
   220     JSAutoCompartment comp(cx, obj);
   222     RootedId internedId(cx);
   223     if (!convertGeckoStringToId(cx, id, &internedId))
   224         return fail(cx, rs);
   226     Rooted<JSPropertyDescriptor> desc(cx);
   227     if (!JS_GetPropertyDescriptorById(cx, obj, internedId, &desc))
   228         return fail(cx, rs);
   230     if (desc.object() != obj)
   231         return ok(rs);
   233     if (!fromDescriptor(cx, desc, out))
   234         return fail(cx, rs);
   236     return ok(rs);
   237 }
   239 bool
   240 JavaScriptChild::AnswerDefineProperty(const ObjectId &objId, const nsString &id,
   241                                       const PPropertyDescriptor &descriptor, ReturnStatus *rs)
   242 {
   243     AutoSafeJSContext cx;
   244     JSAutoRequest request(cx);
   246     RootedObject obj(cx, findObject(objId));
   247     if (!obj)
   248         return false;
   250     JSAutoCompartment comp(cx, obj);
   252     RootedId internedId(cx);
   253     if (!convertGeckoStringToId(cx, id, &internedId))
   254         return fail(cx, rs);
   256     Rooted<JSPropertyDescriptor> desc(cx);
   257     if (!toDescriptor(cx, descriptor, &desc))
   258         return false;
   260     if (!js::CheckDefineProperty(cx, obj, internedId, desc.value(), desc.getter(),
   261                                  desc.setter(), desc.attributes()))
   262     {
   263         return fail(cx, rs);
   264     }
   266     if (!JS_DefinePropertyById(cx, obj, internedId, desc.value(), desc.getter(),
   267                                desc.setter(), desc.attributes()))
   268     {
   269         return fail(cx, rs);
   270     }
   272     return ok(rs);
   273 }
   275 bool
   276 JavaScriptChild::AnswerDelete(const ObjectId &objId, const nsString &id, ReturnStatus *rs,
   277                               bool *success)
   278 {
   279     AutoSafeJSContext cx;
   280     JSAutoRequest request(cx);
   282     *success = false;
   284     RootedObject obj(cx, findObject(objId));
   285     if (!obj)
   286         return false;
   288     JSAutoCompartment comp(cx, obj);
   290     RootedId internedId(cx);
   291     if (!convertGeckoStringToId(cx, id, &internedId))
   292         return fail(cx, rs);
   294     if (!JS_DeletePropertyById2(cx, obj, internedId, success))
   295         return fail(cx, rs);
   297     return ok(rs);
   298 }
   300 bool
   301 JavaScriptChild::AnswerHas(const ObjectId &objId, const nsString &id, ReturnStatus *rs, bool *bp)
   302 {
   303     AutoSafeJSContext cx;
   304     JSAutoRequest request(cx);
   306     *bp = false;
   308     RootedObject obj(cx, findObject(objId));
   309     if (!obj)
   310         return false;
   312     JSAutoCompartment comp(cx, obj);
   314     RootedId internedId(cx);
   315     if (!convertGeckoStringToId(cx, id, &internedId))
   316         return fail(cx, rs);
   318     bool found;
   319     if (!JS_HasPropertyById(cx, obj, internedId, &found))
   320         return fail(cx, rs);
   321     *bp = !!found;
   323     return ok(rs);
   324 }
   326 bool
   327 JavaScriptChild::AnswerHasOwn(const ObjectId &objId, const nsString &id, ReturnStatus *rs, bool *bp)
   328 {
   329     AutoSafeJSContext cx;
   330     JSAutoRequest request(cx);
   332     *bp = false;
   334     RootedObject obj(cx, findObject(objId));
   335     if (!obj)
   336         return false;
   338     JSAutoCompartment comp(cx, obj);
   340     RootedId internedId(cx);
   341     if (!convertGeckoStringToId(cx, id, &internedId))
   342         return fail(cx, rs);
   344     Rooted<JSPropertyDescriptor> desc(cx);
   345     if (!JS_GetPropertyDescriptorById(cx, obj, internedId, &desc))
   346         return fail(cx, rs);
   347     *bp = (desc.object() == obj);
   349     return ok(rs);
   350 }
   352 bool
   353 JavaScriptChild::AnswerGet(const ObjectId &objId, const ObjectId &receiverId, const nsString &id,
   354                            ReturnStatus *rs, JSVariant *result)
   355 {
   356     AutoSafeJSContext cx;
   357     JSAutoRequest request(cx);
   359     // The outparam will be written to the buffer, so it must be set even if
   360     // the parent won't read it.
   361     *result = void_t();
   363     RootedObject obj(cx, findObject(objId));
   364     if (!obj)
   365         return false;
   367     RootedObject receiver(cx, findObject(receiverId));
   368     if (!receiver)
   369         return false;
   371     JSAutoCompartment comp(cx, obj);
   373     RootedId internedId(cx);
   374     if (!convertGeckoStringToId(cx, id, &internedId))
   375         return fail(cx, rs);
   377     JS::RootedValue val(cx);
   378     if (!JS_ForwardGetPropertyTo(cx, obj, internedId, receiver, &val))
   379         return fail(cx, rs);
   381     if (!toVariant(cx, val, result))
   382         return fail(cx, rs);
   384     return ok(rs);
   385 }
   387 bool
   388 JavaScriptChild::AnswerSet(const ObjectId &objId, const ObjectId &receiverId, const nsString &id,
   389                            const bool &strict, const JSVariant &value, ReturnStatus *rs,
   390                            JSVariant *result)
   391 {
   392     AutoSafeJSContext cx;
   393     JSAutoRequest request(cx);
   395     // The outparam will be written to the buffer, so it must be set even if
   396     // the parent won't read it.
   397     *result = void_t();
   399     RootedObject obj(cx, findObject(objId));
   400     if (!obj)
   401         return false;
   403     RootedObject receiver(cx, findObject(receiverId));
   404     if (!receiver)
   405         return false;
   407     JSAutoCompartment comp(cx, obj);
   409     RootedId internedId(cx);
   410     if (!convertGeckoStringToId(cx, id, &internedId))
   411         return fail(cx, rs);
   413     MOZ_ASSERT(obj == receiver);
   415     RootedValue val(cx);
   416     if (!toValue(cx, value, &val))
   417         return fail(cx, rs);
   419     if (!JS_SetPropertyById(cx, obj, internedId, val))
   420         return fail(cx, rs);
   422     if (!toVariant(cx, val, result))
   423         return fail(cx, rs);
   425     return ok(rs);
   426 }
   428 bool
   429 JavaScriptChild::AnswerIsExtensible(const ObjectId &objId, ReturnStatus *rs, bool *result)
   430 {
   431     AutoSafeJSContext cx;
   432     JSAutoRequest request(cx);
   434     *result = false;
   436     RootedObject obj(cx, findObject(objId));
   437     if (!obj)
   438         return false;
   440     JSAutoCompartment comp(cx, obj);
   442     bool extensible;
   443     if (!JS_IsExtensible(cx, obj, &extensible))
   444         return fail(cx, rs);
   446     *result = !!extensible;
   447     return ok(rs);
   448 }
   450 bool
   451 JavaScriptChild::AnswerCall(const ObjectId &objId, const nsTArray<JSParam> &argv, ReturnStatus *rs,
   452                             JSVariant *result, nsTArray<JSParam> *outparams)
   453 {
   454     AutoSafeJSContext cx;
   455     JSAutoRequest request(cx);
   457     // The outparam will be written to the buffer, so it must be set even if
   458     // the parent won't read it.
   459     *result = void_t();
   461     RootedObject obj(cx, findObject(objId));
   462     if (!obj)
   463         return false;
   465     MOZ_ASSERT(argv.Length() >= 2);
   467     RootedValue objv(cx);
   468     if (!toValue(cx, argv[0], &objv))
   469         return fail(cx, rs);
   471     JSAutoCompartment comp(cx, &objv.toObject());
   473     *result = JSVariant(void_t());
   475     AutoValueVector vals(cx);
   476     AutoValueVector outobjects(cx);
   477     for (size_t i = 0; i < argv.Length(); i++) {
   478         if (argv[i].type() == JSParam::Tvoid_t) {
   479             // This is an outparam.
   480             JSCompartment *compartment = js::GetContextCompartment(cx);
   481             RootedObject global(cx, JS_GetGlobalForCompartmentOrNull(cx, compartment));
   482             RootedObject obj(cx, xpc::NewOutObject(cx, global));
   483             if (!obj)
   484                 return fail(cx, rs);
   485             if (!outobjects.append(ObjectValue(*obj)))
   486                 return fail(cx, rs);
   487             if (!vals.append(ObjectValue(*obj)))
   488                 return fail(cx, rs);
   489         } else {
   490             RootedValue v(cx);
   491             if (!toValue(cx, argv[i].get_JSVariant(), &v))
   492                 return fail(cx, rs);
   493             if (!vals.append(v))
   494                 return fail(cx, rs);
   495         }
   496     }
   498     RootedValue rval(cx);
   499     {
   500         AutoSaveContextOptions asco(cx);
   501         ContextOptionsRef(cx).setDontReportUncaught(true);
   503         HandleValueArray args = HandleValueArray::subarray(vals, 2, vals.length() - 2);
   504         bool success = JS::Call(cx, vals.handleAt(1), vals.handleAt(0), args, &rval);
   505         if (!success)
   506             return fail(cx, rs);
   507     }
   509     if (!toVariant(cx, rval, result))
   510         return fail(cx, rs);
   512     // Prefill everything with a dummy jsval.
   513     for (size_t i = 0; i < outobjects.length(); i++)
   514         outparams->AppendElement(JSParam(void_t()));
   516     // Go through each argument that was an outparam, retrieve the "value"
   517     // field, and add it to a temporary list. We need to do this separately
   518     // because the outparams vector is not rooted.
   519     vals.clear();
   520     for (size_t i = 0; i < outobjects.length(); i++) {
   521         RootedObject obj(cx, &outobjects[i].toObject());
   523         RootedValue v(cx);
   524         bool found;
   525         if (JS_HasProperty(cx, obj, "value", &found)) {
   526             if (!JS_GetProperty(cx, obj, "value", &v))
   527                 return fail(cx, rs);
   528         } else {
   529             v = UndefinedValue();
   530         }
   531         if (!vals.append(v))
   532             return fail(cx, rs);
   533     }
   535     // Copy the outparams. If any outparam is already set to a void_t, we
   536     // treat this as the outparam never having been set.
   537     for (size_t i = 0; i < vals.length(); i++) {
   538         JSVariant variant;
   539         if (!toVariant(cx, vals.handleAt(i), &variant))
   540             return fail(cx, rs);
   541         outparams->ReplaceElementAt(i, JSParam(variant));
   542     }
   544     return ok(rs);
   545 }
   547 bool
   548 JavaScriptChild::AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
   549                                      bool *result)
   550 {
   551     AutoSafeJSContext cx;
   552     JSAutoRequest request(cx);
   554     RootedObject obj(cx, findObject(objId));
   555     if (!obj)
   556         return false;
   558     JSAutoCompartment comp(cx, obj);
   560     *result = js_ObjectClassIs(cx, obj, (js::ESClassValue)classValue);
   561     return true;
   562 }
   564 bool
   565 JavaScriptChild::AnswerClassName(const ObjectId &objId, nsString *name)
   566 {
   567     AutoSafeJSContext cx;
   568     JSAutoRequest request(cx);
   570     RootedObject obj(cx, findObject(objId));
   571     if (!obj)
   572         return false;
   574     JSAutoCompartment comp(cx, obj);
   576     *name = NS_ConvertASCIItoUTF16(js_ObjectClassName(cx, obj));
   577     return true;
   578 }
   580 bool
   581 JavaScriptChild::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
   582                                         ReturnStatus *rs, nsTArray<nsString> *names)
   583 {
   584     AutoSafeJSContext cx;
   585     JSAutoRequest request(cx);
   587     RootedObject obj(cx, findObject(objId));
   588     if (!obj)
   589         return false;
   591     JSAutoCompartment comp(cx, obj);
   593     AutoIdVector props(cx);
   594     if (!js::GetPropertyNames(cx, obj, flags, &props))
   595         return fail(cx, rs);
   597     for (size_t i = 0; i < props.length(); i++) {
   598         nsString name;
   599         if (!convertIdToGeckoString(cx, props.handleAt(i), &name))
   600             return fail(cx, rs);
   602         names->AppendElement(name);
   603     }
   605     return ok(rs);
   606 }
   608 bool
   609 JavaScriptChild::AnswerInstanceOf(const ObjectId &objId, const JSIID &iid, ReturnStatus *rs,
   610                                   bool *instanceof)
   611 {
   612     AutoSafeJSContext cx;
   613     JSAutoRequest request(cx);
   615     *instanceof = false;
   617     RootedObject obj(cx, findObject(objId));
   618     if (!obj)
   619         return false;
   621     JSAutoCompartment comp(cx, obj);
   623     nsID nsiid;
   624     ConvertID(iid, &nsiid);
   626     nsresult rv = xpc::HasInstance(cx, obj, &nsiid, instanceof);
   627     if (rv != NS_OK)
   628         return fail(cx, rs);
   630     return ok(rs);
   631 }
   633 bool
   634 JavaScriptChild::AnswerDOMInstanceOf(const ObjectId &objId, const int &prototypeID,
   635                                      const int &depth,
   636                                      ReturnStatus *rs, bool *instanceof)
   637 {
   638     AutoSafeJSContext cx;
   639     JSAutoRequest request(cx);
   641     *instanceof = false;
   643     RootedObject obj(cx, findObject(objId));
   644     if (!obj)
   645         return false;
   647     JSAutoCompartment comp(cx, obj);
   649     bool tmp;
   650     if (!mozilla::dom::InterfaceHasInstance(cx, prototypeID, depth, obj, &tmp))
   651         return fail(cx, rs);
   652     *instanceof = tmp;
   654     return ok(rs);
   655 }

mercurial