browser_checkloaduri.js (12759B)
1 "use strict"; 2 3 let ssm = Services.scriptSecurityManager; 4 // This will show a directory listing, but we never actually load these so that's OK. 5 const kDummyPage = getRootDirectory(gTestPath); 6 7 const kAboutPagesRegistered = Promise.all([ 8 BrowserTestUtils.registerAboutPage( 9 registerCleanupFunction, 10 "test-chrome-privs", 11 kDummyPage, 12 Ci.nsIAboutModule.ALLOW_SCRIPT 13 ), 14 BrowserTestUtils.registerAboutPage( 15 registerCleanupFunction, 16 "test-chrome-privs2", 17 kDummyPage, 18 Ci.nsIAboutModule.ALLOW_SCRIPT 19 ), 20 BrowserTestUtils.registerAboutPage( 21 registerCleanupFunction, 22 "test-unknown-linkable", 23 kDummyPage, 24 Ci.nsIAboutModule.MAKE_LINKABLE | Ci.nsIAboutModule.ALLOW_SCRIPT 25 ), 26 BrowserTestUtils.registerAboutPage( 27 registerCleanupFunction, 28 "test-unknown-linkable2", 29 kDummyPage, 30 Ci.nsIAboutModule.MAKE_LINKABLE | Ci.nsIAboutModule.ALLOW_SCRIPT 31 ), 32 BrowserTestUtils.registerAboutPage( 33 registerCleanupFunction, 34 "test-unknown-unlinkable", 35 kDummyPage, 36 Ci.nsIAboutModule.ALLOW_SCRIPT 37 ), 38 BrowserTestUtils.registerAboutPage( 39 registerCleanupFunction, 40 "test-unknown-unlinkable2", 41 kDummyPage, 42 Ci.nsIAboutModule.ALLOW_SCRIPT 43 ), 44 BrowserTestUtils.registerAboutPage( 45 registerCleanupFunction, 46 "test-content-unlinkable", 47 kDummyPage, 48 Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | 49 Ci.nsIAboutModule.ALLOW_SCRIPT 50 ), 51 BrowserTestUtils.registerAboutPage( 52 registerCleanupFunction, 53 "test-content-unlinkable2", 54 kDummyPage, 55 Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | 56 Ci.nsIAboutModule.ALLOW_SCRIPT 57 ), 58 BrowserTestUtils.registerAboutPage( 59 registerCleanupFunction, 60 "test-content-linkable", 61 kDummyPage, 62 Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | 63 Ci.nsIAboutModule.MAKE_LINKABLE | 64 Ci.nsIAboutModule.ALLOW_SCRIPT 65 ), 66 BrowserTestUtils.registerAboutPage( 67 registerCleanupFunction, 68 "test-content-linkable2", 69 kDummyPage, 70 Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT | 71 Ci.nsIAboutModule.MAKE_LINKABLE | 72 Ci.nsIAboutModule.ALLOW_SCRIPT 73 ), 74 ]); 75 76 const URLs = new Map([ 77 [ 78 "http://www.example.com", 79 [ 80 // For each of these entries, the booleans represent whether the parent URI can: 81 // - load them 82 // - load them without principal inheritance 83 // - whether the URI can be created at all (some protocol handlers will 84 // refuse to create certain variants) 85 ["http://www.example2.com", true, true, true], 86 ["https://www.example2.com", true, true, true], 87 ["moz-icon:file:///foo/bar/baz.exe", false, false, true], 88 ["moz-icon://.exe", false, false, true], 89 ["chrome://foo/content/bar.xul", false, false, true], 90 ["view-source:http://www.example2.com", false, false, true], 91 ["view-source:https://www.example2.com", false, false, true], 92 ["data:text/html,Hi", true, false, true], 93 ["view-source:data:text/html,Hi", false, false, true], 94 ["javascript:alert('hi')", true, false, true], 95 ["moz://a", false, false, true], 96 ["about:test-chrome-privs", false, false, true], 97 ["about:test-unknown-unlinkable", false, false, true], 98 ["about:test-content-unlinkable", false, false, true], 99 ["about:test-content-linkable", true, true, true], 100 // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: 101 ["about:test-unknown-linkable", false, false, true], 102 ], 103 ], 104 [ 105 "view-source:http://www.example.com", 106 [ 107 ["http://www.example2.com", true, true, true], 108 ["https://www.example2.com", true, true, true], 109 ["moz-icon:file:///foo/bar/baz.exe", false, false, true], 110 ["moz-icon://.exe", false, false, true], 111 ["chrome://foo/content/bar.xul", false, false, true], 112 ["view-source:http://www.example2.com", true, true, true], 113 ["view-source:https://www.example2.com", true, true, true], 114 ["data:text/html,Hi", true, false, true], 115 ["view-source:data:text/html,Hi", true, false, true], 116 ["javascript:alert('hi')", true, false, true], 117 ["moz://a", false, false, true], 118 ["about:test-chrome-privs", false, false, true], 119 ["about:test-unknown-unlinkable", false, false, true], 120 ["about:test-content-unlinkable", false, false, true], 121 ["about:test-content-linkable", true, true, true], 122 // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: 123 ["about:test-unknown-linkable", false, false, true], 124 ], 125 ], 126 // about: related tests. 127 [ 128 "about:test-chrome-privs", 129 [ 130 ["about:test-chrome-privs", true, true, true], 131 ["about:test-chrome-privs2", true, true, true], 132 ["about:test-chrome-privs2?foo#bar", true, true, true], 133 ["about:test-chrome-privs2?foo", true, true, true], 134 ["about:test-chrome-privs2#bar", true, true, true], 135 136 ["about:test-unknown-unlinkable", true, true, true], 137 138 ["about:test-content-unlinkable", true, true, true], 139 ["about:test-content-unlinkable?foo", true, true, true], 140 ["about:test-content-unlinkable?foo#bar", true, true, true], 141 ["about:test-content-unlinkable#bar", true, true, true], 142 143 ["about:test-content-linkable", true, true, true], 144 145 ["about:test-unknown-linkable", true, true, true], 146 ["moz-icon:file:///foo/bar/baz.exe", true, true, true], 147 ["moz-icon://.exe", true, true, true], 148 ], 149 ], 150 [ 151 "about:test-unknown-unlinkable", 152 [ 153 ["about:test-chrome-privs", false, false, true], 154 155 // Can link to ourselves: 156 ["about:test-unknown-unlinkable", true, true, true], 157 // Can't link to unlinkable content if we're not sure it's privileged: 158 ["about:test-unknown-unlinkable2", false, false, true], 159 160 ["about:test-content-unlinkable", true, true, true], 161 ["about:test-content-unlinkable2", true, true, true], 162 ["about:test-content-unlinkable2?foo", true, true, true], 163 ["about:test-content-unlinkable2?foo#bar", true, true, true], 164 ["about:test-content-unlinkable2#bar", true, true, true], 165 166 ["about:test-content-linkable", true, true, true], 167 168 // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: 169 ["about:test-unknown-linkable", false, false, true], 170 ], 171 ], 172 [ 173 "about:test-content-unlinkable", 174 [ 175 ["about:test-chrome-privs", false, false, true], 176 177 // Can't link to unlinkable content if we're not sure it's privileged: 178 ["about:test-unknown-unlinkable", false, false, true], 179 180 ["about:test-content-unlinkable", true, true, true], 181 ["about:test-content-unlinkable2", true, true, true], 182 ["about:test-content-unlinkable2?foo", true, true, true], 183 ["about:test-content-unlinkable2?foo#bar", true, true, true], 184 ["about:test-content-unlinkable2#bar", true, true, true], 185 186 ["about:test-content-linkable", true, true, true], 187 ["about:test-unknown-linkable", false, false, true], 188 ], 189 ], 190 [ 191 "about:test-unknown-linkable", 192 [ 193 ["about:test-chrome-privs", false, false, true], 194 195 // Linkable content can't link to unlinkable content. 196 ["about:test-unknown-unlinkable", false, false, true], 197 198 ["about:test-content-unlinkable", false, false, true], 199 ["about:test-content-unlinkable2", false, false, true], 200 ["about:test-content-unlinkable2?foo", false, false, true], 201 ["about:test-content-unlinkable2?foo#bar", false, false, true], 202 ["about:test-content-unlinkable2#bar", false, false, true], 203 204 // ... but it can link to other linkable content. 205 ["about:test-content-linkable", true, true, true], 206 207 // Can link to ourselves: 208 ["about:test-unknown-linkable", true, true, true], 209 210 // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: 211 ["about:test-unknown-linkable2", false, false, true], 212 ], 213 ], 214 [ 215 "about:test-content-linkable", 216 [ 217 ["about:test-chrome-privs", false, false, true], 218 219 // Linkable content can't link to unlinkable content. 220 ["about:test-unknown-unlinkable", false, false, true], 221 222 ["about:test-content-unlinkable", false, false, true], 223 224 // ... but it can link to itself and other linkable content. 225 ["about:test-content-linkable", true, true, true], 226 ["about:test-content-linkable2", true, true, true], 227 228 // Because this page doesn't have SAFE_FOR_UNTRUSTED, the web can't link to it: 229 ["about:test-unknown-linkable", false, false, true], 230 ], 231 ], 232 ]); 233 234 function testURL( 235 source, 236 target, 237 canLoad, 238 canLoadWithoutInherit, 239 canCreate, 240 flags 241 ) { 242 function getPrincipalDesc(principal) { 243 if (principal.spec != "") { 244 return principal.spec; 245 } 246 if (principal.isSystemPrincipal) { 247 return "system principal"; 248 } 249 if (principal.isNullPrincipal) { 250 return "null principal"; 251 } 252 return "unknown principal"; 253 } 254 let threw = false; 255 let targetURI; 256 try { 257 targetURI = Services.io.newURI(target); 258 } catch (ex) { 259 ok( 260 !canCreate, 261 "Shouldn't be passing URIs that we can't create. Failed to create: " + 262 target 263 ); 264 return; 265 } 266 ok( 267 canCreate, 268 "Created a URI for " + 269 target + 270 " which should " + 271 (canCreate ? "" : "not ") + 272 "be possible." 273 ); 274 try { 275 ssm.checkLoadURIWithPrincipal(source, targetURI, flags); 276 } catch (ex) { 277 info(ex.message); 278 threw = true; 279 } 280 let inheritDisallowed = flags & ssm.DISALLOW_INHERIT_PRINCIPAL; 281 let shouldThrow = inheritDisallowed ? !canLoadWithoutInherit : !canLoad; 282 Assert.equal( 283 threw, 284 shouldThrow, 285 "Should " + 286 (shouldThrow ? "" : "not ") + 287 "throw an error when loading " + 288 target + 289 " from " + 290 getPrincipalDesc(source) + 291 (inheritDisallowed ? " without" : " with") + 292 " principal inheritance." 293 ); 294 } 295 296 add_task(async function () { 297 // In this test we want to verify both http and https load 298 // restrictions, hence we explicitly switch off the https-first 299 // upgrading mechanism. 300 await SpecialPowers.pushPrefEnv({ 301 set: [ 302 ["dom.security.https_first", false], 303 ["security.allow_eval_with_system_principal", true], 304 ], 305 }); 306 307 await kAboutPagesRegistered; 308 let baseFlags = ssm.STANDARD | ssm.DONT_REPORT_ERRORS; 309 for (let [sourceString, targetsAndExpectations] of URLs) { 310 let source; 311 if (sourceString.startsWith("about:test-chrome-privs")) { 312 source = ssm.getSystemPrincipal(); 313 } else { 314 source = ssm.createContentPrincipal(Services.io.newURI(sourceString), {}); 315 } 316 for (let [ 317 target, 318 canLoad, 319 canLoadWithoutInherit, 320 canCreate, 321 ] of targetsAndExpectations) { 322 testURL( 323 source, 324 target, 325 canLoad, 326 canLoadWithoutInherit, 327 canCreate, 328 baseFlags 329 ); 330 testURL( 331 source, 332 target, 333 canLoad, 334 canLoadWithoutInherit, 335 canCreate, 336 baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL 337 ); 338 } 339 } 340 341 // Now test blob URIs, which we need to do in-content. 342 await BrowserTestUtils.withNewTab( 343 "http://www.example.com/", 344 async function (browser) { 345 await SpecialPowers.spawn( 346 browser, 347 [testURL.toString()], 348 async function (testURLFn) { 349 // eslint-disable-next-line no-shadow , no-eval 350 let testURL = eval("(" + testURLFn + ")"); 351 // eslint-disable-next-line no-shadow 352 let ssm = Services.scriptSecurityManager; 353 // eslint-disable-next-line no-shadow 354 let baseFlags = ssm.STANDARD | ssm.DONT_REPORT_ERRORS; 355 // eslint-disable-next-line no-unused-vars 356 let b = new content.Blob(["I am a blob"]); 357 let contentBlobURI = content.URL.createObjectURL(b); 358 let contentPrincipal = content.document.nodePrincipal; 359 // Loading this blob URI from the content page should work: 360 testURL( 361 contentPrincipal, 362 contentBlobURI, 363 true, 364 true, 365 true, 366 baseFlags 367 ); 368 testURL( 369 contentPrincipal, 370 contentBlobURI, 371 true, 372 true, 373 true, 374 baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL 375 ); 376 377 testURL( 378 contentPrincipal, 379 "view-source:" + contentBlobURI, 380 false, 381 false, 382 true, 383 baseFlags 384 ); 385 testURL( 386 contentPrincipal, 387 "view-source:" + contentBlobURI, 388 false, 389 false, 390 true, 391 baseFlags | ssm.DISALLOW_INHERIT_PRINCIPAL 392 ); 393 } 394 ); 395 } 396 ); 397 });