Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/nsContentPolicyUtils.h
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
/*
7
 * Utility routines for checking content load/process policy settings,
8
 * and routines helpful for content policy implementors.
9
 *
10
 * XXXbz it would be nice if some of this stuff could be out-of-lined in
11
 * nsContentUtils.  That would work for almost all the callers...
12
 */
13
14
#ifndef __nsContentPolicyUtils_h__
15
#define __nsContentPolicyUtils_h__
16
17
#include "nsContentUtils.h"
18
#include "nsIContentPolicy.h"
19
#include "nsIContent.h"
20
#include "nsIScriptSecurityManager.h"
21
#include "nsIURI.h"
22
#include "nsServiceManagerUtils.h"
23
#include "nsStringFwd.h"
24
25
//XXXtw sadly, this makes consumers of nsContentPolicyUtils depend on widget
26
#include "nsIDocument.h"
27
#include "nsPIDOMWindow.h"
28
29
class nsIPrincipal;
30
31
#define NS_CONTENTPOLICY_CONTRACTID   "@mozilla.org/layout/content-policy;1"
32
#define NS_CONTENTPOLICY_CATEGORY "content-policy"
33
#define NS_CONTENTPOLICY_CID                              \
34
  {0x0e3afd3d, 0xeb60, 0x4c2b,                            \
35
     { 0x96, 0x3b, 0x56, 0xd7, 0xc4, 0x39, 0xf1, 0x24 }}
36
37
/**
38
 * Evaluates to true if val is ACCEPT.
39
 *
40
 * @param val the status returned from shouldProcess/shouldLoad
41
 */
42
0
#define NS_CP_ACCEPTED(val) ((val) == nsIContentPolicy::ACCEPT)
43
44
/**
45
 * Evaluates to true if val is a REJECT_* status
46
 *
47
 * @param val the status returned from shouldProcess/shouldLoad
48
 */
49
5
#define NS_CP_REJECTED(val) ((val) != nsIContentPolicy::ACCEPT)
50
51
// Offer convenient translations of constants -> const char*
52
53
// convenience macro to reduce some repetative typing...
54
// name is the name of a constant from this interface
55
#define CASE_RETURN(name)          \
56
  case nsIContentPolicy:: name :   \
57
    return #name
58
59
/**
60
 * Returns a string corresponding to the name of the response constant, or
61
 * "<Unknown Response>" if an unknown response value is given.
62
 *
63
 * The return value is static and must not be freed.
64
 *
65
 * @param response the response code
66
 * @return the name of the given response code
67
 */
68
inline const char *
69
NS_CP_ResponseName(int16_t response)
70
{
71
  switch (response) {
72
    CASE_RETURN( REJECT_REQUEST );
73
    CASE_RETURN( REJECT_TYPE    );
74
    CASE_RETURN( REJECT_SERVER  );
75
    CASE_RETURN( REJECT_OTHER   );
76
    CASE_RETURN( ACCEPT         );
77
  default:
78
    return "<Unknown Response>";
79
  }
80
}
81
82
/**
83
 * Returns a string corresponding to the name of the content type constant, or
84
 * "<Unknown Type>" if an unknown content type value is given.
85
 *
86
 * The return value is static and must not be freed.
87
 *
88
 * @param contentType the content type code
89
 * @return the name of the given content type code
90
 */
91
inline const char *
92
NS_CP_ContentTypeName(uint32_t contentType)
93
{
94
  switch (contentType) {
95
    CASE_RETURN( TYPE_OTHER                       );
96
    CASE_RETURN( TYPE_SCRIPT                      );
97
    CASE_RETURN( TYPE_IMAGE                       );
98
    CASE_RETURN( TYPE_STYLESHEET                  );
99
    CASE_RETURN( TYPE_OBJECT                      );
100
    CASE_RETURN( TYPE_DOCUMENT                    );
101
    CASE_RETURN( TYPE_SUBDOCUMENT                 );
102
    CASE_RETURN( TYPE_REFRESH                     );
103
    CASE_RETURN( TYPE_XBL                         );
104
    CASE_RETURN( TYPE_PING                        );
105
    CASE_RETURN( TYPE_XMLHTTPREQUEST              );
106
    CASE_RETURN( TYPE_OBJECT_SUBREQUEST           );
107
    CASE_RETURN( TYPE_DTD                         );
108
    CASE_RETURN( TYPE_FONT                        );
109
    CASE_RETURN( TYPE_MEDIA                       );
110
    CASE_RETURN( TYPE_WEBSOCKET                   );
111
    CASE_RETURN( TYPE_CSP_REPORT                  );
112
    CASE_RETURN( TYPE_XSLT                        );
113
    CASE_RETURN( TYPE_BEACON                      );
114
    CASE_RETURN( TYPE_FETCH                       );
115
    CASE_RETURN( TYPE_IMAGESET                    );
116
    CASE_RETURN( TYPE_WEB_MANIFEST                );
117
    CASE_RETURN( TYPE_INTERNAL_SCRIPT             );
118
    CASE_RETURN( TYPE_INTERNAL_WORKER             );
119
    CASE_RETURN( TYPE_INTERNAL_SHARED_WORKER      );
120
    CASE_RETURN( TYPE_INTERNAL_EMBED              );
121
    CASE_RETURN( TYPE_INTERNAL_OBJECT             );
122
    CASE_RETURN( TYPE_INTERNAL_FRAME              );
123
    CASE_RETURN( TYPE_INTERNAL_IFRAME             );
124
    CASE_RETURN( TYPE_INTERNAL_AUDIO              );
125
    CASE_RETURN( TYPE_INTERNAL_VIDEO              );
126
    CASE_RETURN( TYPE_INTERNAL_TRACK              );
127
    CASE_RETURN( TYPE_INTERNAL_XMLHTTPREQUEST     );
128
    CASE_RETURN( TYPE_INTERNAL_EVENTSOURCE        );
129
    CASE_RETURN( TYPE_INTERNAL_SERVICE_WORKER     );
130
    CASE_RETURN( TYPE_INTERNAL_SCRIPT_PRELOAD     );
131
    CASE_RETURN( TYPE_INTERNAL_IMAGE              );
132
    CASE_RETURN( TYPE_INTERNAL_IMAGE_PRELOAD      );
133
    CASE_RETURN( TYPE_INTERNAL_IMAGE_FAVICON      );
134
    CASE_RETURN( TYPE_INTERNAL_STYLESHEET         );
135
    CASE_RETURN( TYPE_INTERNAL_STYLESHEET_PRELOAD );
136
    CASE_RETURN( TYPE_INTERNAL_WORKER_IMPORT_SCRIPTS );
137
    CASE_RETURN( TYPE_SAVEAS_DOWNLOAD             );
138
    CASE_RETURN( TYPE_SPECULATIVE                 );
139
   default:
140
    return "<Unknown Type>";
141
  }
142
}
143
144
#undef CASE_RETURN
145
146
/* Passes on parameters from its "caller"'s context. */
147
#define CHECK_CONTENT_POLICY(action)                                          \
148
  PR_BEGIN_MACRO                                                              \
149
    nsCOMPtr<nsIContentPolicy> policy =                                       \
150
         do_GetService(NS_CONTENTPOLICY_CONTRACTID);                          \
151
    if (!policy)                                                              \
152
        return NS_ERROR_FAILURE;                                              \
153
                                                                              \
154
    return policy-> action (contentLocation, loadInfo, mimeType, decision);   \
155
  PR_END_MACRO
156
157
/* Passes on parameters from its "caller"'s context. */
158
#define CHECK_CONTENT_POLICY_WITH_SERVICE(action, _policy)                    \
159
  PR_BEGIN_MACRO                                                              \
160
    return _policy-> action (contentLocation, loadInfo, mimeType, decision);  \
161
  PR_END_MACRO
162
163
/**
164
 * Check whether we can short-circuit this check and bail out.  If not, get the
165
 * origin URI to use.
166
 *
167
 * Note: requestOrigin is scoped outside the PR_BEGIN_MACRO/PR_END_MACRO on
168
 * purpose */
169
#define CHECK_PRINCIPAL_AND_DATA(action)                                      \
170
  nsCOMPtr<nsIURI> requestOrigin;                                             \
171
  PR_BEGIN_MACRO                                                              \
172
  if (loadingPrincipal) {                                                     \
173
      /* We exempt most loads into any document with the system principal     \
174
       * from content policy checks, mostly as an optimization. Which means   \
175
       * that we need to apply this check to the loading principal, not the   \
176
       * principal that triggered the load. */                                \
177
      bool isSystem = loadingPrincipal->GetIsSystemPrincipal();               \
178
      if (isSystem && contentType != nsIContentPolicy::TYPE_DOCUMENT) {       \
179
          *decision = nsIContentPolicy::ACCEPT;                               \
180
          nsCOMPtr<nsINode> n = do_QueryInterface(context);                   \
181
          if (!n) {                                                           \
182
              nsCOMPtr<nsPIDOMWindowOuter> win = do_QueryInterface(context);  \
183
              n = win ? win->GetExtantDoc() : nullptr;                        \
184
          }                                                                   \
185
          if (n) {                                                            \
186
              nsIDocument* d = n->OwnerDoc();                                 \
187
              if (d->IsLoadedAsData() || d->IsBeingUsedAsImage() ||           \
188
                  d->IsResourceDoc()) {                                       \
189
                  nsCOMPtr<nsIContentPolicy> dataPolicy =                     \
190
                      do_GetService(                                          \
191
                              "@mozilla.org/data-document-content-policy;1"); \
192
                  if (dataPolicy) {                                           \
193
                      dataPolicy-> action (contentLocation, loadInfo,         \
194
                                           mimeType, decision);               \
195
                  }                                                           \
196
              }                                                               \
197
          }                                                                   \
198
          return NS_OK;                                                       \
199
      }                                                                       \
200
      nsresult rv = loadingPrincipal->GetURI(getter_AddRefs(requestOrigin));  \
201
      NS_ENSURE_SUCCESS(rv, rv);                                              \
202
  }                                                                           \
203
  PR_END_MACRO
204
205
/**
206
 * Alias for calling ShouldLoad on the content policy service.  Parameters are
207
 * the same as nsIContentPolicy::shouldLoad, except for the loadingPrincipal
208
 * and triggeringPrincipal parameters (which should be non-null if possible,
209
 * and have the same semantics as in nsLoadInfo), and the last parameter,
210
 * which can be used to pass in a pointer to a useful service if the caller
211
 * already has it.  The origin URI to pass to shouldLoad will be the URI of
212
 * loadingPrincipal, unless loadingPrincipal is null (in which case a null
213
 * origin URI will be passed).
214
 */
215
inline nsresult
216
NS_CheckContentLoadPolicy(nsIURI           *contentLocation,
217
                          nsILoadInfo      *loadInfo,
218
                          const nsACString &mimeType,
219
                          int16_t          *decision,
220
                          nsIContentPolicy *policyService = nullptr)
221
{
222
    nsIPrincipal* loadingPrincipal = loadInfo->LoadingPrincipal();
223
    nsCOMPtr<nsISupports> context = loadInfo->GetLoadingContext();
224
    nsContentPolicyType contentType = loadInfo->InternalContentPolicyType();
225
    CHECK_PRINCIPAL_AND_DATA(ShouldLoad);
226
    if (policyService) {
227
        CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldLoad, policyService);
228
    }
229
    CHECK_CONTENT_POLICY(ShouldLoad);
230
}
231
232
/**
233
 * Alias for calling ShouldProcess on the content policy service.
234
 */
235
inline nsresult
236
NS_CheckContentProcessPolicy(nsIURI           *contentLocation,
237
                             nsILoadInfo      *loadInfo,
238
                             const nsACString &mimeType,
239
                             int16_t          *decision,
240
                             nsIContentPolicy *policyService = nullptr)
241
{
242
    nsIPrincipal* loadingPrincipal = loadInfo->LoadingPrincipal();
243
    nsCOMPtr<nsISupports> context = loadInfo->GetLoadingContext();
244
    nsContentPolicyType contentType = loadInfo->InternalContentPolicyType();
245
    CHECK_PRINCIPAL_AND_DATA(ShouldProcess);
246
    if (policyService) {
247
        CHECK_CONTENT_POLICY_WITH_SERVICE(ShouldProcess, policyService);
248
    }
249
    CHECK_CONTENT_POLICY(ShouldProcess);
250
}
251
252
#undef CHECK_CONTENT_POLICY
253
#undef CHECK_CONTENT_POLICY_WITH_SERVICE
254
255
/**
256
 * Helper function to get an nsIDocShell given a context.
257
 * If the context is a document or window, the corresponding docshell will be
258
 * returned.
259
 * If the context is a non-document DOM node, the docshell of its ownerDocument
260
 * will be returned.
261
 *
262
 * @param aContext the context to find a docshell for (can be null)
263
 *
264
 * @return a WEAK pointer to the docshell, or nullptr if it could
265
 *     not be obtained
266
 *
267
 * @note  As of this writing, calls to nsIContentPolicy::Should{Load,Process}
268
 * for TYPE_DOCUMENT and TYPE_SUBDOCUMENT pass in an aContext that either
269
 * points to the frameElement of the window the load is happening in
270
 * (in which case NS_CP_GetDocShellFromContext will return the parent of the
271
 * docshell the load is happening in), or points to the window the load is
272
 * happening in (in which case NS_CP_GetDocShellFromContext will return
273
 * the docshell the load is happening in).  It's up to callers to QI aContext
274
 * and handle things accordingly if they want the docshell the load is
275
 * happening in.  These are somewhat odd semantics, and bug 466687 has been
276
 * filed to consider improving them.
277
 */
278
inline nsIDocShell*
279
NS_CP_GetDocShellFromContext(nsISupports *aContext)
280
0
{
281
0
    if (!aContext) {
282
0
        return nullptr;
283
0
    }
284
0
285
0
    nsCOMPtr<nsPIDOMWindowOuter> window = do_QueryInterface(aContext);
286
0
287
0
    if (!window) {
288
0
        // Our context might be a document.
289
0
        nsCOMPtr<nsIDocument> doc = do_QueryInterface(aContext);
290
0
        if (!doc) {
291
0
            // we were not a document after all, get our ownerDocument,
292
0
            // hopefully
293
0
            nsCOMPtr<nsIContent> content = do_QueryInterface(aContext);
294
0
            if (content) {
295
0
                doc = content->OwnerDoc();
296
0
            }
297
0
        }
298
0
299
0
        if (doc) {
300
0
            if (doc->GetDisplayDocument()) {
301
0
                doc = doc->GetDisplayDocument();
302
0
            }
303
0
304
0
            window = doc->GetWindow();
305
0
        }
306
0
    }
307
0
308
0
    if (!window) {
309
0
        return nullptr;
310
0
    }
311
0
312
0
    return window->GetDocShell();
313
0
}
314
315
#endif /* __nsContentPolicyUtils_h__ */