Coverage Report

Created: 2018-09-25 14:53

/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
}