diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index 3c9a4f48b5cd..3d8f340b0716 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -76,8 +76,16 @@ bool subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) { contentType == nsIContentPolicy::TYPE_STYLESHEET || contentType == nsIContentPolicy::TYPE_DTD || contentType == nsIContentPolicy::TYPE_XBL; - if (aURI->SchemeIs("resource") && !isImgOrStyleOrDTDorXBL) { - return true; + if (aURI->SchemeIs("resource")) { + nsAutoCString uriSpec; + aURI->GetSpec(uriSpec); + // Exempt pdf.js from being subject to a page's CSP. + if (StringBeginsWith(uriSpec, NS_LITERAL_CSTRING("resource://pdf.js/"))) { + return false; + } + if (!isImgOrStyleOrDTDorXBL) { + return true; + } } if (aURI->SchemeIs("chrome") && !isImgOrStyleOrDTDorXBL) { return true; @@ -237,9 +245,9 @@ CSPService::AsyncOnChannelRedirect(nsIChannel* oldChannel, // context. In turn, we do not have an event target for policy violations. // Enforce the CSP check in the content process where we have that info. // We allow redirect checks to run for document loads via - // DocumentLoadListener, since these are fully supported and we don't expose - // the redirects to the content process. We can't do this for all request - // types yet because we don't serialize nsICSPEventListener. + // DocumentLoadListener, since these are fully supported and we don't + // expose the redirects to the content process. We can't do this for all + // request types yet because we don't serialize nsICSPEventListener. if (parentChannel && !docListener) { return NS_OK; } @@ -323,9 +331,9 @@ nsresult CSPService::ConsultCSPForRedirect(nsIURI* aOriginalURI, bool isPreload = nsContentUtils::IsPreloadType(policyType); - /* On redirect, if the content policy is a preload type, rejecting the preload - * results in the load silently failing, so we convert preloads to the actual - * type. See Bug 1219453. + /* On redirect, if the content policy is a preload type, rejecting the + * preload results in the load silently failing, so we convert preloads to + * the actual type. See Bug 1219453. */ policyType = nsContentUtils::InternalContentPolicyTypeToExternalOrWorker(policyType); diff --git a/dom/security/test/csp/browser.ini b/dom/security/test/csp/browser.ini index 17102a9fff35..f2273f018053 100644 --- a/dom/security/test/csp/browser.ini +++ b/dom/security/test/csp/browser.ini @@ -17,3 +17,7 @@ support-files = support-files = file_csp_meta_uir.html [browser_manifest-src-override-default-src.js] +[browser_pdfjs_not_subject_to_csp.js] +support-files = + dummy.pdf + file_pdfjs_not_subject_to_csp.html diff --git a/dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js b/dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js new file mode 100644 index 000000000000..dbcbf8efbf25 --- /dev/null +++ b/dom/security/test/csp/browser_pdfjs_not_subject_to_csp.js @@ -0,0 +1,48 @@ +"use strict"; + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +add_task(async function() { + await SpecialPowers.pushPrefEnv({ + set: [["pdfjs.eventBusDispatchToDOM", true]], + }); + await BrowserTestUtils.withNewTab( + TEST_PATH + "file_pdfjs_not_subject_to_csp.html", + async function(browser) { + let pdfPromise = BrowserTestUtils.waitForContentEvent( + browser, + "documentloaded", + false, + null, + true + ); + + await ContentTask.spawn(browser, {}, async function() { + let pdfButton = content.document.getElementById("pdfButton"); + pdfButton.click(); + }); + + await pdfPromise; + + await ContentTask.spawn(browser, {}, async function() { + let pdfFrame = content.document.getElementById("pdfFrame"); + // 1) Sanity that we have loaded the PDF using a blob + ok(pdfFrame.src.startsWith("blob:"), "it's a blob URL"); + + // 2) Ensure that the PDF has actually loaded + ok( + pdfFrame.contentDocument.querySelector("div#viewer"), + "document content has viewer UI" + ); + + // 3) Ensure we have the correct CSP attached + let cspJSON = pdfFrame.contentDocument.cspJSON; + ok(cspJSON.includes("script-src"), "found script-src directive"); + ok(cspJSON.includes("allowPDF"), "found script-src nonce value"); + }); + } + ); +}); diff --git a/dom/security/test/csp/dummy.pdf b/dom/security/test/csp/dummy.pdf new file mode 100644 index 000000000000..7ad87e3c2e32 Binary files /dev/null and b/dom/security/test/csp/dummy.pdf differ diff --git a/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html b/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html new file mode 100644 index 000000000000..132d77b47c26 --- /dev/null +++ b/dom/security/test/csp/file_pdfjs_not_subject_to_csp.html @@ -0,0 +1,21 @@ + + + + + + +
+ + + +