/src/mozilla-central/caps/nsJSPrincipals.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #include "xpcpublic.h" |
7 | | #include "nsString.h" |
8 | | #include "nsIObjectOutputStream.h" |
9 | | #include "nsIObjectInputStream.h" |
10 | | #include "nsJSPrincipals.h" |
11 | | #include "plstr.h" |
12 | | #include "nsCOMPtr.h" |
13 | | #include "nsIServiceManager.h" |
14 | | #include "nsMemory.h" |
15 | | #include "nsStringBuffer.h" |
16 | | |
17 | | #include "mozilla/dom/StructuredCloneTags.h" |
18 | | // for mozilla::dom::workerinternals::kJSPrincipalsDebugToken |
19 | | #include "mozilla/dom/workerinternals/JSSettings.h" |
20 | | // for mozilla::dom::worklet::kJSPrincipalsDebugToken |
21 | | #include "mozilla/dom/WorkletPrincipal.h" |
22 | | #include "mozilla/ipc/BackgroundUtils.h" |
23 | | |
24 | | using namespace mozilla; |
25 | | using namespace mozilla::ipc; |
26 | | |
27 | | NS_IMETHODIMP_(MozExternalRefCountType) |
28 | | nsJSPrincipals::AddRef() |
29 | 5.83k | { |
30 | 5.83k | MOZ_ASSERT(NS_IsMainThread()); |
31 | 5.83k | MOZ_ASSERT(int32_t(refcount) >= 0, "illegal refcnt"); |
32 | 5.83k | nsrefcnt count = ++refcount; |
33 | 5.83k | NS_LOG_ADDREF(this, count, "nsJSPrincipals", sizeof(*this)); |
34 | 5.83k | return count; |
35 | 5.83k | } |
36 | | |
37 | | NS_IMETHODIMP_(MozExternalRefCountType) |
38 | | nsJSPrincipals::Release() |
39 | 5.80k | { |
40 | 5.80k | MOZ_ASSERT(NS_IsMainThread()); |
41 | 5.80k | MOZ_ASSERT(0 != refcount, "dup release"); |
42 | 5.80k | nsrefcnt count = --refcount; |
43 | 5.80k | NS_LOG_RELEASE(this, count, "nsJSPrincipals"); |
44 | 5.80k | if (count == 0) { |
45 | 5.77k | delete this; |
46 | 5.77k | } |
47 | 5.80k | |
48 | 5.80k | return count; |
49 | 5.80k | } |
50 | | |
51 | | /* static */ bool |
52 | | nsJSPrincipals::Subsume(JSPrincipals *jsprin, JSPrincipals *other) |
53 | 0 | { |
54 | 0 | bool result; |
55 | 0 | nsresult rv = nsJSPrincipals::get(jsprin)->Subsumes(nsJSPrincipals::get(other), &result); |
56 | 0 | return NS_SUCCEEDED(rv) && result; |
57 | 0 | } |
58 | | |
59 | | /* static */ void |
60 | | nsJSPrincipals::Destroy(JSPrincipals *jsprin) |
61 | 0 | { |
62 | 0 | // The JS runtime can call this method during the last GC when |
63 | 0 | // nsScriptSecurityManager is destroyed. So we must not assume here that |
64 | 0 | // the security manager still exists. |
65 | 0 |
|
66 | 0 | nsJSPrincipals *nsjsprin = nsJSPrincipals::get(jsprin); |
67 | 0 |
|
68 | 0 | // We need to destroy the nsIPrincipal. We'll do this by adding |
69 | 0 | // to the refcount and calling release |
70 | 0 |
|
71 | | #ifdef NS_BUILD_REFCNT_LOGGING |
72 | | // The refcount logging considers AddRef-to-1 to indicate creation, |
73 | | // so trick it into thinking it's otherwise, but balance the |
74 | | // Release() we do below. |
75 | | nsjsprin->refcount++; |
76 | | nsjsprin->AddRef(); |
77 | | nsjsprin->refcount--; |
78 | | #else |
79 | | nsjsprin->refcount++; |
80 | 0 | #endif |
81 | 0 | nsjsprin->Release(); |
82 | 0 | } |
83 | | |
84 | | #ifdef DEBUG |
85 | | |
86 | | // Defined here so one can do principals->dump() in the debugger |
87 | | JS_PUBLIC_API(void) |
88 | | JSPrincipals::dump() |
89 | | { |
90 | | if (debugToken == nsJSPrincipals::DEBUG_TOKEN) { |
91 | | nsAutoCString str; |
92 | | nsresult rv = static_cast<nsJSPrincipals *>(this)->GetScriptLocation(str); |
93 | | fprintf(stderr, "nsIPrincipal (%p) = %s\n", static_cast<void*>(this), |
94 | | NS_SUCCEEDED(rv) ? str.get() : "(unknown)"); |
95 | | } else if (debugToken == dom::workerinternals::kJSPrincipalsDebugToken) { |
96 | | fprintf(stderr, "Web Worker principal singleton (%p)\n", this); |
97 | | } else if (debugToken == mozilla::dom::WorkletPrincipal::kJSPrincipalsDebugToken) { |
98 | | fprintf(stderr, "Web Worklet principal singleton (%p)\n", this); |
99 | | } else { |
100 | | fprintf(stderr, |
101 | | "!!! JSPrincipals (%p) is not nsJSPrincipals instance - bad token: " |
102 | | "actual=0x%x expected=0x%x\n", |
103 | | this, unsigned(debugToken), unsigned(nsJSPrincipals::DEBUG_TOKEN)); |
104 | | } |
105 | | } |
106 | | |
107 | | #endif |
108 | | |
109 | | /* static */ bool |
110 | | nsJSPrincipals::ReadPrincipals(JSContext* aCx, JSStructuredCloneReader* aReader, |
111 | | JSPrincipals** aOutPrincipals) |
112 | 0 | { |
113 | 0 | uint32_t tag; |
114 | 0 | uint32_t unused; |
115 | 0 | if (!JS_ReadUint32Pair(aReader, &tag, &unused)) { |
116 | 0 | return false; |
117 | 0 | } |
118 | 0 | |
119 | 0 | if (!(tag == SCTAG_DOM_NULL_PRINCIPAL || |
120 | 0 | tag == SCTAG_DOM_SYSTEM_PRINCIPAL || |
121 | 0 | tag == SCTAG_DOM_CONTENT_PRINCIPAL || |
122 | 0 | tag == SCTAG_DOM_EXPANDED_PRINCIPAL)) { |
123 | 0 | xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); |
124 | 0 | return false; |
125 | 0 | } |
126 | 0 | |
127 | 0 | return ReadKnownPrincipalType(aCx, aReader, tag, aOutPrincipals); |
128 | 0 | } |
129 | | |
130 | | static bool |
131 | | ReadPrincipalInfo(JSStructuredCloneReader* aReader, |
132 | | OriginAttributes& aAttrs, |
133 | | nsACString& aSpec, |
134 | | nsACString& aOriginNoSuffix) |
135 | 0 | { |
136 | 0 | uint32_t suffixLength, specLength; |
137 | 0 | if (!JS_ReadUint32Pair(aReader, &suffixLength, &specLength)) { |
138 | 0 | return false; |
139 | 0 | } |
140 | 0 | |
141 | 0 | nsAutoCString suffix; |
142 | 0 | if (!suffix.SetLength(suffixLength, fallible)) { |
143 | 0 | return false; |
144 | 0 | } |
145 | 0 | |
146 | 0 | if (!JS_ReadBytes(aReader, suffix.BeginWriting(), suffixLength)) { |
147 | 0 | return false; |
148 | 0 | } |
149 | 0 | |
150 | 0 | if (!aAttrs.PopulateFromSuffix(suffix)) { |
151 | 0 | return false; |
152 | 0 | } |
153 | 0 | |
154 | 0 | if (!aSpec.SetLength(specLength, fallible)) { |
155 | 0 | return false; |
156 | 0 | } |
157 | 0 | |
158 | 0 | if (!JS_ReadBytes(aReader, aSpec.BeginWriting(), specLength)) { |
159 | 0 | return false; |
160 | 0 | } |
161 | 0 | |
162 | 0 | uint32_t originNoSuffixLength, dummy; |
163 | 0 | if (!JS_ReadUint32Pair(aReader, &originNoSuffixLength, &dummy)) { |
164 | 0 | return false; |
165 | 0 | } |
166 | 0 | |
167 | 0 | MOZ_ASSERT(dummy == 0); |
168 | 0 |
|
169 | 0 | if (!aOriginNoSuffix.SetLength(originNoSuffixLength, fallible)) { |
170 | 0 | return false; |
171 | 0 | } |
172 | 0 | |
173 | 0 | if (!JS_ReadBytes(aReader, aOriginNoSuffix.BeginWriting(), |
174 | 0 | originNoSuffixLength)) { |
175 | 0 | return false; |
176 | 0 | } |
177 | 0 | |
178 | 0 | return true; |
179 | 0 | } |
180 | | |
181 | | static bool |
182 | | ReadPrincipalInfo(JSStructuredCloneReader* aReader, |
183 | | uint32_t aTag, |
184 | | PrincipalInfo& aInfo) |
185 | 0 | { |
186 | 0 | if (aTag == SCTAG_DOM_SYSTEM_PRINCIPAL) { |
187 | 0 | aInfo = SystemPrincipalInfo(); |
188 | 0 | } else if (aTag == SCTAG_DOM_NULL_PRINCIPAL) { |
189 | 0 | OriginAttributes attrs; |
190 | 0 | nsAutoCString spec; |
191 | 0 | nsAutoCString originNoSuffix; |
192 | 0 | if (!ReadPrincipalInfo(aReader, attrs, spec, originNoSuffix)) { |
193 | 0 | return false; |
194 | 0 | } |
195 | 0 | aInfo = NullPrincipalInfo(attrs, spec); |
196 | 0 | } else if (aTag == SCTAG_DOM_EXPANDED_PRINCIPAL) { |
197 | 0 | uint32_t length, unused; |
198 | 0 | if (!JS_ReadUint32Pair(aReader, &length, &unused)) { |
199 | 0 | return false; |
200 | 0 | } |
201 | 0 | |
202 | 0 | ExpandedPrincipalInfo expanded; |
203 | 0 |
|
204 | 0 | for (uint32_t i = 0; i < length; i++) { |
205 | 0 | uint32_t tag; |
206 | 0 | if (!JS_ReadUint32Pair(aReader, &tag, &unused)) { |
207 | 0 | return false; |
208 | 0 | } |
209 | 0 | |
210 | 0 | PrincipalInfo sub; |
211 | 0 | if (!ReadPrincipalInfo(aReader, tag, sub)) { |
212 | 0 | return false; |
213 | 0 | } |
214 | 0 | expanded.whitelist().AppendElement(sub); |
215 | 0 | } |
216 | 0 |
|
217 | 0 | aInfo = expanded; |
218 | 0 | } else if (aTag == SCTAG_DOM_CONTENT_PRINCIPAL) { |
219 | 0 | OriginAttributes attrs; |
220 | 0 | nsAutoCString spec; |
221 | 0 | nsAutoCString originNoSuffix; |
222 | 0 | if (!ReadPrincipalInfo(aReader, attrs, spec, originNoSuffix)) { |
223 | 0 | return false; |
224 | 0 | } |
225 | 0 | |
226 | 0 | #ifdef FUZZING |
227 | 0 | if (originNoSuffix.IsEmpty()) { |
228 | 0 | return false; |
229 | 0 | } |
230 | 0 | #endif |
231 | 0 | |
232 | 0 | MOZ_DIAGNOSTIC_ASSERT(!originNoSuffix.IsEmpty()); |
233 | 0 |
|
234 | 0 | aInfo = ContentPrincipalInfo(attrs, originNoSuffix, spec); |
235 | 0 | } else { |
236 | 0 | #ifdef FUZZING |
237 | 0 | return false; |
238 | | #else |
239 | | MOZ_CRASH("unexpected principal structured clone tag"); |
240 | | #endif |
241 | | } |
242 | 0 |
|
243 | 0 | return true; |
244 | 0 | } |
245 | | |
246 | | /* static */ bool |
247 | | nsJSPrincipals::ReadKnownPrincipalType(JSContext* aCx, |
248 | | JSStructuredCloneReader* aReader, |
249 | | uint32_t aTag, |
250 | | JSPrincipals** aOutPrincipals) |
251 | 0 | { |
252 | 0 | MOZ_ASSERT(aTag == SCTAG_DOM_NULL_PRINCIPAL || |
253 | 0 | aTag == SCTAG_DOM_SYSTEM_PRINCIPAL || |
254 | 0 | aTag == SCTAG_DOM_CONTENT_PRINCIPAL || |
255 | 0 | aTag == SCTAG_DOM_EXPANDED_PRINCIPAL); |
256 | 0 |
|
257 | 0 | if (NS_WARN_IF(!NS_IsMainThread())) { |
258 | 0 | xpc::Throw(aCx, NS_ERROR_UNCATCHABLE_EXCEPTION); |
259 | 0 | return false; |
260 | 0 | } |
261 | 0 | |
262 | 0 | PrincipalInfo info; |
263 | 0 | if (!ReadPrincipalInfo(aReader, aTag, info)) { |
264 | 0 | return false; |
265 | 0 | } |
266 | 0 | |
267 | 0 | nsresult rv; |
268 | 0 | nsCOMPtr<nsIPrincipal> prin = PrincipalInfoToPrincipal(info, &rv); |
269 | 0 | if (NS_WARN_IF(NS_FAILED(rv))) { |
270 | 0 | xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); |
271 | 0 | return false; |
272 | 0 | } |
273 | 0 | |
274 | 0 | *aOutPrincipals = get(prin.forget().take()); |
275 | 0 | return true; |
276 | 0 | } |
277 | | |
278 | | static bool |
279 | | WritePrincipalInfo(JSStructuredCloneWriter* aWriter, |
280 | | const OriginAttributes& aAttrs, |
281 | | const nsCString& aSpec, |
282 | | const nsCString& aOriginNoSuffix) |
283 | 0 | { |
284 | 0 | nsAutoCString suffix; |
285 | 0 | aAttrs.CreateSuffix(suffix); |
286 | 0 |
|
287 | 0 | return JS_WriteUint32Pair(aWriter, suffix.Length(), aSpec.Length()) && |
288 | 0 | JS_WriteBytes(aWriter, suffix.get(), suffix.Length()) && |
289 | 0 | JS_WriteBytes(aWriter, aSpec.get(), aSpec.Length()) && |
290 | 0 | JS_WriteUint32Pair(aWriter, aOriginNoSuffix.Length(), 0) && |
291 | 0 | JS_WriteBytes(aWriter, aOriginNoSuffix.get(), |
292 | 0 | aOriginNoSuffix.Length()); |
293 | 0 | } |
294 | | |
295 | | static bool |
296 | | WritePrincipalInfo(JSStructuredCloneWriter* aWriter, const PrincipalInfo& aInfo) |
297 | 0 | { |
298 | 0 | if (aInfo.type() == PrincipalInfo::TNullPrincipalInfo) { |
299 | 0 | const NullPrincipalInfo& nullInfo = aInfo; |
300 | 0 | return JS_WriteUint32Pair(aWriter, SCTAG_DOM_NULL_PRINCIPAL, 0) && |
301 | 0 | WritePrincipalInfo(aWriter, nullInfo.attrs(), nullInfo.spec(), |
302 | 0 | EmptyCString()); |
303 | 0 | } |
304 | 0 | if (aInfo.type() == PrincipalInfo::TSystemPrincipalInfo) { |
305 | 0 | return JS_WriteUint32Pair(aWriter, SCTAG_DOM_SYSTEM_PRINCIPAL, 0); |
306 | 0 | } |
307 | 0 | if (aInfo.type() == PrincipalInfo::TExpandedPrincipalInfo) { |
308 | 0 | const ExpandedPrincipalInfo& expanded = aInfo; |
309 | 0 | if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_EXPANDED_PRINCIPAL, 0) || |
310 | 0 | !JS_WriteUint32Pair(aWriter, expanded.whitelist().Length(), 0)) { |
311 | 0 | return false; |
312 | 0 | } |
313 | 0 | |
314 | 0 | for (uint32_t i = 0; i < expanded.whitelist().Length(); i++) { |
315 | 0 | if (!WritePrincipalInfo(aWriter, expanded.whitelist()[i])) { |
316 | 0 | return false; |
317 | 0 | } |
318 | 0 | } |
319 | 0 | return true; |
320 | 0 | } |
321 | 0 | |
322 | 0 | MOZ_ASSERT(aInfo.type() == PrincipalInfo::TContentPrincipalInfo); |
323 | 0 | const ContentPrincipalInfo& cInfo = aInfo; |
324 | 0 | return JS_WriteUint32Pair(aWriter, SCTAG_DOM_CONTENT_PRINCIPAL, 0) && |
325 | 0 | WritePrincipalInfo(aWriter, cInfo.attrs(), cInfo.spec(), |
326 | 0 | cInfo.originNoSuffix()); |
327 | 0 | } |
328 | | |
329 | | bool |
330 | | nsJSPrincipals::write(JSContext* aCx, JSStructuredCloneWriter* aWriter) |
331 | 0 | { |
332 | 0 | PrincipalInfo info; |
333 | 0 | if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(this, &info)))) { |
334 | 0 | xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); |
335 | 0 | return false; |
336 | 0 | } |
337 | 0 | |
338 | 0 | return WritePrincipalInfo(aWriter, info); |
339 | 0 | } |