js/xpconnect/src/XPCJSContextStack.cpp

branch
TOR_BUG_3246
changeset 7
129ffea94266
equal deleted inserted replaced
-1:000000000000 0:27c70229eed8
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /* Implement global service to track stack of JSContext. */
8
9 #include "xpcprivate.h"
10 #include "XPCWrapper.h"
11 #include "nsDOMJSUtils.h"
12 #include "nsNullPrincipal.h"
13 #include "mozilla/dom/BindingUtils.h"
14
15 using namespace mozilla;
16 using namespace JS;
17 using namespace xpc;
18 using mozilla::dom::DestroyProtoAndIfaceCache;
19
20 /***************************************************************************/
21
22 XPCJSContextStack::~XPCJSContextStack()
23 {
24 if (mSafeJSContext) {
25 mSafeJSContextGlobal = nullptr;
26 JS_DestroyContextNoGC(mSafeJSContext);
27 mSafeJSContext = nullptr;
28 }
29 }
30
31 JSContext*
32 XPCJSContextStack::Pop()
33 {
34 MOZ_ASSERT(!mStack.IsEmpty());
35
36 uint32_t idx = mStack.Length() - 1; // The thing we're popping
37
38 JSContext *cx = mStack[idx].cx;
39
40 mStack.RemoveElementAt(idx);
41 if (idx == 0) {
42 js::Debug_SetActiveJSContext(mRuntime->Runtime(), nullptr);
43 return cx;
44 }
45
46 --idx; // Advance to new top of the stack
47
48 XPCJSContextInfo &e = mStack[idx];
49 if (e.cx && e.savedFrameChain) {
50 // Pop() can be called outside any request for e.cx.
51 JSAutoRequest ar(e.cx);
52 JS_RestoreFrameChain(e.cx);
53 e.savedFrameChain = false;
54 }
55 js::Debug_SetActiveJSContext(mRuntime->Runtime(), e.cx);
56 return cx;
57 }
58
59 bool
60 XPCJSContextStack::Push(JSContext *cx)
61 {
62 js::Debug_SetActiveJSContext(mRuntime->Runtime(), cx);
63 if (mStack.Length() == 0) {
64 mStack.AppendElement(cx);
65 return true;
66 }
67
68 XPCJSContextInfo &e = mStack[mStack.Length() - 1];
69 if (e.cx) {
70 // The cx we're pushing is also stack-top. In general we still need to
71 // call JS_SaveFrameChain here. But if that would put us in a
72 // compartment that's same-origin with the current one, we can skip it.
73 nsIScriptSecurityManager* ssm = XPCWrapper::GetSecurityManager();
74 if ((e.cx == cx) && ssm) {
75 // DOM JSContexts don't store their default compartment object on
76 // the cx, so in those cases we need to fetch it via the scx
77 // instead. And in some cases (i.e. the SafeJSContext), we have no
78 // default compartment object at all.
79 RootedObject defaultScope(cx, GetDefaultScopeFromJSContext(cx));
80 if (defaultScope) {
81 nsIPrincipal *currentPrincipal =
82 GetCompartmentPrincipal(js::GetContextCompartment(cx));
83 nsIPrincipal *defaultPrincipal = GetObjectPrincipal(defaultScope);
84 if (currentPrincipal->Equals(defaultPrincipal)) {
85 mStack.AppendElement(cx);
86 return true;
87 }
88 }
89 }
90
91 {
92 // Push() can be called outside any request for e.cx.
93 JSAutoRequest ar(e.cx);
94 if (!JS_SaveFrameChain(e.cx))
95 return false;
96 e.savedFrameChain = true;
97 }
98 }
99
100 mStack.AppendElement(cx);
101 return true;
102 }
103
104 bool
105 XPCJSContextStack::HasJSContext(JSContext *cx)
106 {
107 for (uint32_t i = 0; i < mStack.Length(); i++)
108 if (cx == mStack[i].cx)
109 return true;
110 return false;
111 }
112
113 static bool
114 SafeGlobalResolve(JSContext *cx, HandleObject obj, HandleId id)
115 {
116 bool resolved;
117 return JS_ResolveStandardClass(cx, obj, id, &resolved);
118 }
119
120 static void
121 SafeFinalize(JSFreeOp *fop, JSObject* obj)
122 {
123 SandboxPrivate* sop =
124 static_cast<SandboxPrivate*>(xpc_GetJSPrivate(obj));
125 sop->ForgetGlobalObject();
126 NS_IF_RELEASE(sop);
127 DestroyProtoAndIfaceCache(obj);
128 }
129
130 const JSClass xpc::SafeJSContextGlobalClass = {
131 "global_for_XPCJSContextStack_SafeJSContext",
132 XPCONNECT_GLOBAL_FLAGS,
133 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
134 JS_EnumerateStub, SafeGlobalResolve, JS_ConvertStub, SafeFinalize,
135 nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook
136 };
137
138 JSContext*
139 XPCJSContextStack::GetSafeJSContext()
140 {
141 MOZ_ASSERT(mSafeJSContext);
142 return mSafeJSContext;
143 }
144
145 JSObject*
146 XPCJSContextStack::GetSafeJSContextGlobal()
147 {
148 MOZ_ASSERT(mSafeJSContextGlobal);
149 return mSafeJSContextGlobal;
150 }
151
152 JSContext*
153 XPCJSContextStack::InitSafeJSContext()
154 {
155 MOZ_ASSERT(!mSafeJSContext);
156
157 // Start by getting the principal holder and principal for this
158 // context. If we can't manage that, don't bother with the rest.
159 nsRefPtr<nsNullPrincipal> principal = new nsNullPrincipal();
160 nsresult rv = principal->Init();
161 if (NS_FAILED(rv))
162 MOZ_CRASH();
163
164 nsXPConnect* xpc = nsXPConnect::XPConnect();
165 JSRuntime *rt = xpc->GetRuntime()->Runtime();
166 if (!rt)
167 MOZ_CRASH();
168
169 mSafeJSContext = JS_NewContext(rt, 8192);
170 if (!mSafeJSContext)
171 MOZ_CRASH();
172 JSAutoRequest req(mSafeJSContext);
173 ContextOptionsRef(mSafeJSContext).setNoDefaultCompartmentObject(true);
174
175 JS_SetErrorReporter(mSafeJSContext, xpc::SystemErrorReporter);
176
177 JS::CompartmentOptions options;
178 options.setZone(JS::SystemZone)
179 .setTrace(TraceXPCGlobal);
180 mSafeJSContextGlobal = CreateGlobalObject(mSafeJSContext,
181 &SafeJSContextGlobalClass,
182 principal, options);
183 if (!mSafeJSContextGlobal)
184 MOZ_CRASH();
185
186 // Note: make sure to set the private before calling
187 // InitClasses
188 nsRefPtr<SandboxPrivate> sp = new SandboxPrivate(principal, mSafeJSContextGlobal);
189 JS_SetPrivate(mSafeJSContextGlobal, sp.forget().take());
190
191 // After this point either glob is null and the
192 // nsIScriptObjectPrincipal ownership is either handled by the
193 // nsCOMPtr or dealt with, or we'll release in the finalize
194 // hook.
195 if (NS_FAILED(xpc->InitClasses(mSafeJSContext, mSafeJSContextGlobal)))
196 MOZ_CRASH();
197
198 JS::RootedObject glob(mSafeJSContext, mSafeJSContextGlobal);
199 JS_FireOnNewGlobalObject(mSafeJSContext, glob);
200
201 return mSafeJSContext;
202 }

mercurial