Attachment #394403: CSP Work in Progress (v5.1 - repaired) for bug #493857

View | Details | Raw Unified | Return to bug 493857
Collapse All | Expand All

(-)43fdf17e10a3 (+139 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the Content Security Policy IDL definition.
15
 *
16
 * The Initial Developer of the Original Code is
17
 *   Mozilla Corporation
18
 *
19
 * Contributor(s):
20
 *   Sid Stamm <sid@mozilla.com>
21
 *   Brandon Sterne <bsterne@mozilla.com>
22
 *   Daniel Veditz <dveditz@mozilla.com>
23
 *
24
 * Alternatively, the contents of this file may be used under the terms of
25
 * either the GNU General Public License Version 2 or later (the "GPL"), or
26
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27
 * in which case the provisions of the GPL or the LGPL are applicable instead
28
 * of those above. If you wish to allow use of your version of this file only
29
 * under the terms of either the GPL or the LGPL, and not to allow others to
30
 * use your version of this file under the terms of the MPL, indicate your
31
 * decision by deleting the provisions above and replace them with the notice
32
 * and other provisions required by the GPL or the LGPL. If you do not delete
33
 * the provisions above, a recipient may use your version of this file under
34
 * the terms of any one of the MPL, the GPL or the LGPL.
35
 *
36
 * ***** END LICENSE BLOCK ***** */
37
38
#include "nsISupports.idl"
39
40
interface nsIURI;
41
interface nsIHttpChannel;
42
interface nsIDocShell;
43
44
/**
45
 * IContentSecurityPolicy  
46
 * Describes an XPCOM component used to model an enforce CSPs.
47
 */
48
49
[scriptable, uuid(AB36A2BF-CB32-4AA6-AB41-6B4E4444A221)]
50
interface IContentSecurityPolicy : nsISupports
51
{
52
53
  /**
54
   * Set to true when the CSP has been read in and parsed and is ready to
55
   * enforce.  This is a barrier for the nsDocument so it doesn't load any
56
   * sub-content until either it knows that a CSP is ready or will not be used.
57
   */
58
  attribute boolean isInitialized;
59
60
  /**
61
   * When set to true, content load-blocking and fail-closed are disabled: CSP
62
   * will ONLY send reports, and not modify behavior.
63
   */
64
  attribute boolean reportOnlyMode;
65
66
  /**
67
   * A read-only string version of the policy for debugging.
68
   */
69
  readonly attribute AString policy;
70
71
  /**
72
   * Whether this policy allows in-page script
73
   */
74
  readonly attribute boolean allowsInlineScript;
75
76
  /**
77
   * whether this policy allows eval and eval-like functions
78
   * such as setTimeout("code string", time)
79
   */
80
  readonly attribute boolean allowsEval;
81
82
  /**
83
   * Triggers violation report sending given a URI and reason.
84
   * The URI may be null, in which case "self" is sent.
85
   * @param blockedURI
86
   *     the URI that violated the policy
87
   * @param violatedDirective
88
   *     the directive that was violated.
89
   * @return 
90
   *     nothing.
91
   */
92
  void sendReports(in AString blockedURI, in AString violatedDirective);
93
94
  /**
95
   * Called after the CSP object is created to fill in the appropriate request
96
   * and request header information needed in case a report needs to be sent.
97
   */
98
  void scanRequestData(in nsIHttpChannel aChannel);
99
100
  /**
101
   * Updates the policy currently stored in the CSP to be "refined" or
102
   * tightened by the one specified in the string policyString.
103
   */
104
  void refinePolicy(in AString policyString, in nsIURI selfURI);
105
106
  /**
107
   * Verifies ancestry as permitted by the policy.
108
   * @param docShell
109
   *    containing the protected resource
110
   * @return
111
   *    true if the frame's ancestors are all permitted by policy
112
   */
113
  boolean permitsAncestry(in nsIDocShell docShell);
114
115
  /**
116
   * Delegate method called by the service when sub-elements of the protected
117
   * document are being loaded.  Given a bit of information about the request,
118
   * decides whether or not the policy is satisfied.
119
   */
120
  short shouldLoad(in unsigned long   aContentType, 
121
                   in nsIURI          aContentLocation, 
122
                   in nsIURI          aRequestOrigin, 
123
                   in nsISupports     aContext, 
124
                   in ACString        aMimeTypeGuess, 
125
                   in nsISupports     aExtra);
126
127
  /**
128
   * Delegate method called by the service when sub-elements of the protected
129
   * document are being processed.  Given a bit of information about the request,
130
   * decides whether or not the policy is satisfied.
131
   */
132
  short shouldProcess(in unsigned long   aContentType, 
133
                      in nsIURI          aContentLocation, 
134
                      in nsIURI          aRequestOrigin, 
135
                      in nsISupports     aContext, 
136
                      in ACString        aMimeType,
137
                      in nsISupports     aExtra);
138
139
};
(-)a/content/base/public/Makefile.in (+1 lines)
Line     Link Here 
 Lines 106-117   XPIDLSRCS = \ Link Here 
106
		nsISyncLoadDOMService.idl  \
106
		nsISyncLoadDOMService.idl  \
107
		nsIDragDropHandler.idl \
107
		nsIDragDropHandler.idl \
108
		nsIScriptEventHandler.idl \
108
		nsIScriptEventHandler.idl \
109
		nsIScriptEventManager.idl \
109
		nsIScriptEventManager.idl \
110
		nsIImageLoadingContent.idl \
110
		nsIImageLoadingContent.idl \
111
		nsIObjectLoadingContent.idl \
111
		nsIObjectLoadingContent.idl \
112
		nsIFrameLoader.idl \
112
		nsIFrameLoader.idl \
113
		nsIXMLHttpRequest.idl \
113
		nsIXMLHttpRequest.idl \
114
		IContentSecurityPolicy.idl \
114
		$(NULL)
115
		$(NULL)
115
116
116
include $(topsrcdir)/config/rules.mk
117
include $(topsrcdir)/config/rules.mk
117
118
(-)a/content/base/public/nsIDocument.h (+12 lines)
Line     Link Here 
 Lines 52-67    Link Here 
52
#include "nsCompatibility.h"
52
#include "nsCompatibility.h"
53
#include "nsTObserverArray.h"
53
#include "nsTObserverArray.h"
54
#include "nsTHashtable.h"
54
#include "nsTHashtable.h"
55
#include "nsHashKeys.h"
55
#include "nsHashKeys.h"
56
#include "nsNodeInfoManager.h"
56
#include "nsNodeInfoManager.h"
57
#include "nsIStreamListener.h"
57
#include "nsIStreamListener.h"
58
#include "nsIObserver.h"
58
#include "nsIObserver.h"
59
#include "nsAutoPtr.h"
59
#include "nsAutoPtr.h"
60
#include "IContentSecurityPolicy.h"
60
#ifdef MOZ_SMIL
61
#ifdef MOZ_SMIL
61
class nsSMILAnimationController;
62
class nsSMILAnimationController;
62
#endif // MOZ_SMIL
63
#endif // MOZ_SMIL
63
64
64
class nsIContent;
65
class nsIContent;
65
class nsPresContext;
66
class nsPresContext;
66
class nsIPresShell;
67
class nsIPresShell;
67
class nsIDocShell;
68
class nsIDocShell;
 Lines 1057-1072   public: Link Here 
1057
                    "have a presentation or a docshell or a window");
1058
                    "have a presentation or a docshell or a window");
1058
    NS_PRECONDITION(aDisplayDocument != this, "Should be different document");
1059
    NS_PRECONDITION(aDisplayDocument != this, "Should be different document");
1059
    NS_PRECONDITION(!aDisplayDocument->GetDisplayDocument(),
1060
    NS_PRECONDITION(!aDisplayDocument->GetDisplayDocument(),
1060
                    "Display documents should not nest");
1061
                    "Display documents should not nest");
1061
    mDisplayDocument = aDisplayDocument;
1062
    mDisplayDocument = aDisplayDocument;
1062
  }
1063
  }
1063
1064
1064
  /**
1065
  /**
1066
   * Return the Content Security Policy object for the document
1067
   */
1068
  IContentSecurityPolicy* GetContentSecurityPolicy() const
1069
  {
1070
    return mCSP;
1071
  }
1072
1073
  /**
1065
   * A class that represents an external resource load that has begun but
1074
   * A class that represents an external resource load that has begun but
1066
   * doesn't have a document yet.  Observers can be registered on this object,
1075
   * doesn't have a document yet.  Observers can be registered on this object,
1067
   * and will be notified after the document is created.  Observers registered
1076
   * and will be notified after the document is created.  Observers registered
1068
   * after the document has been created will NOT be notified.  When observers
1077
   * after the document has been created will NOT be notified.  When observers
1069
   * are notified, the subject will be the newly-created document, the topic
1078
   * are notified, the subject will be the newly-created document, the topic
1070
   * will be "external-resource-document-created", and the data will be null.
1079
   * will be "external-resource-document-created", and the data will be null.
1071
   * If document creation fails for some reason, observers will still be
1080
   * If document creation fails for some reason, observers will still be
1072
   * notified, with a null document pointer.
1081
   * notified, with a null document pointer.
 Lines 1275-1290   protected: Link Here 
1275
  PRUint32            mSubtreeModifiedDepth;
1284
  PRUint32            mSubtreeModifiedDepth;
1276
1285
1277
  // If we're an external resource document, this will be non-null and will
1286
  // If we're an external resource document, this will be non-null and will
1278
  // point to our "display document": the one that all resource lookups should
1287
  // point to our "display document": the one that all resource lookups should
1279
  // go to.
1288
  // go to.
1280
  nsCOMPtr<nsIDocument> mDisplayDocument;
1289
  nsCOMPtr<nsIDocument> mDisplayDocument;
1281
1290
1282
  PRUint32 mEventsSuppressed;
1291
  PRUint32 mEventsSuppressed;
1292
1293
  // CSP policy object/data
1294
  nsCOMPtr<IContentSecurityPolicy> mCSP;
1283
};
1295
};
1284
1296
1285
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
1297
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocument, NS_IDOCUMENT_IID)
1286
1298
1287
/**
1299
/**
1288
 * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
1300
 * mozAutoSubtreeModified batches DOM mutations so that a DOMSubtreeModified
1289
 * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
1301
 * event is dispatched, if necessary, when the outermost mozAutoSubtreeModified
1290
 * object is deleted.
1302
 * object is deleted.
(-)43fdf17e10a3 (+1036 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the Content Security Policy data structures.
15
 *
16
 * The Initial Developer of the Original Code is
17
 *   Mozilla Corporation
18
 *
19
 * Contributor(s):
20
 *   Sid Stamm <sid@mozilla.com>
21
 *
22
 * Alternatively, the contents of this file may be used under the terms of
23
 * either the GNU General Public License Version 2 or later (the "GPL"), or
24
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25
 * in which case the provisions of the GPL or the LGPL are applicable instead
26
 * of those above. If you wish to allow use of your version of this file only
27
 * under the terms of either the GPL or the LGPL, and not to allow others to
28
 * use your version of this file under the terms of the MPL, indicate your
29
 * decision by deleting the provisions above and replace them with the notice
30
 * and other provisions required by the GPL or the LGPL. If you do not delete
31
 * the provisions above, a recipient may use your version of this file under
32
 * the terms of any one of the MPL, the GPL or the LGPL.
33
 *
34
 * ***** END LICENSE BLOCK ***** */
35
36
/**
37
 * Content Security Policy Utilities
38
 * 
39
 * Overview
40
 * This contains a set of classes and utilities for CSP.  It is in this
41
 * separate file for testing purposes.
42
 */
43
44
// Module stuff
45
var EXPORTED_SYMBOLS = ["CSPRep", "CSPSourceList", "CSPSource", 
46
                        "CSPHost", "CSPWarning", "CSPError", "CSPdebug"];
47
48
49
//these are not exported
50
var gIoService = Components.classes["@mozilla.org/network/io-service;1"]
51
                 .getService(Components.interfaces.nsIIOService);
52
53
var gETLDService = Components.classes["@mozilla.org/network/effective-tld-service;1"]
54
                   .getService(Components.interfaces.nsIEffectiveTLDService);
55
56
57
function CSPWarning(aMsg) {
58
  //customize this to redirect output.
59
  aMsg = 'CSP WARN:  ' + aMsg + "\n";
60
  dump(aMsg);
61
  Components.classes["@mozilla.org/consoleservice;1"]
62
                    .getService(Components.interfaces.nsIConsoleService)
63
                    .logStringMessage(aMsg);
64
}
65
function CSPError(aMsg) {
66
  aMsg = 'CSP ERROR: ' + aMsg + "\n";
67
  dump(aMsg);
68
  Components.classes["@mozilla.org/consoleservice;1"]
69
                    .getService(Components.interfaces.nsIConsoleService)
70
                    .logStringMessage(aMsg);
71
}
72
function CSPdebug(aMsg) {
73
  aMsg = 'CSP debug: ' + aMsg + "\n";
74
  dump(aMsg);
75
  Components.classes["@mozilla.org/consoleservice;1"]
76
                    .getService(Components.interfaces.nsIConsoleService)
77
                    .logStringMessage(aMsg);
78
}
79
80
81
//:::::::::::::::::::::::: CLASSES ::::::::::::::::::::::::::// 
82
83
/**
84
 * Class that represents a parsed policy structure.
85
 */
86
function CSPRep() {
87
  // this gets set to true when the policy is done parsing, or when a
88
  // URI-borne policy has finished loading.
89
  this._isInitialized = false;
90
91
  this._allowEval = false;
92
  this._allowInlineScripts = false;
93
94
  // don't auto-populate _directives, so it is easier to find bugs
95
  this._directives = {};
96
97
}
98
CSPRep.SRC_DIRECTIVES = {
99
  ALLOW:            "allow",
100
  SCRIPT_SRC:       "script-src",
101
  STYLE_SRC:        "style-src",
102
  MEDIA_SRC:        "media-src",
103
  IMG_SRC:          "img-src",
104
  OBJECT_SRC:       "object-src",
105
  FRAME_SRC:        "frame-src",
106
  FRAME_ANCESTORS:  "frame-ancestors",
107
  FONT_SRC:         "font-src",
108
  XHR_SRC:          "xhr-src"
109
};
110
CSPRep.URI_DIRECTIVES = {
111
  REPORT_URI:       "report-uri",
112
  POLICY_URI:       "policy-uri"
113
};
114
115
116
/**
117
  * Factory to create a new CSPRep, parsed from a string.
118
  *
119
  * @param aStr
120
  *        string rep of a CSP
121
  * @param self (optional)
122
  *        string or CSPSource representing the "self" source
123
  * @returns
124
  *        an instance of CSPRep
125
  */
126
CSPRep.fromString = function(aStr, self) {
127
  var SD = CSPRep.SRC_DIRECTIVES;
128
  var UD = CSPRep.URI_DIRECTIVES;
129
  var pieces = aStr.split(/;\s*/);
130
  var aCSPR = new CSPRep();
131
132
  // NOTE: currently, every time a directive is encountered, its value
133
  // overwrites any previous values for the same directive.  So the policy 
134
  // "dir foo; dir bar" gets parsed as "dir bar".
135
  
136
  piece:for(var i in pieces) {
137
    //split off first token and figure out what to do
138
    var dirname = pieces[i].match(/(\S+)/)[0];
139
140
    //careful to trim the stuff so there's no extra tokens 
141
    var dirvalue = pieces[i].substring(dirname.length)
142
                            .replace(/^\s+/,'')
143
                            .replace(/\s+$/,'');
144
145
    //If it is the script-src directive, pull out "eval" and "inline"
146
    if(dirname == SD.SCRIPT_SRC) {
147
      let listchunks = dirvalue.split(/\s+/);
148
      for(let i in listchunks) {
149
        if(listchunks[i] == "'eval'") {
150
          listchunks.splice(i,1);
151
          aCSPR._allowEval = true;
152
        }
153
        if(listchunks[i] == "'inline'") {
154
          listchunks.splice(i,1);
155
          aCSPR._allowInlineScripts = true;
156
        }
157
      }
158
      // repair source list without the keywords
159
      dirvalue = listchunks.join(" ");
160
    }
161
162
    //is it a SRC directive?
163
    for(var sdi in SD) {
164
      if(dirname == SD[sdi]) {
165
        var dv = CSPSourceList.fromString(dirvalue, self);
166
        if(dv) {  // fromString() can return null if the list is bad
167
          aCSPR._directives[SD[sdi]] = dv;
168
          continue piece;
169
        }
170
      }
171
    }
172
173
    //not a SRC directive, check URI directives
174
175
    // POLICY URI //////////////////////////////////////////////////////////
176
    if(dirname == UD.POLICY_URI) {
177
      // POLICY_URI can only be alone
178
      if(aCSPR._directives.length > 0 || pieces.length > 1) {
179
        CSPError("policy-uri directive can only appear alone");
180
        return CSPRep.fromString("allow 'none'");
181
      }
182
183
      var uri = '';
184
      try {
185
        uri = gIoService.newURI(dirvalue, null, null);
186
      } catch(e) {
187
        CSPError("could not parse URI in policy URI: " + dirvalue);
188
        return CSPRep.fromString("allow 'none'");
189
      }
190
      
191
      // Verify that policy URI comes from the same origin
192
      if(self) {
193
        var selfUri = gIoService.newURI(self.toString(), null, null);
194
        if(selfUri.host !== uri.host){
195
          CSPError("can't fetch policy uri from non-matching hostname: " + uri.host);
196
          return CSPRep.fromString("allow 'none'");
197
        }
198
        if(selfUri.port !== uri.port){
199
          CSPError("can't fetch policy uri from non-matching port: " + uri.port);
200
          return CSPRep.fromString("allow 'none'");
201
        }
202
        if(selfUri.scheme !== uri.scheme){
203
          CSPError("can't fetch policy uri from non-matching scheme: " + uri.scheme);
204
          return CSPRep.fromString("allow 'none'");
205
        }
206
      }
207
208
      var req = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"]  
209
                  .createInstance(Components.interfaces.nsIXMLHttpRequest);  
210
211
      // insert error hook
212
      req.onerror = CSPError;
213
214
      // synchronous -- otherwise we need to architect a callback into the
215
      // xpcom component so that whomever creates the policy object gets
216
      // notified when it's loaded and ready to go.
217
      req.open("GET", dirvalue, false);
218
219
      // make request anonymous
220
      // This prevents sending cookies with the request, in case the policy URI
221
      // is injected, it can't be abused for CSRF.
222
      req.channel.loadFlags |= Components.interfaces.nsIChannel.LOAD_ANONYMOUS;
223
224
      //CSPdebug("Fetching URI " + dirvalue);
225
      req.send(null);  
226
      if(req.status == 200) {
227
        //CSPdebug("XHR returned: " + req.responseText);
228
        aCSPR = CSPRep.fromString(req.responseText, self);
229
        //remember where we got the policy
230
        aCSPR._directives[UD.POLICY_URI] = dirvalue;
231
        return aCSPR;
232
      }
233
      CSPError("Error fetching policy URI: server response was " + req.status);
234
      return CSPRep.fromString("allow 'none'");
235
    }
236
237
    // REPORT URI //////////////////////////////////////////////////////////
238
    if(dirname == UD.REPORT_URI) {
239
      // supporting a space-separated list of URIs
240
      var uriStrings = dirvalue.split(/\s+/);
241
      var okUriStrings = [];
242
      var selfUri = self ? gIoService.newURI(self.toString(),null,null) : null;
243
244
      // Verify that each report URI is in the same etld + 1
245
      // if "self" is defined, and just that it's valid otherwise.
246
      for(let i in uriStrings) {
247
        try {
248
          var uri = gIoService.newURI(uriStrings[i]);
249
          if(self) {
250
            if( gETLDService.getBaseDomain(uri) === 
251
                gETLDService.getBaseDomain(selfUri) ) {
252
              okUriStrings.push(uriStrings[i]);
253
            } else {
254
              CSPWarning("can't use report URI from non-matching eTLD+1: "
255
                         + gETLDService.getBaseDomain(uri));
256
            }
257
          }
258
        } catch(e) {
259
          CSPWarning("couldn't parse report URI: " + dirvalue);
260
        }
261
      }
262
      aCSPR._directives[UD.REPORT_URI] = okUriStrings.join(' ');
263
264
      continue piece;
265
    }
266
267
    //no directives matched
268
    CSPWarning("Couldn't process unknown directive '" + dirname + "'");
269
  }
270
271
  if(aCSPR._directives.length < 1) {
272
    CSPError("invalid policy -- no recognized directives");
273
    return CSPRep.fromString("allow 'none'");
274
  }
275
276
  if(!aCSPR._directives[SD.ALLOW]) {
277
    CSPWarning("allow directive is not present, using \"allow 'none'\"");
278
    aCSPR._directives[SD.ALLOW] = CSPSourceList.fromString("'none'");
279
  }
280
281
  aCSPR.makeExplicit();
282
  return aCSPR;
283
};
284
285
CSPRep.prototype = {
286
  /**
287
   * Returns array of all report uris defined, or 'none' if there are none.
288
   */
289
  getReportURIs:
290
  function() {
291
    if(!this._directives[CSPRep.URI_DIRECTIVES.REPORT_URI])
292
      return [];
293
294
    var uris = this._directives[CSPRep.URI_DIRECTIVES.REPORT_URI].split(",");
295
    for(let i in uris) {
296
      //trim off surrounding whitespace
297
      uris[i] = uris[i].replace(/^\s+/, "").replace(/\s+$/, "");
298
    }
299
    return uris;
300
  },
301
302
  /**
303
   * Compares this CSPRep instance to another.
304
   */
305
  equals:
306
  function(that) {
307
    if(this._directives.length != that._directives.length) {
308
      return false;
309
    }
310
    for(var i in this._directives) {
311
      if(!that._directives[i] || !this._directives[i].equals(that._directives[i])) {
312
        return false;
313
      }
314
    }
315
    return true;
316
  },
317
318
  /**
319
   * Generates string representation of the policy.  Should be fairly similar
320
   * to the original.
321
   */
322
  toString:
323
  function csp_toString() {
324
    var dirs = [];
325
    for(var i in this._directives) {
326
      if(this._directives[i]) {
327
        dirs.push(i + " " + this._directives[i].toString());
328
      }
329
    }
330
    return dirs.join("; ");
331
  },
332
333
334
  /**
335
   * Determines if this policy accepts a URI.
336
   * @param aContext
337
   *        one of the SRC_DIRECTIVES defined above
338
   * @returns 
339
   *        true if the policy permits the URI in given context.
340
   */
341
  permits:
342
  function csp_permits(aURI, aContext) {
343
344
    // GLOBALLY ALLOW "about:" SCHEME
345
    if(aURI instanceof String && aURI.substring(0,6) == "about:") {
346
      return true;
347
    }
348
    if(aURI instanceof Components.interfaces.nsIURI
349
        && aURI.scheme == "about") {
350
      return true;
351
    }
352
353
    //make sure the context is valid
354
    for(var i in CSPRep.SRC_DIRECTIVES) {
355
      if(CSPRep.SRC_DIRECTIVES[i] == aContext) {
356
        return this._directives[aContext].permits(aURI);
357
      }
358
    }
359
    return false;
360
  },
361
362
  /**
363
   * Intersects with another CSPRep, deciding the subset policy 
364
   * that should be enforced, and returning a new instance.
365
   * @param aCSPRep
366
   *        a CSPRep instance to use as "other" CSP
367
   * @returns
368
   *        a new CSPRep instance of the intersection
369
   */
370
  intersectWith:
371
  function cspsd_intersectWith(aCSPRep) {
372
    var newRep = new CSPRep();
373
374
    for(var dir in CSPRep.SRC_DIRECTIVES) {
375
      var dirv = CSPRep.SRC_DIRECTIVES[dir];
376
      newRep._directives[dirv] = this._directives[dirv]
377
               .intersectWith(aCSPRep._directives[dirv]);
378
    }
379
    return newRep;
380
  },
381
382
383
  /**
384
   * Copies default source list to each unspecified directive.
385
   * @returns
386
   *      true  if the makeExplicit succeeds
387
   *      false if it fails (for some weird reason)
388
   */
389
  makeExplicit:
390
  function cspsd_makeExplicit() {
391
    var SD = CSPRep.SRC_DIRECTIVES;
392
    var allowDir = this._directives[SD.ALLOW];
393
    if(!allowDir) {
394
      return false;
395
    }
396
397
    for(var dir in SD) {
398
      var dirv = SD[dir];
399
      if(dirv == SD.ALLOW) {
400
        continue;
401
      }
402
      if(!this._directives[dirv]) {
403
        //implicit directive, make explicit
404
        this._directives[dirv] = allowDir.clone();
405
      }
406
    }
407
    this._isInitialized = true;
408
    return true;
409
  },
410
411
  /**
412
   * Returns true if "eval" is enabled through the "eval" keyword.
413
   */
414
  get allowsEvalInScripts () {
415
    return this._allowEval;
416
  },
417
418
  /**
419
   * Returns true if inline scripts are enabled through the "inline"
420
   * keyword.
421
   */
422
  get allowsInlineScripts () {
423
    return this._allowInlineScripts;
424
  },
425
};
426
427
428
//////////////////////////////////////////////////////////////////////
429
/**
430
 * Class to represent a list of sources 
431
 */
432
function CSPSourceList() {
433
  this._sources = [];
434
  this._permitAllSources = false;
435
}
436
437
/**
438
 * Factory to create a new CSPSourceList, parsed from a string.
439
 *
440
 * @param aStr
441
 *        string rep of a CSP Source List
442
 * @param self (optional)
443
 *        string or CSPSource representing the "self" source
444
 * @returns
445
 *        an instance of CSPSourceList 
446
 */
447
CSPSourceList.fromString = function(aStr, self) {
448
  //Source list is:
449
  //    <host-dir-value> ::= <source-list>
450
  //                       | "'none'"
451
  //    <source-list>    ::= <source>
452
  //                       | <source-list>" "<source>
453
454
  var slObj = new CSPSourceList();
455
  if(aStr == "'none'") {
456
    return slObj;
457
  }
458
459
  var ss = aStr.split(/\s+/);
460
  for(var i in ss) {
461
    var o = CSPSource.fromString(ss[i], self);
462
463
    //skip sources that don't parse
464
    if(o)
465
      slObj._sources[i] = o;
466
    else
467
      CSPWarning("Failed to parse invalid source: " + ss[i]);
468
  }
469
  return slObj;
470
};
471
472
CSPSourceList.prototype = {
473
474
  /**
475
   * Compares one CSPSourceList to another.
476
   *
477
   * @param that
478
   *        another CSPSourceList
479
   * @returns 
480
   *        true if they have the same data
481
   */
482
  equals:
483
  function(that) {
484
    if(that._sources.length != this._sources.length) {
485
      return false;
486
    }
487
    //sort both arrays and compare like a zipper
488
    //XXX (sid): I think we can make this more efficient
489
    var sortfn = function(a,b) {
490
      return a.toString() > b.toString();
491
    };
492
    var a_sorted = this._sources.sort(sortfn);
493
    var b_sorted = that._sources.sort(sortfn);
494
    for(var i in a_sorted) {
495
      if(!a_sorted[i].equals(b_sorted[i])) {
496
        return false;
497
      }
498
    }
499
    return true;
500
  },
501
502
  /**
503
   * Generates string representation of the Source List.
504
   * Should be fairly similar to the original.
505
   */
506
  toString:
507
  function() {
508
    if(this.isNone()) {
509
      return "'none'";
510
    }
511
    return this._sources.map(function(x) { return x.toString(); }).join(" ");
512
  },
513
514
  /**
515
   * Returns whether or not this source list represents the "'none'" special
516
   * case.
517
   */
518
  isNone:
519
  function() {
520
    return (!this._permitAllSources) && (this._sources.length < 1);
521
  },
522
523
  /**
524
   * Makes a new instance that resembles this object.
525
   * @returns
526
   *      a new CSPSourceList
527
   */
528
  clone:
529
  function() {
530
    var aSL = new CSPSourceList();
531
    aSL._permitAllSources = this._permitAllSources;
532
    for(var i in this._sources) {
533
      aSL._sources[i] = this._sources[i].clone();
534
    }
535
    return aSL;
536
  },
537
538
539
  /**
540
   * Determines if this directive accepts a URI.
541
   * @param aURI
542
   *        the URI in question
543
   * @returns
544
   *        true if the URI matches a source in this source list.
545
   */
546
  permits:
547
  function cspsd_permits(aURI) {
548
    if(this.isNone()) {
549
      return false;
550
    }
551
    for(var i in this._sources) {
552
      if(this._sources[i].permits(aURI)) {
553
        return true;
554
      }
555
    }
556
    return false;
557
  },
558
559
560
  /**
561
   * Intersects with another CSPSourceList, deciding the subset directive
562
   * that should be enforced, and returning a new instance.
563
   * @param that 
564
   *        the other CSPSourceList to intersect "this" with
565
   * @returns
566
   *        a new instance of a CSPSourceList representing the intersection
567
   */
568
  intersectWith:
569
  function cspsd_intersectWith(that) {
570
    if(this._permitAllSources) {
571
      return that.clone();
572
    }
573
    if(that._permitAllSources) {
574
      return this.clone();
575
    }
576
577
    // "'none'" case
578
    if(this.isNone() || that.isNone()) {
579
      return CSPSourceList.fromString("'none'");
580
    }
581
582
    // --  find only common sources
583
584
    //XXX (sid): figure out a good algorithm for this.
585
    // This is horribly inefficient. O(n^2)
586
    var isrcs = [];
587
    for(var i in this._sources) {
588
      for(var j in that._sources) {
589
        var s = that._sources[j].intersectWith(this._sources[i]);
590
        if(s) {
591
          isrcs.push(s);
592
        }
593
      }
594
    }
595
    //Next, remove duplicates
596
    dup:for(var i = 0; i < isrcs.length; i++) {
597
      for(var j = 0; j < i; j++) {
598
        if(isrcs[i].equals(isrcs[j])) {
599
          isrcs.splice(i, 1);
600
          i--;
601
          continue dup;
602
        }
603
      }
604
    }
605
    var newCSPSrcList = new CSPSourceList();
606
    newCSPSrcList._sources = isrcs;
607
    return newCSPSrcList;
608
  }
609
}
610
611
612
//////////////////////////////////////////////////////////////////////
613
/**
614
 * Class to model a source (scheme, host, port)
615
 */
616
function CSPSource() {
617
  this._scheme = "*";
618
  this._port = "*";
619
  this._host = CSPHost.fromString("*");
620
}
621
622
/**
623
 * Factory to create a new CSPSource, from a nsIURI.
624
 *
625
 * @param aURI
626
 *        nsIURI rep of a URI
627
 * @param self (optional)
628
 *        string or CSPSource representing the "self" source
629
 * @returns
630
 *        an instance of CSPSource 
631
 */
632
CSPSource.fromURI = function(aURI, self) {
633
634
  if( !(aURI instanceof Components.interfaces.nsIURI) ){
635
    CSPError("Provided argument is not an nsIURI");
636
    return null;
637
  }
638
639
  if(typeof self === "string") {
640
    self = CSPSource.fromString(self);
641
  }
642
643
  var sObj = new CSPSource();
644
645
  try {
646
    //if there was a scheme...
647
    sObj._scheme = aURI.scheme;
648
  } catch (e) {
649
    // aaah!  No scheme even though we tried two methods to force a scheme into
650
    // the source.
651
      CSPError("failed parsing source: '" + aURI.asciiSpec + "'");
652
      return null;
653
  }
654
655
  //now, check if there was a host
656
  try {
657
    sObj._host = CSPHost.fromString(aURI.host);
658
659
    //and if there was a host, copy the port (if present)
660
    if(aURI.port > 0) {
661
      sObj._port = aURI.port;
662
    } else {
663
      // either port was absent or *.
664
      // If empty, the port is inherited from "self"
665
      if(aStr.substr(-2) === ":*")
666
        sObj._port = "*";
667
      else 
668
        sObj._port = self._port;
669
    }
670
  } catch(e) {
671
    // no host! (or an error getting the port)
672
    // It's ok if there's no host (scheme-only sources like javascript:
673
    // allowed).
674
    // Copy in any data that needs to be inherited, but if there's no 
675
    // host, there's no need for a port either.  "*" as host _WILL_ be 
676
    // parsed correctly by newURI(), and won't throw an exception 
677
    // putting us here.
678
    if(sObj._host && !sObj._port)
679
      sObj._port = self._port;
680
  }
681
  return sObj;
682
};
683
684
/**
685
 * Factory to create a new CSPSource, parsed from a string.
686
 *
687
 * @param aStr
688
 *        string rep of a CSP Source
689
 * @param self (optional)
690
 *        string or CSPSource representing the "self" source
691
 * @returns
692
 *        an instance of CSPSource 
693
 */
694
CSPSource.fromString = function(aStr, self) {
695
  //take care of 'self' keyword
696
  if(aStr == "'self'") {
697
    if(typeof self === 'undefined') {
698
      CSPError("self keyword used, but no self data specified");
699
      return null;
700
    } 
701
    if(self == "'self'") {
702
      CSPError("self reference cannot be 'self'");
703
      return null;
704
    }
705
    if(self instanceof CSPSource) { 
706
      return self.clone();
707
    }
708
    return CSPSource.fromString(self);
709
  }
710
711
  if(typeof self === "string") {
712
    self = CSPSource.fromString(self);
713
  }
714
715
716
  let chunks = aStr.split(":");
717
  // Workaround for problems:
718
  // - "*" not parsed right by the URI parser
719
  //    ... solution: special case for the * source
720
  if(aStr == "*")
721
    return new CSPSource(); //default is *://*:*
722
    
723
  // - a.com is not easily parsed by gIoService.newURI(), need to add a scheme
724
  // - a.com:20 is ambiguous.  Could mean scheme = a.com, or host = a.com to
725
  //   the io-service URI parser
726
  //    ... but since :20 is not a valid host, CSP should treat it as a
727
  //        host:port combination.
728
  //    ... not a problem for three-chunk values like x:a.com:20
729
  //    ... solution: prepend self's scheme
730
  if(chunks.length == 1 || chunks.length == 2 && chunks[1].match(/^\d+$/)) {
731
    if(!self) {
732
      CSPError("can't parse ambiguous source: '" + aStr + "' without 'self' defined");
733
      return null;
734
    }
735
    aStr = self._scheme + "://" + aStr;
736
  }
737
738
  // - ports are not validated ('3f' is turned into '-1')
739
  //    ... solution: validate ports manually
740
  if(chunks.length == 3 && !(chunks[2].match(/^\d+$/) || chunks[2] === "*")) {
741
    CSPError("invalid port string: '" + chunks[2] + "' not entirely numeric.");
742
    return null;
743
  }
744
745
  // Try to parse the URI 
746
  var uriSource;
747
  try {
748
    uriSource = gIoService.newURI(aStr, null, null);
749
  } catch(e) {
750
    try {
751
      //this means there was no scheme specified, or the URI was malformed.
752
      // Need to use backup parsing mechanism here, with "self" defining the
753
      // scheme.
754
      let bStr = self._scheme + "://" + aStr;
755
      uriSource = gIoService.newURI(bStr, null, null);
756
    } catch(e) {
757
      //fatal error!  Can't parse.. there must be a scheme or at least a
758
      //parseable host!
759
      CSPError("failed parsing source: '" + aStr + "'");
760
      return null;
761
    }
762
  }
763
  return CSPSource.fromURI(uriSource);
764
};
765
766
CSPSource.prototype = {
767
768
  /**
769
   * Generates string representation of the Source.
770
   * Should be fairly similar to the original.
771
   */
772
  toString:
773
  function() {
774
    var s = this._host;
775
    if(this._port && this._port != "*") {
776
      s = s + ":" + this._port;
777
    }
778
    if(this._scheme && this._scheme != "*") {
779
      s = this._scheme + "://" + s;
780
    }
781
    return s;
782
  },
783
784
  /**
785
   * Makes a new instance that resembles this object.
786
   * @returns
787
   *      a new CSPSource
788
   */
789
  clone:
790
  function() {
791
    var aClone = new CSPSource();
792
    aClone._scheme = this._scheme;
793
    aClone._port = this._port;
794
    aClone._host = this._host ? this._host.clone() : null;
795
    return aClone;
796
  },
797
798
  /**
799
   * Determines if this Source accepts a URI.
800
   * @param aURI
801
   *        the URI in question
802
   * @returns
803
   *        true if the URI matches a source in this source list.
804
   */
805
  permits:
806
  function(aSource) {
807
    if(aSource instanceof Components.interfaces.nsIURI) {
808
      //figure out based on URI
809
      return this.permits(CSPSource.fromURI(aSource));
810
    }
811
    if(!(aSource instanceof CSPSource)) {
812
      //convert to CSPSource first
813
      return this.permits(CSPSource.fromString(aSource));
814
    }
815
816
    //verify scheme, host, and port
817
    if(    (this._scheme == "*" || this._scheme == aSource._scheme)
818
        && (this._port == "*"   || this._port == aSource._port)    ){
819
      return this._host === "*" ||
820
             this._host.permits(aSource._host);
821
    }
822
    // something didn't match.
823
    return false;
824
  },
825
826
  /**
827
   * Determines the intersection of two sources.
828
   * Returns a null object if intersection generates no
829
   * hosts that satisfy it.
830
   * @param that 
831
   *        the other CSPSource to intersect "this" with
832
   * @returns
833
   *        a new instance of a CSPSource representing the intersection
834
   */
835
  intersectWith:
836
  function(that) {
837
    var newSource = new CSPSource();
838
839
    //port
840
    if(this._port == "*") { 
841
      newSource._port = that._port;
842
    } else if(that._port == "*") { 
843
      newSource._port = this._port;
844
    } else if(that._port == this._port) {
845
      newSource._port = this._port;
846
    } else {
847
      //CSPError("Could not intersect " + this + " with " + that
848
      //         + " due to port problems.");
849
      return null;
850
    }
851
852
    //scheme
853
    if(this._scheme == "*") { 
854
      newSource._scheme = that._scheme;
855
    } else if(that._scheme == "*") { 
856
      newSource._scheme = this._scheme;
857
    } else if(that._scheme == this._scheme) {
858
      newSource._scheme = this._scheme;
859
    } else {
860
      //CSPError("Could not intersect " + this + " with " + that
861
      //         + " due to scheme problems.");
862
      return null;
863
    }
864
865
    //host
866
    if(this._host)
867
      newSource._host = this._host.intersectWith(that._host);
868
869
    return newSource._host ? newSource : null;
870
  },
871
872
  /**
873
   * Compares one CSPSource to another.
874
   *
875
   * @param that
876
   *        another CSPSource
877
   * @returns 
878
   *        true if they have the same data
879
   */
880
  equals:
881
  function(aSrc) {
882
    return this._scheme == aSrc._scheme
883
        && this._port == aSrc._port
884
        && this._host.equals(aSrc._host);
885
  }
886
};
887
  
888
889
//////////////////////////////////////////////////////////////////////
890
/**
891
 * Class to model a host *.x.y.
892
 */
893
function CSPHost() {
894
  this._segments = [];
895
}
896
897
/**
898
 * Factory to create a new CSPHost, parsed from a string.
899
 *
900
 * @param aStr
901
 *        string rep of a CSP Host 
902
 * @returns
903
 *        an instance of CSPHost
904
 */
905
CSPHost.fromString = function(aStr) {
906
  var hObj = new CSPHost();
907
  hObj._segments = aStr.split(/\./);
908
  if(hObj._segments.length < 1 ||
909
     hObj._segments.length == 1 && hObj._segments[0] != "*"
910
                                && hObj._segments[0] != "localhost") {
911
    //only short hosts allowed are "*" and "localhost"
912
    return null;
913
  }
914
  //TODO: double-check that each segment is appropriate:
915
  //  -- if there's a * it must be first
916
  //  all segments are LDH (except *)
917
  return hObj;
918
};
919
920
CSPHost.prototype = {
921
  /**
922
   * Generates string representation of the Source.
923
   * Should be fairly similar to the original.
924
   */
925
  toString:
926
  function() {
927
    return this._segments.join(".");
928
  },
929
930
  /**
931
   * Makes a new instance that resembles this object.
932
   * @returns
933
   *      a new CSPHost
934
   */
935
  clone:
936
  function() {
937
    var aHost = new CSPHost();
938
    for(var i in this._segments) {
939
      aHost._segments[i] = this._segments[i];
940
    }
941
    return aHost;
942
  },
943
944
  /**
945
   * Returns true if this host accepts the provided host (or the other way
946
   * around).
947
   * @param aHost
948
   *        the FQDN in question (CSPHost or String)
949
   * @returns
950
   */
951
  permits:
952
  function(aHost) {
953
    if(!(aHost instanceof CSPHost)) {
954
      // -- compare CSPHost to String
955
      return this.permits(CSPHost.fromString(aHost));
956
    }
957
    var thislen = this._segments.length;
958
    var thatlen = aHost._segments.length;
959
960
    // don't accept a less specific host: 
961
    //   \--> *.b.a doesn't accept b.a.
962
    if(thatlen < thislen) { return false; }
963
964
    // check for more specific host (and wildcard):
965
    //   \--> *.b.a accepts d.c.b.a.
966
    //   \--> c.b.a doesn't accept d.c.b.a.
967
    if((thatlen > thislen) && this._segments[0] != "*") {
968
      return false;
969
    }
970
971
    // Given the wildcard condition (from above), 
972
    // only necessary to compare elements that are present
973
    // in this host.  Extra tokens in aHost are ok. 
974
    // * Compare from right to left.
975
    for(var i=1; i <= thislen; i++) {
976
      if( this._segments[thislen-i] != "*" && 
977
          (this._segments[thislen-i] != aHost._segments[thatlen-i]) ) {
978
        return false;
979
      }
980
    }
981
982
    //at this point, all conditions are met, so the host is allowed
983
    return true;
984
  },
985
986
  /**
987
   * Determines the intersection of two Hosts.
988
   * Basically, they must be the same, or one must have a wildcard.
989
   * @param that 
990
   *        the other CSPHost to intersect "this" with
991
   * @returns
992
   *        a new instance of a CSPHost representing the intersection
993
   *        (or null, if they can't be intersected)
994
   */
995
  intersectWith:
996
  function(that) {
997
    if(!(this.permits(that) || that.permits(this))) {
998
      // host definitions cannot co-exist without a more general host
999
      // ... one must be a subset of the other, or intersection makes no sense.
1000
      return null;
1001
    } 
1002
1003
    // pick the more specific one, if both are same length.
1004
    if(this._segments.length == that._segments.length) {
1005
      // *.a vs b.a : b.a
1006
      return (this._segments[0] == "*") ? that.clone() : this.clone();
1007
    }
1008
1009
    //different lengths...
1010
    // *.b.a vs *.a : *.b.a
1011
    // *.b.a vs d.c.b.a : d.c.b.a
1012
    return (this._segments.length > that._segments.length) 
1013
            ? this.clone() : that.clone();
1014
  },
1015
1016
  /**
1017
   * Compares one CSPHost to another.
1018
   *
1019
   * @param that
1020
   *        another CSPHost
1021
   * @returns 
1022
   *        true if they have the same data
1023
   */
1024
  equals:
1025
  function(that) {
1026
    if(this._segments.length != that._segments.length) {
1027
      return false;
1028
    }
1029
    for(var i=0; i<this._segments.length; i++) {
1030
      if(this._segments[i] != that._segments[i]) {
1031
        return false;
1032
      }
1033
    }
1034
    return true;
1035
  }
1036
};
(-)a/content/base/src/Makefile.in (-1 / +9 lines)
Line     Link Here 
 Lines 117-132   CPPSRCS = \ Link Here 
117
		nsContentAreaDragDrop.cpp \
117
		nsContentAreaDragDrop.cpp \
118
		nsContentIterator.cpp \
118
		nsContentIterator.cpp \
119
		nsContentList.cpp \
119
		nsContentList.cpp \
120
		nsContentPolicy.cpp \
120
		nsContentPolicy.cpp \
121
		nsContentSink.cpp \
121
		nsContentSink.cpp \
122
		nsContentUtils.cpp \
122
		nsContentUtils.cpp \
123
		nsCopySupport.cpp \
123
		nsCopySupport.cpp \
124
		nsCrossSiteListenerProxy.cpp \
124
		nsCrossSiteListenerProxy.cpp \
125
		nsCSPService.cpp \
125
		nsDataDocumentContentPolicy.cpp \
126
		nsDataDocumentContentPolicy.cpp \
126
		nsDOMAttribute.cpp \
127
		nsDOMAttribute.cpp \
127
		nsDOMAttributeMap.cpp \
128
		nsDOMAttributeMap.cpp \
128
		nsDOMDocumentType.cpp \
129
		nsDOMDocumentType.cpp \
129
		nsDOMFile.cpp \
130
		nsDOMFile.cpp \
130
		nsDOMLists.cpp \
131
		nsDOMLists.cpp \
131
		nsDOMParser.cpp \
132
		nsDOMParser.cpp \
132
		nsDOMSerializer.cpp \
133
		nsDOMSerializer.cpp \
 Lines 177-193   CPPSRCS = \ Link Here 
177
		$(NULL)
178
		$(NULL)
178
179
179
GQI_SRCS = contentbase.gqi
180
GQI_SRCS = contentbase.gqi
180
181
181
# we don't want the shared lib, but we want to force the creation of a
182
# we don't want the shared lib, but we want to force the creation of a
182
# static lib.
183
# static lib.
183
FORCE_STATIC_LIB = 1
184
FORCE_STATIC_LIB = 1
184
185
185
EXTRA_COMPONENTS = $(srcdir)/nsBadCertHandler.js
186
EXTRA_COMPONENTS = \
187
		$(srcdir)/nsBadCertHandler.js \
188
		contentSecurityPolicy.js \
189
		$(NULL)
190
191
EXTRA_JS_MODULES = \
192
		CSPUtils.jsm \
193
		$(NULL)
186
194
187
include $(topsrcdir)/config/rules.mk
195
include $(topsrcdir)/config/rules.mk
188
196
189
INCLUDES	+= \
197
INCLUDES	+= \
190
		-I$(srcdir)/../../events/src \
198
		-I$(srcdir)/../../events/src \
191
		-I$(srcdir)/../../xml/content/src \
199
		-I$(srcdir)/../../xml/content/src \
192
		-I$(srcdir)/../../xul/base/src \
200
		-I$(srcdir)/../../xul/base/src \
193
		-I$(srcdir)/../../xul/content/src \
201
		-I$(srcdir)/../../xul/content/src \
(-)43fdf17e10a3 (+371 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the ContentSecurityPolicy module.
15
 *
16
 * The Initial Developer of the Original Code is
17
 *   Mozilla Corporation
18
 *
19
 * Contributor(s):
20
 *   Sid Stamm <sid@mozilla.com>
21
 *   Brandon Sterne <bsterne@mozilla.com>
22
 *
23
 * Alternatively, the contents of this file may be used under the terms of
24
 * either the GNU General Public License Version 2 or later (the "GPL"), or
25
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
 * in which case the provisions of the GPL or the LGPL are applicable instead
27
 * of those above. If you wish to allow use of your version of this file only
28
 * under the terms of either the GPL or the LGPL, and not to allow others to
29
 * use your version of this file under the terms of the MPL, indicate your
30
 * decision by deleting the provisions above and replace them with the notice
31
 * and other provisions required by the GPL or the LGPL. If you do not delete
32
 * the provisions above, a recipient may use your version of this file under
33
 * the terms of any one of the MPL, the GPL or the LGPL.
34
 *
35
 * ***** END LICENSE BLOCK ***** */
36
37
38
/**
39
 * Content Security Policy
40
 * 
41
 * Overview
42
 * This is a stub component that will be fleshed out to do all the fancy stuff
43
 * that ContentSecurityPolicy has to do.
44
 */
45
46
/* :::::::: Constants and Helpers ::::::::::::::: */
47
48
const Cc = Components.classes;
49
const Ci = Components.interfaces;
50
const Cr = Components.results;
51
const Cu = Components.utils;
52
53
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
54
Cu.import("resource://gre/modules/CSPUtils.jsm");
55
56
/* ::::: Policy Parsing & Data structures :::::: */
57
58
function ContentSecurityPolicy() {
59
  CSPdebug("CSP CREATED");
60
  this._isInitialized = false;
61
  this._reportOnlyMode = false;
62
  this._policy = CSPRep.fromString("allow *");
63
  this._requestHeaders = []; 
64
  this._request = "";
65
  CSPdebug("CSP POLICY INITED TO 'allow *'");
66
}
67
68
/*
69
 * Set up mappings from nsIContentPolicy content types to CSP directives.
70
 */
71
with(Ci.nsIContentPolicy) {
72
  let csp = ContentSecurityPolicy;
73
  let cspr_sd = CSPRep.SRC_DIRECTIVES;
74
75
  csp._MAPPINGS=[];
76
77
  /* default, catch-all case */
78
  csp._MAPPINGS[TYPE_OTHER]             =  cspr_sd.ALLOW;
79
80
  /* self */
81
  csp._MAPPINGS[TYPE_DOCUMENT]          =  null;
82
83
  /* shouldn't see this one */
84
  csp._MAPPINGS[TYPE_REFRESH]           =  null;
85
86
  /* categorized content types */
87
  csp._MAPPINGS[TYPE_SCRIPT]            = cspr_sd.SCRIPT_SRC;
88
  csp._MAPPINGS[TYPE_IMAGE]             = cspr_sd.IMG_SRC;
89
  csp._MAPPINGS[TYPE_STYLESHEET]        = cspr_sd.STYLE_SRC;
90
  csp._MAPPINGS[TYPE_OBJECT]            = cspr_sd.OBJECT_SRC;
91
  csp._MAPPINGS[TYPE_SUBDOCUMENT]       = cspr_sd.FRAME_SRC;
92
  csp._MAPPINGS[TYPE_MEDIA]             = cspr_sd.MEDIA_SRC;
93
  csp._MAPPINGS[TYPE_FONT]              = cspr_sd.FONT_SRC;
94
  csp._MAPPINGS[TYPE_XMLHTTPREQUEST]    = cspr_sd.XHR_SRC;
95
96
97
  /* These must go through the catch-all */
98
  csp._MAPPINGS[TYPE_XBL]               = cspr_sd.ALLOW;
99
  csp._MAPPINGS[TYPE_PING]              = cspr_sd.ALLOW;
100
  csp._MAPPINGS[TYPE_OBJECT_SUBREQUEST] = cspr_sd.ALLOW;
101
  csp._MAPPINGS[TYPE_DTD]               = cspr_sd.ALLOW;
102
}
103
104
ContentSecurityPolicy.prototype = {
105
  classDescription: "Content Security Policy Component",
106
  contractID:       "@mozilla.org/contentsecuritypolicy;1",
107
  classID:          Components.ID("{AB36A2BF-CB32-4AA6-AB41-6B4E4444A221}"),
108
  QueryInterface:   XPCOMUtils.generateQI([Ci.IContentSecurityPolicy]),
109
110
  // get this contractID registered for certain categories via XPCOMUtils
111
  _xpcom_categories: [ ],
112
113
  get isInitialized() {
114
    return this._isInitialized;
115
  },
116
117
  set isInitialized (foo) {
118
    this._isInitialized = foo;
119
  },
120
121
  get policy () {
122
    return this._policy.toString();
123
  },
124
125
  get allowsInlineScript() {
126
    return this._policy.allowsInlineScripts;
127
  },
128
129
  get allowsEval() {
130
    return this._policy.allowsEvalInScripts;
131
  },
132
133
  set reportOnlyMode(val) {
134
    this._reportOnlyMode = val;
135
  },
136
137
  get reportOnlyMode () {
138
    return this._reportOnlyMode;
139
  },
140
141
  /*
142
  // Having a setter is a bad idea... opens up the policy to "loosening"
143
  // Instead, use "refinePolicy."
144
  set policy (aStr) {
145
    this._policy = CSPRep.fromString(aStr);
146
  },
147
  */
148
149
  /**
150
   * Given an nsIHttpChannel, fill out the appropriate data.
151
   */
152
  scanRequestData:
153
  function(aChannel) {
154
    // grab the request line
155
    var internalChannel = aChannel.QueryInterface(Ci.nsIHttpChannelInternal);
156
    var reqMaj = {};
157
    var reqMin = {};
158
    var reqVersion = internalChannel.getRequestVersion(reqMaj, reqMin);
159
    this._request = aChannel.requestMethod + " " 
160
                  + aChannel.URI 
161
                  + " HTTP/" + reqMaj.value + "." + reqMin.value;
162
163
    // grab the request headers
164
    var self = this;
165
    aChannel.visitRequestHeaders({
166
      visitHeader: function(aHeader, aValue) {
167
        self._requestHeaders.push(aHeader + ": " + aValue);
168
      }});
169
  },
170
171
/* ........ Methods .............. */
172
173
  /**
174
   * Given a new policy, intersects the currently enforced policy with the new
175
   * one and stores the result.  The effect is a "tightening" or refinement of
176
   * an old policy.  This is called any time a new policy is encountered and
177
   * the effective policy has to be refined.
178
   */
179
  refinePolicy:
180
  function csp_refinePolicy(aPolicy, selfURI) {
181
    CSPdebug("REFINE POLICY: " + aPolicy);
182
    CSPdebug("         SELF: " + selfURI.asciiSpec);
183
184
    // stay uninitialized until policy merging is done
185
    this._isInitialized = false;
186
187
    // If there is a policy-uri, fetch the policy, then re-call this function.
188
    // (1) parse and create a CSPRep object
189
    var newpolicy = CSPRep.fromString(aPolicy,
190
                                      selfURI.scheme + "://" + selfURI.hostPort);
191
192
    // (2) Intersect the currently installed CSPRep object with the new one
193
    var intersect = this._policy.intersectWith(newpolicy);
194
    //TODO: make sure intersect worked
195
 
196
    // (3) Save the result
197
    this._policy = intersect;
198
    this._isInitialized = true;
199
  },
200
201
  /**
202
   * Generates and sends a violation report to the specified report URIs.
203
   */
204
  sendReports:
205
  function(blockedUri, violatedDirective) {
206
    var uris = this._policy.getReportURIs();
207
    if(uris.length > 0) {
208
      // Generate report to send composed of:
209
      // <csp-report>
210
      //   <request>GET /index.html HTTP/1.1</request>
211
      //   <request-headers>Host: example.com
212
      //            User-Agent: ...
213
      //            ...
214
      //   </request-headers>
215
      //   <blocked-uri>...</blocked-uri>
216
      //   <violated-directive>...</violated-directive>
217
      // </csp-report>
218
      //   
219
      var strHeaders = "";
220
      for(let i in this._requestHeaders) {
221
        strHeaders += this._requestHeaders[i] + "\n";
222
      }
223
224
      var report = "<csp-report>\n" +
225
        " <request>" + this._request + "</request>\n" +
226
        "   <request-headers><![CDATA[\n" +
227
        strHeaders +
228
        "   ]]></request-headers>\n" +
229
        "   <blocked-uri>" + blockedUri + "</blocked-uri>\n" +
230
        "   <violated-directive>" + violatedDirective + "</violated-directive>\n" +
231
        "</csp-report>\n";
232
233
      // For each URI in the report list, send out a report.
234
      for(let i in uris) {
235
        var failure = function(aEvt) {  
236
          if(req.readyState == 4 && req.status != 200) {
237
            CSPError("Failed to send report to " + reportURI);
238
          }  
239
        };  
240
        var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]  
241
                    .createInstance(Ci.nsIXMLHttpRequest);  
242
243
        req.open("POST", uris[i], true);
244
        req.setRequestHeader('Content-Type', 'application/xml');
245
        req.upload.addEventListener("error", failure, false);  
246
        req.upload.addEventListener("abort", failure, false);  
247
        //req.channel.loadFlags |= Ci.nsIRequest.LOAD_BYPASS_CACHE;
248
 
249
        // make request anonymous
250
        // This prevents sending cookies with the request, 
251
        // in case the policy URI is injected, it can't be
252
        // abused for CSRF.
253
        req.channel.loadFlags |= Ci.nsIChannel.LOAD_ANONYMOUS;
254
255
        req.send(report);
256
      }
257
    }
258
  },
259
260
  /**
261
   * Exposed Method to analyze docShell for approved frame ancestry.
262
   * Also sends violation reports if necessary.
263
   * @param docShell
264
   *    the docShell for this policy's resource.
265
   * @return
266
   *    true if the frame ancestry is allowed by this policy.
267
   */
268
  permitsAncestry:
269
  function(docShell) {
270
    if(!docShell) { return false; }
271
    CSPdebug(" in permitsAncestry(), docShell = " + docShell);
272
273
    // walk up this docShell tree until we hit chrome
274
    var dst = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
275
                      .getInterface(Ci.nsIDocShellTreeItem);
276
277
    // collect ancestors and make sure they're allowed.
278
    var ancestors = [];
279
    while(dst.parent) {
280
      dst = dst.parent;
281
      let it = dst.QueryInterface(Ci.nsIInterfaceRequestor)
282
                  .getInterface(Ci.nsIWebNavigation);
283
      if(it.currentURI) {
284
        if(it.currentURI.scheme == "chrome") {
285
          break;
286
        }
287
        let ancestor = it.currentURI.scheme + "://" + it.currentURI.hostPort;
288
        CSPdebug(" found frame ancestor " + ancestor);
289
        ancestors.push(ancestor);
290
      }
291
    } 
292
293
    // scan the discovered ancestors
294
    let cspContext = CSPRep.SRC_DIRECTIVES.FRAME_ANCESTORS;
295
    for(let i in ancestors) {
296
      if(!this._policy.permits(ancestors[i], cspContext)) {
297
        // report the frame-ancestor violation
298
        this.sendReports("self", cspContext +" "+ this._policy._directives[cspContext]);
299
        // need to lie if we are testing in report-only mode
300
        return this._reportOnlyMode;
301
      }
302
    }
303
    return true;
304
  },
305
306
  /**
307
   * Delegate method called by the service when sub-elements of the protected
308
   * document are being loaded.  Given a bit of information about the request,
309
   * decides whether or not the policy is satisfied.
310
   */
311
  shouldLoad:
312
  function csp_shouldLoad(aContentType, 
313
                          aContentLocation, 
314
                          aRequestOrigin, 
315
                          aContext, 
316
                          aMimeTypeGuess, 
317
                          aExtra) {
318
319
    //don't filter chrome stuff
320
    if(aContentLocation.scheme == 'chrome') {
321
      return Ci.nsIContentPolicy.ACCEPT;
322
    }
323
324
    //interpret the context, and then pass off to the decision structure
325
    CSPdebug("shouldLoad location = " + aContentLocation.asciiSpec);
326
    CSPdebug("shouldLoad content type = " + aContentType);
327
    var cspContext = ContentSecurityPolicy._MAPPINGS[aContentType];
328
    //CSPdebug("shouldLoad CSP directive =" + cspContext);
329
330
    // if the mapping is null, there's no policy, let it through.
331
    if(!cspContext) {
332
      return Ci.nsIContentPolicy.ACCEPT;
333
    }
334
335
    // otherwise, honor the translation
336
    //var source = aContentLocation.scheme + "://" + aContentLocation.hostPort; 
337
    var res = this._policy.permits(aContentLocation, cspContext)
338
              ? Ci.nsIContentPolicy.ACCEPT 
339
              : Ci.nsIContentPolicy.REJECT_SERVER;
340
341
    // frame-ancestors is taken care of early on (as this document is loaded)
342
343
    // If the result is *NOT* ACCEPT, then send report
344
    if(res != Ci.nsIContentPolicy.ACCEPT) { 
345
      CSPdebug("blocking request for " + aContentLocation.asciiSpec);
346
      this.sendReports(aContentLocation,
347
                       cspContext + " " + this._policy._directives[cspContext]);
348
    }
349
350
    return (this._reportOnlyMode ? Ci.nsIContentPolicy.ACCEPT : res);
351
  },
352
  
353
  shouldProcess:
354
  function csp_shouldProcess(aContentType,
355
                             aContentLocation,
356
                             aRequestOrigin,
357
                             aContext,
358
                             aMimeType,
359
                             aExtra) {
360
    // frame-ancestors check is done outside the ContentPolicy
361
    var res = Ci.nsIContentPolicy.ACCEPT;
362
    CSPdebug("shouldProcess aContext=" + aContext);
363
    return res;
364
  },
365
366
};
367
368
369
370
function NSGetModule(aComMgr, aFileSpec)
371
  XPCOMUtils.generateModule([ContentSecurityPolicy]);
(-)43fdf17e10a3 (+203 lines)
Added Link Here 
Added Link Here 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
 *
5
 * The contents of this file are subject to the Mozilla Public License Version
6
 * 1.1 (the "License"); you may not use this file except in compliance with
7
 * the License. You may obtain a copy of the License at
8
 * http://www.mozilla.org/MPL/
9
 *
10
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 * for the specific language governing rights and limitations under the
13
 * License.
14
 *
15
 * The Original Code is mozilla.org code.
16
 *
17
 * The Initial Developer of the Original Code is
18
 * Mozilla Corporation.
19
 * Portions created by the Initial Developer are Copyright (C) 2009
20
 * the Initial Developer. All Rights Reserved.
21
 *
22
 * Contributor(s):
23
 *   Brandon Sterne <bsterne@mozilla.com>
24
 *
25
 * Alternatively, the contents of this file may be used under the terms of
26
 * either of the GNU General Public License Version 2 or later (the "GPL"),
27
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
29
 * of those above. If you wish to allow use of your version of this file only
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
31
 * use your version of this file under the terms of the MPL, indicate your
32
 * decision by deleting the provisions above and replace them with the notice
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
34
 * the provisions above, a recipient may use your version of this file under
35
 * the terms of any one of the MPL, the GPL or the LGPL.
36
 *
37
 * ***** END LICENSE BLOCK ***** */
38
39
#include "nsIURI.h"
40
#include "nsString.h"
41
#include "nsCSPService.h"
42
#include "nsIDocument.h"
43
#include "nsIContent.h"
44
#include "IContentSecurityPolicy.h"
45
#include "nsContentUtils.h"
46
#include "prlog.h"
47
48
/* Keeps track of whether or not CSP is enabled */
49
static PRBool gCSPEnabled = PR_FALSE;
50
51
#ifdef PR_LOGGING
52
static PRLogModuleInfo* gCspPRLog;
53
#endif
54
55
CSPService::CSPService()
56
{
57
  gCSPEnabled = nsContentUtils::GetBoolPref("security.csp.enable", PR_TRUE);
58
  nsContentUtils::AddBoolPrefVarCache("security.csp.enable", &gCSPEnabled);
59
60
#ifdef PR_LOGGING
61
  if (!gCspPRLog)
62
    gCspPRLog = PR_NewLogModule("CSP");
63
#endif
64
}
65
66
CSPService::~CSPService()
67
{
68
}
69
70
NS_IMPL_ISUPPORTS1(CSPService, nsIContentPolicy)
71
72
/* nsIContentPolicy implementation */
73
NS_IMETHODIMP
74
CSPService::ShouldLoad(PRUint32 aContentType,
75
                       nsIURI *aContentLocation,
76
                       nsIURI *aRequestOrigin,
77
                       nsISupports *aRequestContext,
78
                       const nsACString &aMimeTypeGuess,
79
                       nsISupports *aExtra,
80
                       PRInt16 *aDecision)
81
{
82
  if (!aContentLocation)
83
    return NS_ERROR_FAILURE;
84
85
#ifdef PR_LOGGING 
86
  {
87
    nsCAutoString location("None");
88
    aContentLocation->GetSpec(location);
89
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
90
           ("CSPService::ShouldLoad called for %s", location.get()));
91
  }
92
#endif
93
  // default decision, CSP can revise it if there's a policy to enforce
94
  *aDecision = nsIContentPolicy::ACCEPT;
95
96
  // No need to continue processing if CSP is disabled
97
  if (!gCSPEnabled) {
98
    //printf(" *** CSPService -- CSP is disabled, returning.\n");
99
    return NS_OK;
100
  }
101
102
  // find the nsDocument that initiated this request and see if it has a
103
  // CSP policy object
104
  nsCOMPtr<nsIDocument> doc;
105
  nsCOMPtr<nsIContent> node(do_QueryInterface(aRequestContext));
106
  if (node) {
107
    doc = node->GetOwnerDoc();
108
  }
109
  if (!doc) {
110
    doc = do_QueryInterface(aRequestContext);
111
  }
112
  
113
  if (doc) {
114
    IContentSecurityPolicy* csp = doc->GetContentSecurityPolicy();
115
    if (csp) {
116
#ifdef PR_LOGGING 
117
      nsAutoString policy;
118
      csp->GetPolicy(policy);
119
      PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
120
             ("Document has CSP: %s", ToNewCString(policy)));
121
#endif
122
      // obtain the enforcement decision
123
      csp->ShouldLoad(aContentType,
124
                      aContentLocation,
125
                      aRequestOrigin,
126
                      aRequestContext,
127
                      aMimeTypeGuess,
128
                      aExtra,
129
                      aDecision);
130
    }
131
  }
132
#ifdef PR_LOGGING
133
  else {
134
    nsCAutoString uriSpec("None");
135
    aContentLocation->GetSpec(uriSpec);
136
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
137
           ("COULD NOT get nsIDocument for location: %s", uriSpec.get()));
138
  }
139
#endif
140
	
141
  return NS_OK;
142
}
143
144
NS_IMETHODIMP
145
CSPService::ShouldProcess(PRUint32         aContentType,
146
                          nsIURI           *aContentLocation,
147
                          nsIURI           *aRequestOrigin,
148
                          nsISupports      *aRequestContext,
149
                          const nsACString &aMimeTypeGuess,
150
                          nsISupports      *aExtra,
151
                          PRInt16          *aDecision)
152
{
153
  if (!aContentLocation)
154
    return NS_ERROR_FAILURE;
155
156
  // default decision is to accept the item
157
  *aDecision = nsIContentPolicy::ACCEPT;
158
159
  // No need to continue processing if CSP is disabled
160
  if (!gCSPEnabled) {
161
    //printf(" *** CSPService -- CSP is disabled, returning.\n");
162
    return NS_OK;
163
  }
164
165
  // find the nsDocument that initiated this request and see if it has a
166
  // CSP policy object
167
  nsCOMPtr<nsIDocument> doc;
168
  nsCOMPtr<nsIContent> node(do_QueryInterface(aRequestContext));
169
  if (node) {
170
    doc = node->GetOwnerDoc();
171
  }
172
  if (!doc) {
173
    doc = do_QueryInterface(aRequestContext);
174
  }
175
  if (doc) {
176
    IContentSecurityPolicy* csp = doc->GetContentSecurityPolicy();
177
    if (csp) {
178
#ifdef PR_LOGGING
179
      nsAutoString policy;
180
      csp->GetPolicy(policy);
181
      PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
182
             ("shouldProcess - document has policy: %s", ToNewCString(policy)));
183
#endif
184
      // obtain the enforcement decision
185
      csp->ShouldProcess(aContentType,
186
                         aContentLocation,
187
                         aRequestOrigin,
188
                         aRequestContext,
189
                         aMimeTypeGuess,
190
                         aExtra,
191
                         aDecision);
192
    }
193
  }
194
#ifdef PR_LOGGING
195
  else {
196
    nsCAutoString uriSpec("None");
197
    aContentLocation->GetSpec(uriSpec);
198
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
199
           ("COULD NOT get nsIDocument for location: %s", uriSpec.get()));
200
  }
201
#endif
202
  return NS_OK;
203
}
(-)43fdf17e10a3 (+67 lines)
Added Link Here 
Added Link Here 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* ***** BEGIN LICENSE BLOCK *****
3
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
 *
5
 * The contents of this file are subject to the Mozilla Public License Version
6
 * 1.1 (the "License"); you may not use this file except in compliance with
7
 * the License. You may obtain a copy of the License at
8
 * http://www.mozilla.org/MPL/
9
 *
10
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 * for the specific language governing rights and limitations under the
13
 * License.
14
 *
15
 * The Original Code is mozilla.org code.
16
 *
17
 * The Initial Developer of the Original Code is
18
 * Mozilla Corporation.
19
 * Portions created by the Initial Developer are Copyright (C) 2009
20
 * the Initial Developer. All Rights Reserved.
21
 *
22
 * Contributor(s):
23
 *   Brandon Sterne <bsterne@mozilla.com>
24
 *
25
 * Alternatively, the contents of this file may be used under the terms of
26
 * either of the GNU General Public License Version 2 or later (the "GPL"),
27
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
29
 * of those above. If you wish to allow use of your version of this file only
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
31
 * use your version of this file under the terms of the MPL, indicate your
32
 * decision by deleting the provisions above and replace them with the notice
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
34
 * the provisions above, a recipient may use your version of this file under
35
 * the terms of any one of the MPL, the GPL or the LGPL.
36
 *
37
 * ***** END LICENSE BLOCK ***** */
38
39
#include "nsIGenericFactory.h"
40
41
#include "nsCOMPtr.h"
42
#include "nsXPCOM.h"
43
#include "nsIServiceManager.h"
44
#include "nsICategoryManager.h"
45
46
#include "nsMemory.h"
47
48
#include "nsIContentPolicy.h"
49
#include "nsIObserver.h"
50
51
#define CSPSERVICE_CONTRACTID "@mozilla.org/cspservice;1"
52
#define CSPSERVICE_CID \
53
{ 0x8d2f40b2, 0x4875, 0x4c95, \
54
  { 0x97, 0xd9, 0x3f, 0x7d, 0xca, 0x2c, 0xb4, 0x60 } }
55
56
class CSPService : public nsIContentPolicy
57
{
58
public:
59
  NS_DECL_ISUPPORTS
60
  NS_DECL_NSICONTENTPOLICY
61
  
62
  CSPService();
63
  virtual ~CSPService();
64
65
private:
66
  PRBool mEnabled;
67
};
(-)a/content/base/src/nsDocument.cpp (+122 lines)
Line     Link Here 
 Lines 174-198   static NS_DEFINE_CID(kDOMEventGroupCID, Link Here 
174
#include "mozAutoDocUpdate.h"
174
#include "mozAutoDocUpdate.h"
175
175
176
#ifdef MOZ_SMIL
176
#ifdef MOZ_SMIL
177
#include "nsSMILAnimationController.h"
177
#include "nsSMILAnimationController.h"
178
#include "imgIContainer.h"
178
#include "imgIContainer.h"
179
#include "nsSVGUtils.h"
179
#include "nsSVGUtils.h"
180
#endif // MOZ_SMIL
180
#endif // MOZ_SMIL
181
181
182
// FOR CSP (autogenerated by xpidl)
183
#include "IContentSecurityPolicy.h"
184
182
185
183
#ifdef MOZ_LOGGING
186
#ifdef MOZ_LOGGING
184
// so we can get logging even in release builds
187
// so we can get logging even in release builds
185
#define FORCE_PR_LOG 1
188
#define FORCE_PR_LOG 1
186
#endif
189
#endif
187
#include "prlog.h"
190
#include "prlog.h"
188
191
189
#ifdef PR_LOGGING
192
#ifdef PR_LOGGING
190
static PRLogModuleInfo* gDocumentLeakPRLog;
193
static PRLogModuleInfo* gDocumentLeakPRLog;
194
static PRLogModuleInfo* gCspPRLog;
191
#endif
195
#endif
192
196
193
void
197
void
194
nsUint32ToContentHashEntry::Destroy()
198
nsUint32ToContentHashEntry::Destroy()
195
{
199
{
196
  HashSet* set = GetHashSet();
200
  HashSet* set = GetHashSet();
197
  if (set) {
201
  if (set) {
198
    delete set;
202
    delete set;
 Lines 1473-1488   nsDocument::nsDocument(const char* aCont Link Here 
1473
  
1477
  
1474
#ifdef PR_LOGGING
1478
#ifdef PR_LOGGING
1475
  if (!gDocumentLeakPRLog)
1479
  if (!gDocumentLeakPRLog)
1476
    gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
1480
    gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
1477
1481
1478
  if (gDocumentLeakPRLog)
1482
  if (gDocumentLeakPRLog)
1479
    PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
1483
    PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
1480
           ("DOCUMENT %p created", this));
1484
           ("DOCUMENT %p created", this));
1485
1486
  if (!gCspPRLog)
1487
    gCspPRLog = PR_NewLogModule("CSP");
1488
1481
#endif
1489
#endif
1482
1490
1483
  // Start out mLastStyleSheetSet as null, per spec
1491
  // Start out mLastStyleSheetSet as null, per spec
1484
  SetDOMStringToNull(mLastStyleSheetSet);
1492
  SetDOMStringToNull(mLastStyleSheetSet);
1485
}
1493
}
1486
1494
1487
static PLDHashOperator
1495
static PLDHashOperator
1488
ClearAllBoxObjects(const void* aKey, nsPIBoxObject* aBoxObject, void* aUserArg)
1496
ClearAllBoxObjects(const void* aKey, nsPIBoxObject* aBoxObject, void* aUserArg)
 Lines 2230-2245   nsDocument::StartDocumentLoad(const char Link Here 
2230
    semicolon = start;
2238
    semicolon = start;
2231
    FindCharInReadable(';', semicolon, end);
2239
    FindCharInReadable(';', semicolon, end);
2232
    mContentType = Substring(start, semicolon);
2240
    mContentType = Substring(start, semicolon);
2233
  }
2241
  }
2234
2242
2235
  RetrieveRelevantHeaders(aChannel);
2243
  RetrieveRelevantHeaders(aChannel);
2236
2244
2237
  mChannel = aChannel;
2245
  mChannel = aChannel;
2246
  
2247
// --------------  Initialize CSP
2248
2249
  PRBool cspEnabled;
2250
  cspEnabled = nsContentUtils::GetBoolPref("security.csp.enable", PR_FALSE);
2251
  
2252
  if(!cspEnabled) {
2253
    // CSP not enabled, don't do all this CSP init stuff.
2254
#ifdef PR_LOGGING
2255
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
2256
           ("CSP is disabled, skipping CSP init for document %p", this));
2257
#endif
2258
    return NS_OK;
2259
  }
2260
2261
  nsresult rv;
2262
  PRBool system;
2263
  nsIScriptSecurityManager *ssm = nsContentUtils::GetSecurityManager();
2264
  nsAutoString cspHeaderValue;
2265
  nsAutoString cspROHeaderValue;
2266
  nsIAtom* cspHeaderAtom = NS_NewAtom("x-content-security-policy");
2267
  nsIAtom* cspROHeaderAtom = NS_NewAtom("x-content-security-policy-report-only");
2268
2269
  this->GetHeaderData(cspHeaderAtom, cspHeaderValue);
2270
  this->GetHeaderData(cspROHeaderAtom, cspROHeaderValue);
2271
2272
  if(NS_SUCCEEDED(ssm->IsSystemPrincipal(NodePrincipal(), &system)) && system) {
2273
    //only makes sense to register new CSP if this document is not priviliged
2274
    return NS_OK;
2275
  }
2276
2277
  if(cspHeaderValue.IsEmpty() && cspROHeaderValue.IsEmpty()) {
2278
    // no CSP header present
2279
    return NS_OK;
2280
  }
2281
2282
2283
2284
#ifdef PR_LOGGING 
2285
  PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
2286
          ("CSP header specified for document %p", this));
2287
#endif
2288
2289
  mCSP = do_CreateInstance("@mozilla.org/contentsecuritypolicy;1", &rv);
2290
2291
  if(NS_FAILED(rv)) {
2292
#ifdef PR_LOGGING 
2293
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("Failed to create CSP object: %6x", rv));
2294
#endif
2295
    return rv;
2296
  }
2297
2298
#ifdef PR_LOGGING 
2299
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP attached to document"));
2300
#endif
2301
2302
  // Store the request context for violation reports
2303
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
2304
  mCSP->ScanRequestData(httpChannel);
2305
2306
  // Start parsing the policy
2307
  nsCOMPtr<nsIURI> chanURI;
2308
  aChannel->GetURI(getter_AddRefs(chanURI));
2309
2310
  // ReportOnly mode is enabled *only* if there are no regular-strength CSP
2311
  // headers present.  If there are, then we ignore the ReportOnly mode and
2312
  // toss a warning into the error console, proceeding with enforcing the
2313
  // regular-strength CSP.
2314
  if(cspHeaderValue.IsEmpty()) {
2315
    mCSP->SetReportOnlyMode(true);
2316
    mCSP->RefinePolicy(cspROHeaderValue, chanURI);
2317
#ifdef PR_LOGGING 
2318
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
2319
          ("CSP (report only) refined, policy: \"%s\"", 
2320
           ToNewCString(cspROHeaderValue)));
2321
#endif
2322
2323
  } else {
2324
    //if(!cspROHeaderValue.IsEmpty()) {
2325
      //TODO: post warning that both read only and regular CSP headers are
2326
      //present.
2327
    //}
2328
    mCSP->RefinePolicy(cspHeaderValue, chanURI);
2329
#ifdef PR_LOGGING 
2330
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, 
2331
          ("CSP refined, policy: \"%s\"", ToNewCString(cspHeaderValue)));
2332
#endif
2333
  }
2334
2335
  // Check for frame-ancestor violation
2336
  nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
2337
  if(docShell != NULL) {
2338
    //PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP has a doc shell!"));
2339
2340
    PRBool safeAncestry = false;
2341
    // PermitsAncestry sends violation reports when necessary
2342
    rv = mCSP->PermitsAncestry(docShell, &safeAncestry);
2343
    if(NS_FAILED(rv)) { return rv; }
2344
2345
    if(!safeAncestry) {
2346
#ifdef PR_LOGGING
2347
      PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP doesn't like frame's ancestry, not loading."));
2348
#endif
2349
      // stop!  ERROR page!
2350
      aChannel->Cancel( NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_SECURITY, 99) );
2351
    }
2352
  }
2353
2354
// -------------- CSP initialized
2238
2355
2239
  return NS_OK;
2356
  return NS_OK;
2240
}
2357
}
2241
2358
2242
void
2359
void
2243
nsDocument::StopDocumentLoad()
2360
nsDocument::StopDocumentLoad()
2244
{
2361
{
2245
  if (mParser) {
2362
  if (mParser) {
 Lines 6569-6584   nsDocument::RetrieveRelevantHeaders(nsIC Link Here 
6569
6686
6570
    static const char *const headers[] = {
6687
    static const char *const headers[] = {
6571
      "default-style",
6688
      "default-style",
6572
      "content-style-type",
6689
      "content-style-type",
6573
      "content-language",
6690
      "content-language",
6574
      "content-disposition",
6691
      "content-disposition",
6575
      "refresh",
6692
      "refresh",
6576
      "x-dns-prefetch-control",
6693
      "x-dns-prefetch-control",
6694
      "x-content-security-policy",
6695
      "x-content-security-policy-read-only",
6577
      // add more http headers if you need
6696
      // add more http headers if you need
6578
      // XXXbz don't add content-location support without reading bug
6697
      // XXXbz don't add content-location support without reading bug
6579
      // 238654 and its dependencies/dups first.
6698
      // 238654 and its dependencies/dups first.
6580
      0
6699
      0
6581
    };
6700
    };
6582
    
6701
    
6583
    nsCAutoString headerVal;
6702
    nsCAutoString headerVal;
6584
    const char *const *name = headers;
6703
    const char *const *name = headers;
 Lines 6872-6887   nsDocument::CanSavePresentation(nsIReque Link Here 
6872
6991
6873
void
6992
void
6874
nsDocument::Destroy()
6993
nsDocument::Destroy()
6875
{
6994
{
6876
  // The ContentViewer wants to release the document now.  So, tell our content
6995
  // The ContentViewer wants to release the document now.  So, tell our content
6877
  // to drop any references to the document so that it can be destroyed.
6996
  // to drop any references to the document so that it can be destroyed.
6878
  if (mIsGoingAway)
6997
  if (mIsGoingAway)
6879
    return;
6998
    return;
6999
	
7000
  // Take down CSP
7001
  mCSP = 0;
6880
7002
6881
  mIsGoingAway = PR_TRUE;
7003
  mIsGoingAway = PR_TRUE;
6882
7004
6883
  RemovedFromDocShell();
7005
  RemovedFromDocShell();
6884
7006
6885
  PRUint32 i, count = mChildren.ChildCount();
7007
  PRUint32 i, count = mChildren.ChildCount();
6886
  for (i = 0; i < count; ++i) {
7008
  for (i = 0; i < count; ++i) {
6887
    mChildren.ChildAt(i)->DestroyContent();
7009
    mChildren.ChildAt(i)->DestroyContent();
(-)a/content/base/src/nsScriptLoader.cpp (-1 / +60 lines)
Line     Link Here 
 Lines 65-80    Link Here 
65
#include "nsUnicharUtils.h"
65
#include "nsUnicharUtils.h"
66
#include "nsAutoPtr.h"
66
#include "nsAutoPtr.h"
67
#include "nsIXPConnect.h"
67
#include "nsIXPConnect.h"
68
#include "nsContentErrors.h"
68
#include "nsContentErrors.h"
69
#include "nsIParser.h"
69
#include "nsIParser.h"
70
#include "nsThreadUtils.h"
70
#include "nsThreadUtils.h"
71
#include "nsIChannelClassifier.h"
71
#include "nsIChannelClassifier.h"
72
#include "nsDocShellCID.h"
72
#include "nsDocShellCID.h"
73
#include "prlog.h"
74
75
#ifdef PR_LOGGING
76
static PRLogModuleInfo* gCspPRLog;
77
#endif
78
73
79
74
//////////////////////////////////////////////////////////////
80
//////////////////////////////////////////////////////////////
75
// Per-request data structure
81
// Per-request data structure
76
//////////////////////////////////////////////////////////////
82
//////////////////////////////////////////////////////////////
77
83
78
class nsScriptLoadRequest : public nsISupports {
84
class nsScriptLoadRequest : public nsISupports {
79
public:
85
public:
80
  nsScriptLoadRequest(nsIScriptElement* aElement,
86
  nsScriptLoadRequest(nsIScriptElement* aElement,
 Lines 122-139   NS_IMPL_THREADSAFE_ISUPPORTS0(nsScriptLo Link Here 
122
//
128
//
123
//////////////////////////////////////////////////////////////
129
//////////////////////////////////////////////////////////////
124
130
125
nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
131
nsScriptLoader::nsScriptLoader(nsIDocument *aDocument)
126
  : mDocument(aDocument),
132
  : mDocument(aDocument),
127
    mBlockerCount(0),
133
    mBlockerCount(0),
128
    mEnabled(PR_TRUE),
134
    mEnabled(PR_TRUE),
129
    mDeferEnabled(PR_FALSE),
135
    mDeferEnabled(PR_FALSE),
130
    mUnblockOnloadWhenDoneProcessing(PR_FALSE)
136
    mUnblockOnloadWhenDoneProcessing(PR_FALSE),
137
    mInlineScriptsAllowed(PR_TRUE)
131
{
138
{
139
  // enable logging for CSP
140
#ifdef PR_LOGGING
141
  if (!gCspPRLog)
142
    gCspPRLog = PR_NewLogModule("CSP");
143
#endif
144
145
  IContentSecurityPolicy *csp = mDocument->GetContentSecurityPolicy();
146
  if (csp) {
147
#ifdef PR_LOGGING
148
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader i ****with CSP****"));
149
#endif
150
    PRBool inlineOK;
151
    PRBool reportOnly;
152
    if (   NS_SUCCEEDED(csp->GetAllowsInlineScript(&inlineOK))
153
        && NS_SUCCEEDED(csp->GetReportOnlyMode(&reportOnly)) ) {
154
      mInlineScriptsAllowed = inlineOK || reportOnly;
155
    }
156
  }
157
#ifdef PR_LOGGING
158
    PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("New ScriptLoader i NO CSP"));
159
#endif
132
}
160
}
133
161
134
nsScriptLoader::~nsScriptLoader()
162
nsScriptLoader::~nsScriptLoader()
135
{
163
{
136
  mObservers.Clear();
164
  mObservers.Clear();
137
165
138
  for (PRInt32 i = 0; i < mRequests.Count(); i++) {
166
  for (PRInt32 i = 0; i < mRequests.Count(); i++) {
139
    mRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
167
    mRequests[i]->FireScriptAvailable(NS_ERROR_ABORT);
 Lines 518-533   nsScriptLoader::ProcessScriptElement(nsI Link Here 
518
          !request->mDefer) {
546
          !request->mDefer) {
519
        nsContentUtils::AddScriptRunner(new nsRunnableMethod<nsScriptLoader>(this,
547
        nsContentUtils::AddScriptRunner(new nsRunnableMethod<nsScriptLoader>(this,
520
          &nsScriptLoader::ProcessPendingRequests));
548
          &nsScriptLoader::ProcessPendingRequests));
521
      }
549
      }
522
550
523
      return request->mDefer ? NS_OK : NS_ERROR_HTMLPARSER_BLOCK;
551
      return request->mDefer ? NS_OK : NS_ERROR_HTMLPARSER_BLOCK;
524
    }
552
    }
525
  }
553
  }
554
  else {
555
    // in-line script
556
    IContentSecurityPolicy *csp = mDocument->GetContentSecurityPolicy();
557
    if (csp) {
558
#ifdef PR_LOGGING
559
      PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("ScriptLoader's document has CSP"));
560
#endif
561
      PRBool inlineOK = PR_TRUE;
562
      PRBool reportOnly = PR_FALSE;
563
      rv = csp->GetAllowsInlineScript(&inlineOK);
564
      NS_ENSURE_SUCCESS(rv, rv);
565
      rv = csp->GetReportOnlyMode(&reportOnly);
566
      NS_ENSURE_SUCCESS(rv, rv);
567
      if (!inlineOK && !reportOnly) {
568
#ifdef PR_LOGGING
569
        PR_LOG(gCspPRLog, PR_LOG_DEBUG, (" CSP blocked inline scripts"));
570
#endif
571
        return NS_ERROR_FAILURE;
572
      }
573
    }
574
#ifdef PR_LOGGING
575
    else PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("ScriptLoader's document NO CSP"));
576
#endif
577
  }
526
578
527
  // Create a request object for this script
579
  // Create a request object for this script
528
  request = new nsScriptLoadRequest(aElement, version);
580
  request = new nsScriptLoadRequest(aElement, version);
529
  NS_ENSURE_TRUE(request, NS_ERROR_OUT_OF_MEMORY);
581
  NS_ENSURE_TRUE(request, NS_ERROR_OUT_OF_MEMORY);
530
582
531
  request->mDefer = mDeferEnabled && aElement->GetScriptDeferred();
583
  request->mDefer = mDeferEnabled && aElement->GetScriptDeferred();
532
584
533
  // First check to see if this is an external script
585
  // First check to see if this is an external script
 Lines 536-551   nsScriptLoader::ProcessScriptElement(nsI Link Here 
536
    request->mIsInline = PR_FALSE;
588
    request->mIsInline = PR_FALSE;
537
    request->mLoading = PR_TRUE;
589
    request->mLoading = PR_TRUE;
538
590
539
    rv = StartLoad(request, type);
591
    rv = StartLoad(request, type);
540
    if (NS_FAILED(rv)) {
592
    if (NS_FAILED(rv)) {
541
      return rv;
593
      return rv;
542
    }
594
    }
543
  } else {
595
  } else {
596
    // in-line script
597
    if (!mInlineScriptsAllowed) {
598
#ifdef PR_LOGGING
599
      PR_LOG(gCspPRLog, PR_LOG_DEBUG, ("CSP blocked inline scripts --2nd chance!"));
600
#endif
601
      return NS_ERROR_FAILURE;
602
    }
544
    request->mLoading = PR_FALSE;
603
    request->mLoading = PR_FALSE;
545
    request->mIsInline = PR_TRUE;
604
    request->mIsInline = PR_TRUE;
546
    request->mURI = mDocument->GetDocumentURI();
605
    request->mURI = mDocument->GetDocumentURI();
547
606
548
    request->mLineNo = aElement->GetScriptLineNumber();
607
    request->mLineNo = aElement->GetScriptLineNumber();
549
608
550
    // If we've got existing pending requests, add ourselves
609
    // If we've got existing pending requests, add ourselves
551
    // to this list.
610
    // to this list.
(-)a/content/base/src/nsScriptLoader.h (+1 lines)
Line     Link Here 
 Lines 321-331   protected: Link Here 
321
321
322
  nsCOMPtr<nsIScriptElement> mCurrentScript;
322
  nsCOMPtr<nsIScriptElement> mCurrentScript;
323
  // XXXbz do we want to cycle-collect these or something?  Not sure.
323
  // XXXbz do we want to cycle-collect these or something?  Not sure.
324
  nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
324
  nsTArray< nsRefPtr<nsScriptLoader> > mPendingChildLoaders;
325
  PRUint32 mBlockerCount;
325
  PRUint32 mBlockerCount;
326
  PRPackedBool mEnabled;
326
  PRPackedBool mEnabled;
327
  PRPackedBool mDeferEnabled;
327
  PRPackedBool mDeferEnabled;
328
  PRPackedBool mUnblockOnloadWhenDoneProcessing;
328
  PRPackedBool mUnblockOnloadWhenDoneProcessing;
329
  PRPackedBool mInlineScriptsAllowed;
329
};
330
};
330
331
331
#endif //__nsScriptLoader_h__
332
#endif //__nsScriptLoader_h__
(-)43fdf17e10a3 (+478 lines)
Added Link Here 
Added Link Here 
1
/* ***** BEGIN LICENSE BLOCK *****
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
 *
4
 * The contents of this file are subject to the Mozilla Public License Version
5
 * 1.1 (the "License"); you may not use this file except in compliance with
6
 * the License. You may obtain a copy of the License at
7
 * http://www.mozilla.org/MPL/
8
 *
9
 * Software distributed under the License is distributed on an "AS IS" basis,
10
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
 * for the specific language governing rights and limitations under the
12
 * License.
13
 *
14
 * The Original Code is the Content Security Policy Data Structures testing code.
15
 *
16
 * The Initial Developer of the Original Code is
17
 *   Mozilla Corporation
18
 *
19
 * Contributor(s):
20
 *   Sid Stamm <sid@mozilla.com>
21
 *
22
 * Alternatively, the contents of this file may be used under the terms of
23
 * either the GNU General Public License Version 2 or later (the "GPL"), or
24
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25
 * in which case the provisions of the GPL or the LGPL are applicable instead
26
 * of those above. If you wish to allow use of your version of this file only
27
 * under the terms of either the GPL or the LGPL, and not to allow others to
28
 * use your version of this file under the terms of the MPL, indicate your
29
 * decision by deleting the provisions above and replace them with the notice
30
 * and other provisions required by the GPL or the LGPL. If you do not delete
31
 * the provisions above, a recipient may use your version of this file under
32
 * the terms of any one of the MPL, the GPL or the LGPL.
33
 *
34
 * ***** END LICENSE BLOCK ***** */
35
36
//load('CSPUtils.jsm');
37
Components.utils.import('resource://gre/modules/CSPUtils.jsm');
38
39
// load the HTTP server
40
do_load_httpd_js();
41
42
var httpServer = new nsHttpServer();
43
44
const POLICY_FROM_URI = "allow 'self'; img-src *";
45
const POLICY_PORT = 9000;
46
const POLICY_URI = "http://localhost:" + POLICY_PORT + "/policy";
47
48
// helper to assert that an object or array must have a given key
49
function do_check_has_key(foo, key, stack) {
50
  if (!stack) 
51
    stack = Components.stack.caller;
52
53
  var keys = [];
54
  for(let k in keys) { keys.push(k); }
55
  var text = key + " in [" + keys.join(",") + "]";
56
57
  for(var x in foo) {
58
    if(x == key) {
59
      //succeed
60
      ++_passedChecks;
61
      dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
62
           stack.lineNumber + "] " + text + "\n");
63
      return;
64
    }
65
  }
66
  do_throw(text, stack);
67
}
68
69
// helper to use .equals on stuff
70
function do_check_equivalent(foo, bar, stack) {
71
  if (!stack) 
72
    stack = Components.stack.caller;
73
74
  var text = foo + ".equals(" + bar + ")";
75
76
  if(foo.equals && foo.equals(bar)) {
77
    ++_passedChecks;
78
      dump("TEST-PASS | " + stack.filename + " | [" + stack.name + " : " +
79
           stack.lineNumber + "] " + text + "\n");
80
      return;
81
  }
82
  do_throw(text, stack);
83
}
84
85
var tests = [];
86
function test(fcn) {
87
  tests.push(fcn);
88
}
89
90
test(
91
  function test_CSPHost_fromstring() {
92
    var h;
93
94
    h = CSPHost.fromString("*");
95
    do_check_neq(null, h); // "* lone wildcard should work"
96
97
    h = CSPHost.fromString("foo.bar");
98
    do_check_neq(null, h); // "standard tuple failed"
99
100
    h = CSPHost.fromString("*.bar");
101
    do_check_neq(null, h); // "wildcard failed"
102
103
    h = CSPHost.fromString("com");
104
    do_check_eq(null, h); // "lone symbol should fail"
105
106
    h = CSPHost.fromString("f00b4r.com");
107
    do_check_neq(null, h); // "Numbers in hosts should work"
108
109
    h = CSPHost.fromString("foo-bar.com");
110
    do_check_neq(null, h); // "dashes in hosts should work"
111
112
    // Not enforced in CSPHost
113
    //h = CSPHost.fromString("foo!bar.com");
114
    //ASSERT_NULL(h, "special chars in hosts should fail");
115
  });
116
117
test(
118
  function test_CSPHost_clone() {
119
    h = CSPHost.fromString("*.a.b.c");
120
    h2 = h.clone();
121
    for(var i in h._segments) {
122
      // "cloned segments should match"
123
      do_check_eq(h._segments[i], h2._segments[i]);
124
    }
125
  });
126
127
test(
128
  function test_CSPHost_permits() {
129
    var h = CSPHost.fromString("*.b.c");
130
    var h2 = CSPHost.fromString("a.b.c");
131
    do_check_true( h.permits(h2));       //"CSPHost *.b.c should allow CSPHost a.b.c"
132
    do_check_true( h.permits("a.b.c"));  //"CSPHost *.b.c should allow string a.b.c"
133
    do_check_true(!h.permits("b.c"));    //"CSPHost *.b.c should not allow string b.c"
134
    do_check_true(!h.permits("a.a.c"));  //"CSPHost *.b.c should not allow string a.a.c"
135
    do_check_true(!h2.permits(h));       //"CSPHost a.b.c should not allow CSPHost *.b.c"
136
    do_check_true(!h2.permits("b.c"));   //"CSPHost a.b.c should not allow string b.c"
137
    do_check_true( h2.permits("a.b.c")); //"CSPHost a.b.c should allow string a.b.c"
138
  });
139
140
test(
141
    function test_CSPHost_intersectWith() {
142
      var h = CSPHost.fromString("*.b.c");
143
      //"*.a.b.c ^ *.b.c should be *.a.b.c"
144
      do_check_eq("*.a.b.c", h.intersectWith(CSPHost.fromString("*.a.b.c")).toString());
145
146
      //"*.b.c ^ *.d.e should not work (null)"
147
      do_check_eq(null, h.intersectWith(CSPHost.fromString("*.d.e")));
148
    });
149
150
///////////////////// Test the Source object //////////////////////
151
152
test(
153
    function test_CSPSource_fromString() {
154
      //"basic source should not be null.");
155
      /*
156
      do_check_neq(null, CSPSource.fromString("a.com"));
157
158
      //"ldh characters should all work for host.");
159
      do_check_neq(null, CSPSource.fromString("a2-c.com"));
160
161
      //"wildcard should work in first token for host.");
162
      do_check_neq(null, CSPSource.fromString("*.a.com"));
163
164
      //print(" --- Ignore the following two errors if they print ---");
165
      //"wildcard should not work in non-first token for host.");
166
      do_check_eq(null, CSPSource.fromString("x.*.a.com"));
167
168
      //"funny characters (#) should not work for host, _HOST_RE is probably broken.");
169
      do_check_eq(null, CSPSource.fromString("a#2-c.com"));
170
      //print(" --- Stop ignoring errors that print ---\n");
171
      */
172
173
      //"failed to parse host with port.");
174
      do_check_neq(null, CSPSource.fromString("http://a.com:23"));
175
      //"failed to parse host with scheme.");
176
      do_check_neq(null, CSPSource.fromString("https://a.com"));
177
      //"failed to parse host with scheme and port.");
178
      do_check_neq(null, CSPSource.fromString("https://a.com:200"));
179
    });
180
181
test(
182
    function test_CSPSource_fromString_withSelf() {
183
      var src;
184
      src = CSPSource.fromString("a.com", "https://foobar.com");
185
      CSPdebug("IN TEST: " + src.toString());
186
      //"src should inherit port *
187
      do_check_true(src.permits("https://a.com:443"));
188
      //"src should inherit and require https scheme
189
      do_check_false(src.permits("http://a.com"));
190
      //"src should inherit scheme 'https'"
191
      do_check_true(src.permits("https://a.com"));
192
      
193
      src = CSPSource.fromString("'self'", "https://foobar.com");
194
      //"src should inherit port *
195
      do_check_true(src.permits("https://foobar.com:443"));
196
      //"src should inherit and require https scheme
197
      do_check_false(src.permits("http://foobar.com"));
198
      //"src should inherit scheme 'https'"
199
      do_check_true(src.permits("https://foobar.com"));
200
      //"src should reject other hosts"
201
      do_check_false(src.permits("https://a.com"));
202
    });
203
204
///////////////////// Test the source list //////////////////////
205
206
test(
207
    function test_CSPSourceList_fromString() {
208
      var sd = CSPSourceList.fromString("'none'");
209
      //"'none' -- should parse"
210
      do_check_neq(null,sd);
211
      // "'none' should be a zero-length list"
212
      do_check_eq(0, sd._sources.length);
213
      do_check_true(sd.isNone());
214
215
      sd = CSPSourceList.fromString("*");
216
      //"'*' should be a one-length list"
217
      do_check_eq(1, sd._sources.length);
218
219
      //print(" --- Ignore the following three errors if they print ---");
220
      //"funny char in host"
221
      do_check_true(CSPSourceList.fromString("f!oo.bar").isNone());
222
      //"funny char in scheme"
223
      do_check_true(CSPSourceList.fromString("ht!ps://f-oo.bar").isNone());
224
      //"funny char in port"
225
      do_check_true(CSPSourceList.fromString("https://f-oo.bar:3f").isNone());
226
      //print(" --- Stop ignoring errors that print ---\n");
227
    });
228
229
test(
230
    function test_CSPSourceList_fromString_twohost() {
231
      var str = "foo.bar:21 https://ras.bar";
232
      var parsed = "http://foo.bar:21 https://ras.bar";
233
      var sd = CSPSourceList.fromString(str, "http://self.com");
234
      //"two-host list should parse"
235
      do_check_neq(null,sd);
236
      //"two-host list should parse to two hosts"
237
      do_check_eq(2, sd._sources.length);
238
      //"two-host list should contain original data"
239
      do_check_eq(parsed, sd.toString());
240
    });
241
242
test(
243
    function test_CSPSourceList_permits() {
244
      var nullSourceList = CSPSourceList.fromString("'none'");
245
      var simpleSourceList = CSPSourceList.fromString("a.com", "http://self.com");
246
      var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88");
247
      var allSourceList = CSPSourceList.fromString("*");
248
249
      //'none' should permit none."
250
      do_check_true( !nullSourceList.permits("http://a.com"));
251
      //a.com should permit a.com"
252
      do_check_true( simpleSourceList.permits("http://a.com"));
253
      //wrong host"
254
      do_check_true( !simpleSourceList.permits("http://b.com"));
255
      //double list permits http://bar.com:88"
256
      do_check_true( doubleSourceList.permits("http://bar.com:88"));
257
      //double list permits https://bar.com:88"
258
      do_check_true( !doubleSourceList.permits("https://bar.com:88"));
259
      //double list does not permit http://bar.com:443"
260
      do_check_true( !doubleSourceList.permits("http://bar.com:443"));
261
      //"double list permits https://foo.com:88"
262
      do_check_true( doubleSourceList.permits("https://foo.com:88"));
263
      //"double list does not permit foo.com"
264
      do_check_true( !doubleSourceList.permits("http://foo.com"));
265
266
      //"* does not permit specific host"
267
      do_check_true( allSourceList.permits("http://x.com:23"));
268
      //"* does not permit a long host with no port"
269
      do_check_true( allSourceList.permits("http://a.b.c.d.e.f.x.com"));
270
271
    });
272
273
test(
274
    function test_CSPSourceList_intersect() {
275
      var nullSourceList = CSPSourceList.fromString("'none'");
276
      var simpleSourceList = CSPSourceList.fromString("a.com", "http://self.com");
277
      var doubleSourceList = CSPSourceList.fromString("https://foo.com http://bar.com:88");
278
      var singleFooSourceList = CSPSourceList.fromString("https://foo.com");
279
      var allSourceList = CSPSourceList.fromString("*");
280
281
      //"Intersection of one source with 'none' source list should be none.");
282
      do_check_true(nullSourceList.intersectWith(simpleSourceList).isNone());
283
      //"Intersection of two sources with 'none' source list should be none.");
284
      do_check_true(nullSourceList.intersectWith(doubleSourceList).isNone());
285
      //"Intersection of '*' with 'none' source list should be none.");
286
      do_check_true(nullSourceList.intersectWith(allSourceList).isNone());
287
288
      //"Intersection of one source with '*' source list should be one source.");
289
      do_check_equivalent(allSourceList.intersectWith(simpleSourceList),
290
                          simpleSourceList);
291
      //"Intersection of two sources with '*' source list should be two sources.");
292
      do_check_equivalent(allSourceList.intersectWith(doubleSourceList),
293
                          doubleSourceList);
294
295
      //"Non-overlapping source lists should intersect to 'none'");
296
      do_check_true(simpleSourceList.intersectWith(doubleSourceList).isNone());
297
298
      //"subset and superset should intersect to subset.");
299
      do_check_equivalent(singleFooSourceList,
300
                          doubleSourceList.intersectWith(singleFooSourceList));
301
302
      //TODO: write more tests?
303
304
    });
305
306
///////////////////// Test the Whole CSP rep object //////////////////////
307
308
test(
309
    function test_CSPRep_fromString() {
310
311
      // check default init
312
      //ASSERT(!(new CSPRep())._isInitialized, "Uninitialized rep thinks it is.")
313
314
      var cspr;
315
      var cspr_allowval;
316
317
      // check default policy "allow *"
318
      cspr = CSPRep.fromString("allow *");
319
      //"ALLOW directive is missing when specified in fromString"
320
      do_check_has_key(cspr._directives, CSPRep.SRC_DIRECTIVES.ALLOW);
321
322
      // ... and check that the other directives were auto-filled with the
323
      // ALLOW one.
324
      var SD = CSPRep.SRC_DIRECTIVES;
325
      cspr_allowval = cspr._directives[SD.ALLOW];
326
      for(var d in CSPRep.SRC_DIRECTIVES) {
327
        //"Missing key " + d
328
        do_check_has_key(cspr._directives, SD[d]);
329
        //"Implicit directive " + d + " has non-allow value."
330
        do_check_eq(cspr._directives[SD[d]].toString(), cspr_allowval.toString());
331
      }
332
    });
333
334
335
test(
336
    function test_CSPRep_fromString_oneDir() {
337
338
      var cspr;
339
      var SD = CSPRep.SRC_DIRECTIVES;
340
      var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.IMG_SRC,
341
                      SD.FRAME_ANCESTORS, SD.FRAME_SRC];
342
343
      // check one-directive policies
344
      cspr = CSPRep.fromString("allow bar.com; script-src https://foo.com", 
345
                               "http://self.com");
346
347
      for(var x in DEFAULTS) {
348
        //DEFAULTS[x] + " does not use default rule."
349
        do_check_true(cspr.permits("http://bar.com:22", DEFAULTS[x]));
350
        //DEFAULTS[x] + " does not use default rule."
351
        do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
352
      }
353
      //"script-src false positive in policy.
354
      do_check_false(cspr.permits("http://bar.com:22", SD.SCRIPT_SRC));
355
      //"script-src false negative in policy.
356
      do_check_true(cspr.permits("https://foo.com:400", SD.SCRIPT_SRC));
357
    });
358
359
test(
360
    function test_CSPRep_fromString_twodir() {
361
      var cspr;
362
      var SD = CSPRep.SRC_DIRECTIVES;
363
      var DEFAULTS = [SD.STYLE_SRC, SD.MEDIA_SRC, SD.FRAME_ANCESTORS, SD.FRAME_SRC];
364
365
      // check two-directive policies
366
      cspr = CSPRep.fromString("allow allow.com; "
367
                             + "script-src https://foo.com; "
368
                             + "img-src bar.com",
369
                             "http://self.com");
370
      for(var x in DEFAULTS) {
371
        do_check_true(cspr.permits("http://allow.com:22", DEFAULTS[x]));
372
        //DEFAULTS[x] + " does not use default rule.
373
        do_check_false(cspr.permits("https://foo.com:400", DEFAULTS[x]));
374
        //DEFAULTS[x] + " does not use default rule.
375
        do_check_false(cspr.permits("http://bar.com:400", DEFAULTS[x]));
376
        //DEFAULTS[x] + " does not use default rule.
377
      }
378
      //"img-src does not use default rule.
379
      do_check_false(cspr.permits("http://allow.com:22", SD.IMG_SRC));
380
      //"img-src does not use default rule.
381
      do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
382
      //"img-src does not use default rule.
383
      do_check_true(cspr.permits("http://bar.com:400", SD.IMG_SRC));
384
385
      //"script-src does not use default rule.
386
      do_check_false(cspr.permits("http://allow.com:22", SD.SCRIPT_SRC));
387
      //"script-src does not use default rule.
388
      do_check_true(cspr.permits("https://foo.com:400", SD.SCRIPT_SRC));
389
      //"script-src does not use default rule.
390
      do_check_false(cspr.permits("http://bar.com:400", SD.SCRIPT_SRC));
391
    });
392
393
test(function test_CSPRep_fromString_withself() {
394
      var cspr;
395
      var SD = CSPRep.SRC_DIRECTIVES;
396
      var self = "https://self.com:34";
397
398
      // check one-directive policies
399
      cspr = CSPRep.fromString("allow 'self'; script-src 'self' https://*:*",
400
                              self);
401
      //"img-src does not enforce default rule, 'self'.
402
      do_check_false(cspr.permits("https://foo.com:400", SD.IMG_SRC));
403
      //"img-src does not allow self
404
      do_check_true(cspr.permits(self, SD.IMG_SRC));
405
      //"script-src is too relaxed
406
      do_check_false(cspr.permits("http://evil.com", SD.SCRIPT_SRC));
407
      //"script-src should allow self
408
      do_check_true(cspr.permits(self, SD.SCRIPT_SRC));
409
      //"script-src is too strict on host/port
410
      do_check_true(cspr.permits("https://evil.com:100", SD.SCRIPT_SRC));
411
     });
412
413
///////////////////// TEST POLICY_URI //////////////////////
414
test(function test_CSPRep_fromPolicyURI() {
415
        var cspr;
416
        var SD = CSPRep.SRC_DIRECTIVES;
417
        var self = "http://localhost:" + POLICY_PORT;
418
419
        cspr = CSPRep.fromString("policy-uri " + POLICY_URI, self);
420
        cspr_static = CSPRep.fromString(POLICY_FROM_URI, self);
421
422
        //"policy-uri failed to load"
423
        do_check_neq(null,cspr);
424
425
        // other directives inherit self
426
        for(var i in SD) {
427
          //SD[i] + " parsed wrong from policy uri"
428
          do_check_equivalent(cspr._directives[SD[i]],
429
                              cspr_static._directives[SD[i]]);
430
        }
431
    });
432
/*
433
434
test(function test_CSPRep_fromPolicyURI_failswhenmixed() {
435
        var cspr;
436
        var self = "http://localhost:" + POLICY_PORT;
437
        var closed_policy = CSPRep.fromString("allow 'none'");
438
        var my_uri_policy = "policy-uri " + POLICY_URI;
439
440
        //print(" --- Ignore the following two errors if they print ---");
441
        cspr = CSPRep.fromString("allow *; " + my_uri_policy, self);
442
443
        //"Parsing should fail when 'policy-uri' is mixed with allow directive"
444
        do_check_equivalent(cspr, closed_policy);
445
        cspr = CSPRep.fromString("img-src 'self'; " + my_uri_policy, self);
446
447
        //"Parsing should fail when 'policy-uri' is mixed with other directives"
448
        do_check_equivalent(cspr, closed_policy);
449
        //print(" --- Stop ignoring errors that print ---\n");
450
451
    });
452
*/
453
454
// TODO: test reporting
455
// TODO: test refinements (?)
456
// TODO: test 'eval' and 'inline' keywords
457
458
function run_test() {
459
  function policyresponder(request,response) {
460
    response.setStatusLine(request.httpVersion, 200, "OK");
461
    response.setHeader("Content-Type", "text/csp", false);
462
    response.bodyOutputStream.write(POLICY_FROM_URI, POLICY_FROM_URI.length);
463
  }
464
  //server.registerDirectory("/", nsILocalFileForBasePath);
465
  httpServer.registerPathHandler("/policy", policyresponder);
466
  httpServer.start(POLICY_PORT);
467
468
  for(let i in tests) {
469
    tests[i]();
470
  }
471
472
  //teardown
473
  httpServer.stop(function() { });
474
  do_test_finished();
475
}
476
477
478
(-)a/content/events/src/nsEventListenerManager.cpp (-1 / +26 lines)
Line     Link Here 
 Lines 87-102    Link Here 
87
#include "nsContentUtils.h"
87
#include "nsContentUtils.h"
88
#include "nsJSUtils.h"
88
#include "nsJSUtils.h"
89
#include "nsIDOMEventGroup.h"
89
#include "nsIDOMEventGroup.h"
90
#include "nsContentCID.h"
90
#include "nsContentCID.h"
91
#include "nsEventDispatcher.h"
91
#include "nsEventDispatcher.h"
92
#include "nsDOMJSUtils.h"
92
#include "nsDOMJSUtils.h"
93
#include "nsDOMScriptObjectHolder.h"
93
#include "nsDOMScriptObjectHolder.h"
94
#include "nsDataHashtable.h"
94
#include "nsDataHashtable.h"
95
#include "IContentSecurityPolicy.h"
95
96
96
#define EVENT_TYPE_EQUALS( ls, type, userType ) \
97
#define EVENT_TYPE_EQUALS( ls, type, userType ) \
97
  (ls->mEventType && ls->mEventType == type && \
98
  (ls->mEventType && ls->mEventType == type && \
98
  (ls->mEventType != NS_USER_DEFINED_EVENT || ls->mTypeAtom == userType))
99
  (ls->mEventType != NS_USER_DEFINED_EVENT || ls->mTypeAtom == userType))
99
100
100
#define EVENT_TYPE_DATA_EQUALS( type1, type2 ) \
101
#define EVENT_TYPE_DATA_EQUALS( type1, type2 ) \
101
  (type1 && type2 && type1->iid && type2->iid && \
102
  (type1 && type2 && type1->iid && type2->iid && \
102
   type1->iid->Equals(*(type2->iid)))
103
   type1->iid->Equals(*(type2->iid)))
 Lines 684-712   nsEventListenerManager::AddScriptEventLi Link Here 
684
    }
685
    }
685
  }
686
  }
686
687
687
  if (!global) {
688
  if (!global) {
688
    // This can happen; for example this document might have been
689
    // This can happen; for example this document might have been
689
    // loaded as data.
690
    // loaded as data.
690
    return NS_OK;
691
    return NS_OK;
691
  }
692
  }
693
694
  nsresult rv;
695
696
  // return early preventing the event listener from being added
697
  if (doc) {
698
    IContentSecurityPolicy* csp = doc->GetContentSecurityPolicy();
699
    if (csp) {
700
      PRBool inlineOK;
701
      PRBool reportOnly;
702
      rv = csp->GetAllowsInlineScript(&inlineOK);
703
      NS_ENSURE_SUCCESS(rv, rv);
704
      rv = csp->GetReportOnlyMode(&reportOnly);
705
      NS_ENSURE_SUCCESS(rv, rv);
706
      if( !inlineOK ) {
707
        nsAutoString attr;
708
        aName->ToString(attr);
709
        //printf(" *** CSP bailing on adding event listener for: %s\n",
710
        //       ToNewCString(attr));
711
        //TODO: send CSP error report
712
        if( !reportOnly ) {
713
          return NS_OK;
714
        }
715
      }
716
    }
717
  }
692
  
718
  
693
  // This might be the first reference to this language in the global
719
  // This might be the first reference to this language in the global
694
  // We must init the language before we attempt to fetch its context.
720
  // We must init the language before we attempt to fetch its context.
695
  if (NS_FAILED(global->EnsureScriptEnvironment(aLanguage))) {
721
  if (NS_FAILED(global->EnsureScriptEnvironment(aLanguage))) {
696
    NS_WARNING("Failed to setup script environment for this language");
722
    NS_WARNING("Failed to setup script environment for this language");
697
    // but fall through and let the inevitable failure below handle it.
723
    // but fall through and let the inevitable failure below handle it.
698
  }
724
  }
699
725
700
  context = global->GetScriptContext(aLanguage);
726
  context = global->GetScriptContext(aLanguage);
701
  NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
727
  NS_ENSURE_TRUE(context, NS_ERROR_FAILURE);
702
728
703
  void *scope = global->GetScriptGlobal(aLanguage);
729
  void *scope = global->GetScriptGlobal(aLanguage);
704
  nsresult rv;
705
730
706
  if (!aDeferCompilation) {
731
  if (!aDeferCompilation) {
707
    nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
732
    nsCOMPtr<nsIScriptEventHandlerOwner> handlerOwner =
708
      do_QueryInterface(aObject);
733
      do_QueryInterface(aObject);
709
734
710
    nsScriptObjectHolder handler(context);
735
    nsScriptObjectHolder handler(context);
711
    PRBool done = PR_FALSE;
736
    PRBool done = PR_FALSE;
712
737
(-)a/docshell/base/nsDocShell.cpp (+8 lines)
Line     Link Here 
 Lines 3559-3574   nsDocShell::DisplayLoadError(nsresult aE Link Here 
3559
        NS_ENSURE_ARG_POINTER(aURI);
3559
        NS_ENSURE_ARG_POINTER(aURI);
3560
        // Get the host
3560
        // Get the host
3561
        nsCAutoString host;
3561
        nsCAutoString host;
3562
        aURI->GetHost(host);
3562
        aURI->GetHost(host);
3563
        CopyUTF8toUTF16(host, formatStrs[0]);
3563
        CopyUTF8toUTF16(host, formatStrs[0]);
3564
        formatStrCount = 1;
3564
        formatStrCount = 1;
3565
        error.AssignLiteral("netTimeout");
3565
        error.AssignLiteral("netTimeout");
3566
    }
3566
    }
3567
    else if ( NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY
3568
             && NS_ERROR_GET_CODE(aError) == 99) {
3569
        // CSP error
3570
        error.AssignLiteral("forbiddenFrameAncestor"); 
3571
        cssClass.AssignLiteral("neterror");
3572
        // TODO: localize this, or at least put the message into a resource
3573
        messageStr.AssignLiteral("CSP Blocked loading of this page because it doesn't trust the page embedding it.");
3574
    } 
3567
    else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
3575
    else if (NS_ERROR_GET_MODULE(aError) == NS_ERROR_MODULE_SECURITY) {
3568
        nsCOMPtr<nsINSSErrorsService> nsserr =
3576
        nsCOMPtr<nsINSSErrorsService> nsserr =
3569
            do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
3577
            do_GetService(NS_NSS_ERRORS_SERVICE_CONTRACTID);
3570
3578
3571
        PRUint32 errorClass;
3579
        PRUint32 errorClass;
3572
        if (!nsserr ||
3580
        if (!nsserr ||
3573
            NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
3581
            NS_FAILED(nsserr->GetErrorClass(aError, &errorClass))) {
3574
          errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
3582
          errorClass = nsINSSErrorsService::ERROR_CLASS_SSL_PROTOCOL;
(-)a/dom/base/nsJSTimeoutHandler.cpp (+30 lines)
Line     Link Here 
 Lines 238-253   nsJSScriptTimeoutHandler::Init(nsGlobalW Link Here 
238
    ::JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
238
    ::JS_ReportError(cx, "useless %s call (missing quotes around argument?)",
239
                     *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
239
                     *aIsInterval ? kSetIntervalStr : kSetTimeoutStr);
240
240
241
    // Return an error that nsGlobalWindow can recognize and turn into NS_OK.
241
    // Return an error that nsGlobalWindow can recognize and turn into NS_OK.
242
    return NS_ERROR_DOM_TYPE_ERR;
242
    return NS_ERROR_DOM_TYPE_ERR;
243
  }
243
  }
244
244
245
  if (expr) {
245
  if (expr) {
246
    // if CSP is enabled, and setTimeout/setInterval was called with a string
247
    // or object, disable the registration and log an error
248
    nsCOMPtr<nsIDOMDocument> domdoc;
249
    aWindow->GetDocument(getter_AddRefs(domdoc));
250
    nsCOMPtr<nsIDocument> doc = do_QueryInterface(domdoc);
251
    
252
    if (doc) {
253
      IContentSecurityPolicy* csp = doc->GetContentSecurityPolicy();
254
      if(csp) {
255
        PRBool allowsEval;
256
        PRBool reportOnly;
257
        rv = csp->GetAllowsEval(&allowsEval);
258
        NS_ENSURE_SUCCESS(rv, rv);
259
        rv = csp->GetReportOnlyMode(&reportOnly);
260
        NS_ENSURE_SUCCESS(rv, rv);
261
        if (csp && !allowsEval) {
262
          // CSP policy does NOT allow "eval"
263
          // XXX: we should make this error report a little more informative.
264
          csp->SendReports(
265
                NS_LITERAL_STRING("self"),
266
                NS_LITERAL_STRING("setInterval or setTimeout with string"));
267
          //don't actually fail unless we're not in reportOnly mode
268
          if (!reportOnly) {
269
            return NS_OK;
270
          }
271
        }
272
      }
273
    } // if there's no document, we don't have to do anything.
274
275
      
246
    rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
276
    rv = NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
247
    NS_ENSURE_SUCCESS(rv, rv);
277
    NS_ENSURE_SUCCESS(rv, rv);
248
278
249
    mExpr = expr;
279
    mExpr = expr;
250
280
251
    nsIPrincipal *prin = aWindow->GetPrincipal();
281
    nsIPrincipal *prin = aWindow->GetPrincipal();
252
282
253
    // Get the calling location.
283
    // Get the calling location.
(-)a/layout/build/nsLayoutModule.cpp (-1 / +82 lines)
Line     Link Here 
 Lines 267-282   static nsresult Initialize(nsIModule* aS Link Here 
267
static void Shutdown();
267
static void Shutdown();
268
268
269
#ifdef MOZ_XTF
269
#ifdef MOZ_XTF
270
#include "nsIXTFService.h"
270
#include "nsIXTFService.h"
271
#include "nsIXMLContentBuilder.h"
271
#include "nsIXMLContentBuilder.h"
272
#endif
272
#endif
273
273
274
#include "nsGeolocation.h"
274
#include "nsGeolocation.h"
275
#include "nsCSPService.h"
275
276
276
// Transformiix
277
// Transformiix
277
/* {0C351177-0159-4500-86B0-A219DFDE4258} */
278
/* {0C351177-0159-4500-86B0-A219DFDE4258} */
278
#define TRANSFORMIIX_XPATH1_SCHEME_CID \
279
#define TRANSFORMIIX_XPATH1_SCHEME_CID \
279
{ 0xc351177, 0x159, 0x4500, { 0x86, 0xb0, 0xa2, 0x19, 0xdf, 0xde, 0x42, 0x58 } }
280
{ 0xc351177, 0x159, 0x4500, { 0x86, 0xb0, 0xa2, 0x19, 0xdf, 0xde, 0x42, 0x58 } }
280
281
281
/* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
282
/* 5d5d92cd-6bf8-11d9-bf4a-000a95dc234c */
282
#define TRANSFORMIIX_NODESET_CID \
283
#define TRANSFORMIIX_NODESET_CID \
 Lines 848-863   CreateWindowControllerWithSingletonComma Link Here 
848
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMScriptObjectFactory)
849
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDOMScriptObjectFactory)
849
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBaseDOMException)
850
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBaseDOMException)
850
851
851
#define NS_GEOLOCATION_SERVICE_CID \
852
#define NS_GEOLOCATION_SERVICE_CID \
852
  { 0x404d02a, 0x1CA, 0xAAAB, { 0x47, 0x62, 0x94, 0x4b, 0x1b, 0xf2, 0xf7, 0xb5 } }
853
  { 0x404d02a, 0x1CA, 0xAAAB, { 0x47, 0x62, 0x94, 0x4b, 0x1b, 0xf2, 0xf7, 0xb5 } }
853
854
854
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
855
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsGeolocationService, nsGeolocationService::GetGeolocationService)
855
856
857
static NS_METHOD
858
CSPServiceRegistration(nsIComponentManager *aCompMgr,
859
                       nsIFile *aPath,
860
                       const char *registryLocation,
861
                       const char *componentType,
862
                       const nsModuleComponentInfo *info)
863
{
864
  nsresult rv;
865
  nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
866
  if (NS_FAILED(rv))
867
    return rv;
868
869
  nsCOMPtr<nsICategoryManager> catman;
870
  rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
871
                                       NS_GET_IID(nsICategoryManager),
872
                                       getter_AddRefs(catman));
873
  if (NS_FAILED(rv))
874
    return rv;
875
  
876
  char* previous = nsnull;
877
  rv = catman->AddCategoryEntry("xpcom-startup",
878
                                "CSPService",
879
                                CSPSERVICE_CONTRACTID,
880
                                PR_TRUE,
881
                                PR_TRUE,
882
                                &previous);
883
  if (previous)
884
    nsMemory::Free(previous);
885
886
  rv = catman->AddCategoryEntry("content-policy",
887
                                "CSPService",
888
                                CSPSERVICE_CONTRACTID,
889
                                PR_TRUE,
890
                                PR_TRUE,
891
                                &previous);
892
  if (previous)
893
    nsMemory::Free(previous);
894
895
  return rv;
896
}
897
898
static NS_METHOD
899
CSPServiceUnregistration(nsIComponentManager *aCompMgr,
900
                         nsIFile *aPath,
901
                         const char *registryLocation,
902
                         const nsModuleComponentInfo *info){
903
  nsresult rv;
904
905
  nsCOMPtr<nsIServiceManager> servman = do_QueryInterface((nsISupports*)aCompMgr, &rv);
906
  if (NS_FAILED(rv))
907
    return rv;
908
909
  nsCOMPtr<nsICategoryManager> catman;
910
  rv = servman->GetServiceByContractID(NS_CATEGORYMANAGER_CONTRACTID,
911
                                       NS_GET_IID(nsICategoryManager),
912
                                       getter_AddRefs(catman));
913
  if (NS_FAILED(rv))
914
    return rv;
915
916
  rv = catman->DeleteCategoryEntry("xpcom-startup",
917
                                   "CSPService",
918
                                   PR_TRUE);
919
920
  rv = catman->DeleteCategoryEntry("content-policy",
921
                                   "CSPService",
922
                                   PR_TRUE);
923
924
  return rv;
925
}
926
927
NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService)
928
929
930
856
// The list of components we register
931
// The list of components we register
857
static const nsModuleComponentInfo gComponents[] = {
932
static const nsModuleComponentInfo gComponents[] = {
858
#ifdef DEBUG
933
#ifdef DEBUG
859
  { "Frame utility",
934
  { "Frame utility",
860
    NS_FRAME_UTIL_CID,
935
    NS_FRAME_UTIL_CID,
861
    nsnull,
936
    nsnull,
862
    CreateNewFrameUtil },
937
    CreateNewFrameUtil },
863
  { "Layout debugger",
938
  { "Layout debugger",
 Lines 1447-1463   static const nsModuleComponentInfo gComp Link Here 
1447
      nsTextServicesDocumentConstructor },
1522
      nsTextServicesDocumentConstructor },
1448
#endif
1523
#endif
1449
1524
1450
    { "Geolocation Service",
1525
    { "Geolocation Service",
1451
      NS_GEOLOCATION_SERVICE_CID,
1526
      NS_GEOLOCATION_SERVICE_CID,
1452
      "@mozilla.org/geolocation/service;1",
1527
      "@mozilla.org/geolocation/service;1",
1453
      nsGeolocationServiceConstructor },
1528
      nsGeolocationServiceConstructor },
1454
1529
1455
1530
    { "Content Security Policy Service",
1531
      CSPSERVICE_CID,
1532
      CSPSERVICE_CONTRACTID,
1533
      CSPServiceConstructor,
1534
      CSPServiceRegistration,
1535
      CSPServiceUnregistration
1536
    },
1456
1537
1457
  { "Focus Manager",
1538
  { "Focus Manager",
1458
    NS_FOCUSMANAGER_CID,
1539
    NS_FOCUSMANAGER_CID,
1459
    "@mozilla.org/focus-manager;1",
1540
    "@mozilla.org/focus-manager;1",
1460
    CreateFocusManager },
1541
    CreateFocusManager },
1461
};
1542
};
1462
1543
1463
NS_IMPL_NSGETMODULE_WITH_CTOR(nsLayoutModule, gComponents, Initialize)
1544
NS_IMPL_NSGETMODULE_WITH_CTOR(nsLayoutModule, gComponents, Initialize)
(-)a/modules/libpref/src/init/all.js (+2 lines)
Line     Link Here 
 Lines 925-940   pref("images.dither", "auto"); Link Here 
925
pref("security.directory",              "");
925
pref("security.directory",              "");
926
926
927
pref("signed.applets.codebase_principal_support", false);
927
pref("signed.applets.codebase_principal_support", false);
928
pref("security.checkloaduri", true);
928
pref("security.checkloaduri", true);
929
pref("security.xpconnect.plugin.unrestricted", true);
929
pref("security.xpconnect.plugin.unrestricted", true);
930
// security-sensitive dialogs should delay button enabling. In milliseconds.
930
// security-sensitive dialogs should delay button enabling. In milliseconds.
931
pref("security.dialog_enable_delay", 2000);
931
pref("security.dialog_enable_delay", 2000);
932
932
933
pref("security.csp.enable", true);
934
933
// Modifier key prefs: default to Windows settings,
935
// Modifier key prefs: default to Windows settings,
934
// menu access key = alt, accelerator key = control.
936
// menu access key = alt, accelerator key = control.
935
// Use 17 for Ctrl, 18 for Alt, 224 for Meta, 0 for none. Mac settings in macprefs.js
937
// Use 17 for Ctrl, 18 for Alt, 224 for Meta, 0 for none. Mac settings in macprefs.js
936
pref("ui.key.accelKey", 17);
938
pref("ui.key.accelKey", 17);
937
pref("ui.key.menuAccessKey", 18);
939
pref("ui.key.menuAccessKey", 18);
938
pref("ui.key.generalAccessKey", -1);
940
pref("ui.key.generalAccessKey", -1);
939
941
940
// If generalAccessKey is -1, use the following two prefs instead.
942
// If generalAccessKey is -1, use the following two prefs instead.

Return to bug 493857