Bug 1941725 - Make blocking of PDFs in sandboxed containers stricter. r=smaug
Differential Revision: https://phabricator.services.mozilla.com/D245598
This commit is contained in:
@@ -283,14 +283,6 @@ class ParentProcessDocumentOpenInfo final : public nsDocumentOpenInfo,
|
|||||||
return nsDocumentOpenInfo::TryStreamConversion(aChannel);
|
return nsDocumentOpenInfo::TryStreamConversion(aChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
|
||||||
loadInfo->GetSandboxFlags() &&
|
|
||||||
mContentType.LowerCaseEqualsLiteral(APPLICATION_PDF)) {
|
|
||||||
// Sandboxed iframes are just never allowed to display plugins. In the
|
|
||||||
// modern world, this just means "application/pdf".
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
nsCOMPtr<nsIStreamConverterService> streamConvService;
|
nsCOMPtr<nsIStreamConverterService> streamConvService;
|
||||||
nsAutoCString str;
|
nsAutoCString str;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "nsURILoader.h"
|
#include "nsURILoader.h"
|
||||||
#include "nsComponentManagerUtils.h"
|
#include "nsComponentManagerUtils.h"
|
||||||
|
#include "nsContentSecurityUtils.h"
|
||||||
#include "nsIURIContentListener.h"
|
#include "nsIURIContentListener.h"
|
||||||
#include "nsIContentHandler.h"
|
#include "nsIContentHandler.h"
|
||||||
#include "nsILoadGroup.h"
|
#include "nsILoadGroup.h"
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/IntegerPrintfMacros.h"
|
#include "mozilla/IntegerPrintfMacros.h"
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
#include "mozilla/Result.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
#include "mozilla/StaticPrefs_browser.h"
|
#include "mozilla/StaticPrefs_browser.h"
|
||||||
#include "mozilla/StaticPrefs_dom.h"
|
#include "mozilla/StaticPrefs_dom.h"
|
||||||
@@ -317,6 +319,62 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStopRequest(nsIRequest* request,
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsContentPDF(nsIChannel* aChannel, const nsACString& aContentType) {
|
||||||
|
bool isPDF = aContentType.LowerCaseEqualsASCII(APPLICATION_PDF);
|
||||||
|
if (!isPDF && (aContentType.LowerCaseEqualsASCII(APPLICATION_OCTET_STREAM) ||
|
||||||
|
aContentType.IsEmpty())) {
|
||||||
|
nsAutoString flname;
|
||||||
|
aChannel->GetContentDispositionFilename(flname);
|
||||||
|
isPDF = StringEndsWith(flname, u".pdf"_ns);
|
||||||
|
if (!isPDF) {
|
||||||
|
nsCOMPtr<nsIURI> uri;
|
||||||
|
aChannel->GetURI(getter_AddRefs(uri));
|
||||||
|
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
|
||||||
|
if (url) {
|
||||||
|
nsAutoCString ext;
|
||||||
|
url->GetFileExtension(ext);
|
||||||
|
isPDF = ext.EqualsLiteral("pdf");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return isPDF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mozilla::Result<bool, nsresult> ShouldHandleExternally(
|
||||||
|
const nsACString& aMimeType) {
|
||||||
|
// For a PDF, check if the preference is set that forces attachments to be
|
||||||
|
// opened inline. If so, treat it as a non-attachment by clearing
|
||||||
|
// 'forceExternalHandling' again. This allows it open a PDF directly
|
||||||
|
// instead of downloading it first. It may still end up being handled by
|
||||||
|
// a helper app depending anyway on the later checks.
|
||||||
|
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIMIMEService> mimeSvc(do_GetService(NS_MIMESERVICE_CONTRACTID));
|
||||||
|
if (!mimeSvc) {
|
||||||
|
return mozilla::Err(NS_ERROR_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
mimeSvc->GetFromTypeAndExtension(aMimeType, EmptyCString(),
|
||||||
|
getter_AddRefs(mimeInfo));
|
||||||
|
|
||||||
|
if (mimeInfo) {
|
||||||
|
int32_t action = nsIMIMEInfo::saveToDisk;
|
||||||
|
mimeInfo->GetPreferredAction(&action);
|
||||||
|
|
||||||
|
bool alwaysAsk = true;
|
||||||
|
mimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk);
|
||||||
|
return alwaysAsk || action != nsIMIMEInfo::handleInternally;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsSandboxed(nsIChannel* aChannel) {
|
||||||
|
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
|
||||||
|
return loadInfo->GetSandboxFlags();
|
||||||
|
}
|
||||||
|
|
||||||
nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request) {
|
nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request) {
|
||||||
LOG(("[0x%p] nsDocumentOpenInfo::DispatchContent for type '%s'", this,
|
LOG(("[0x%p] nsDocumentOpenInfo::DispatchContent for type '%s'", this,
|
||||||
mContentType.get()));
|
mContentType.get()));
|
||||||
@@ -367,56 +425,38 @@ nsresult nsDocumentOpenInfo::DispatchContent(nsIRequest* request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LOG((" forceExternalHandling: %s", forceExternalHandling ? "yes" : "no"));
|
LOG((" forceExternalHandling: %s", forceExternalHandling ? "yes" : "no"));
|
||||||
|
LOG((" IsSandboxed: %s", IsSandboxed(aChannel) ? "yes" : "no"));
|
||||||
|
LOG((" IsContentPDF: %s",
|
||||||
|
IsContentPDF(aChannel, mContentType) ? "yes" : "no"));
|
||||||
|
|
||||||
if (forceExternalHandling &&
|
bool maybeForceInternalHandling =
|
||||||
mozilla::StaticPrefs::browser_download_open_pdf_attachments_inline()) {
|
forceExternalHandling &&
|
||||||
// Check if this is a PDF which should be opened internally. We also handle
|
mozilla::StaticPrefs::browser_download_open_pdf_attachments_inline();
|
||||||
// octet-streams that look like they might be PDFs based on their extension.
|
|
||||||
bool isPDF = mContentType.LowerCaseEqualsASCII(APPLICATION_PDF);
|
|
||||||
if (!isPDF &&
|
|
||||||
(mContentType.LowerCaseEqualsASCII(APPLICATION_OCTET_STREAM) ||
|
|
||||||
mContentType.IsEmpty())) {
|
|
||||||
nsAutoString flname;
|
|
||||||
aChannel->GetContentDispositionFilename(flname);
|
|
||||||
isPDF = StringEndsWith(flname, u".pdf"_ns);
|
|
||||||
if (!isPDF) {
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
aChannel->GetURI(getter_AddRefs(uri));
|
|
||||||
nsCOMPtr<nsIURL> url(do_QueryInterface(uri));
|
|
||||||
if (url) {
|
|
||||||
nsAutoCString ext;
|
|
||||||
url->GetFileExtension(ext);
|
|
||||||
isPDF = ext.EqualsLiteral("pdf");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Check if this is a PDF which should be opened internally. We also handle
|
||||||
|
// octet-streams that look like they might be PDFs based on their extension.
|
||||||
|
if ((maybeForceInternalHandling || IsSandboxed(aChannel)) &&
|
||||||
|
IsContentPDF(aChannel, mContentType)) {
|
||||||
// For a PDF, check if the preference is set that forces attachments to be
|
// For a PDF, check if the preference is set that forces attachments to be
|
||||||
// opened inline. If so, treat it as a non-attachment by clearing
|
// opened inline. If so, treat it as a non-attachment by clearing
|
||||||
// 'forceExternalHandling' again. This allows it open a PDF directly
|
// 'forceExternalHandling' again. This allows it open a PDF directly
|
||||||
// instead of downloading it first. It may still end up being handled by
|
// instead of downloading it first. It may still end up being handled by
|
||||||
// a helper app depending anyway on the later checks.
|
// a helper app depending anyway on the later checks.
|
||||||
if (isPDF) {
|
auto result = ShouldHandleExternally(nsLiteralCString(APPLICATION_PDF));
|
||||||
nsCOMPtr<nsILoadInfo> loadInfo;
|
if (result.isErr()) {
|
||||||
aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
|
return result.unwrapErr();
|
||||||
|
}
|
||||||
|
forceExternalHandling = result.unwrap();
|
||||||
|
|
||||||
nsCOMPtr<nsIMIMEInfo> mimeInfo;
|
// If we're not opening the PDF externally we block it if it's sandboxed.
|
||||||
|
if (IsSandboxed(aChannel) && !forceExternalHandling) {
|
||||||
nsCOMPtr<nsIMIMEService> mimeSvc(
|
LOG(("Blocked sandboxed PDF"));
|
||||||
do_GetService(NS_MIMESERVICE_CONTRACTID));
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
||||||
NS_ENSURE_TRUE(mimeSvc, NS_ERROR_FAILURE);
|
if (httpChannel) {
|
||||||
mimeSvc->GetFromTypeAndExtension(nsLiteralCString(APPLICATION_PDF), ""_ns,
|
nsContentSecurityUtils::LogMessageToConsole(
|
||||||
getter_AddRefs(mimeInfo));
|
httpChannel, "IframeSandboxBlockedDownload");
|
||||||
|
|
||||||
if (mimeInfo) {
|
|
||||||
int32_t action = nsIMIMEInfo::saveToDisk;
|
|
||||||
mimeInfo->GetPreferredAction(&action);
|
|
||||||
|
|
||||||
bool alwaysAsk = true;
|
|
||||||
mimeInfo->GetAlwaysAskBeforeHandling(&alwaysAsk);
|
|
||||||
forceExternalHandling =
|
|
||||||
alwaysAsk || action != nsIMIMEInfo::handleInternally;
|
|
||||||
}
|
}
|
||||||
|
return NS_ERROR_CONTENT_BLOCKED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user