mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1696111 - ORB core Implementation; r=necko-reviewers,dragana
Differential Revision: https://phabricator.services.mozilla.com/D102448
This commit is contained in:
parent
612d68756f
commit
1ff4caafd7
@ -25,7 +25,10 @@ Classes = [
|
||||
'type': 'imgLoader',
|
||||
'headers': ['imgLoader.h'],
|
||||
'init_method': 'Init',
|
||||
'categories': {'content-sniffing-services': '@mozilla.org/image/loader;1'},
|
||||
'categories': {
|
||||
'content-sniffing-services': '@mozilla.org/image/loader;1',
|
||||
'net-content-sniffers': '@mozilla.org/image/loader;1',
|
||||
},
|
||||
},
|
||||
{
|
||||
'cid': '{f6fcd651-164b-4416-b001-9c8c393fd93b}',
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsContentPolicyUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsHttpChannel.h"
|
||||
#include "nsIApplicationCache.h"
|
||||
#include "nsIApplicationCacheContainer.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
@ -2709,7 +2710,21 @@ imgLoader::GetMIMETypeFromContent(nsIRequest* aRequest,
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
return GetMimeTypeFromContent((const char*)aContents, aLength, aContentType);
|
||||
|
||||
nsresult rv =
|
||||
GetMimeTypeFromContent((const char*)aContents, aLength, aContentType);
|
||||
if (NS_SUCCEEDED(rv) && channel && XRE_IsParentProcess()) {
|
||||
if (RefPtr<mozilla::net::nsHttpChannel> httpChannel =
|
||||
do_QueryObject(channel)) {
|
||||
// If the image type pattern matching algorithm given bytes does not
|
||||
// return undefined, then disable the further check and allow the
|
||||
// response.
|
||||
httpChannel->DisableIsOpaqueResponseAllowedAfterSniffCheck(
|
||||
mozilla::net::nsHttpChannel::SnifferType::Image);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -119,6 +119,8 @@ LOCAL_INCLUDES += [
|
||||
"/image/decoders",
|
||||
# For URI-related functionality
|
||||
"/netwerk/base",
|
||||
# For nsHttpChannel.h
|
||||
"/netwerk/protocol/http",
|
||||
# DecodePool uses thread-related facilities.
|
||||
"/xpcom/threads",
|
||||
]
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "mozilla/dom/Performance.h"
|
||||
#include "mozilla/dom/PerformanceStorage.h"
|
||||
#include "mozilla/dom/WindowGlobalParent.h"
|
||||
#include "mozilla/net/OpaqueResponseUtils.h"
|
||||
#include "mozilla/net/PartiallySeekableInputStream.h"
|
||||
#include "mozilla/net/UrlClassifierCommon.h"
|
||||
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
||||
@ -201,7 +202,10 @@ HttpBaseChannel::HttpBaseChannel()
|
||||
mPriority(PRIORITY_NORMAL),
|
||||
mRedirectionLimit(gHttpHandler->RedirectionLimit()),
|
||||
mRedirectCount(0),
|
||||
mInternalRedirectCount(0) {
|
||||
mInternalRedirectCount(0),
|
||||
mCachedOpaqueResponseBlockingPref(
|
||||
StaticPrefs::browser_opaqueResponseBlocking()),
|
||||
mCheckIsOpaqueResponseAllowedAfterSniff(false) {
|
||||
StoreApplyConversion(true);
|
||||
StoreAllowSTS(true);
|
||||
StoreInheritApplicationCache(true);
|
||||
@ -2774,6 +2778,139 @@ nsresult HttpBaseChannel::ValidateMIMEType() {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool HttpBaseChannel::EnsureOpaqueResponseIsAllowed() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
if (!mCachedOpaqueResponseBlockingPref) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mURI || !mResponseHead || !mLoadInfo) {
|
||||
// if there is no uri, no response head or no loadInfo, then there is
|
||||
// nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = mLoadInfo->GetLoadingPrincipal();
|
||||
if (!principal || principal->IsSystemPrincipal()) {
|
||||
// If it's a top-level load or a system principal, then there is nothing to
|
||||
// do.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if it's cross-origin without CORS.
|
||||
const bool isPrivateWin =
|
||||
mLoadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
|
||||
bool isSameOrigin = false;
|
||||
principal->IsSameOrigin(mURI, isPrivateWin, &isSameOrigin);
|
||||
if (isSameOrigin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoCString corsOrigin;
|
||||
nsresult rv = mResponseHead->GetHeader(
|
||||
nsHttp::ResolveAtom("Access-Control-Allow-Origin"), corsOrigin);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (corsOrigin.Equals("*")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> corsOriginURI;
|
||||
rv = NS_NewURI(getter_AddRefs(corsOriginURI), corsOrigin);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
bool isSameOrigin = false;
|
||||
principal->IsSameOrigin(corsOriginURI, isPrivateWin, &isSameOrigin);
|
||||
if (isSameOrigin) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsAutoCString contentType;
|
||||
mResponseHead->ContentType(contentType);
|
||||
if (!contentType.IsEmpty()) {
|
||||
if (IsOpaqueSafeListedMIMEType(contentType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsOpaqueBlockListedNeverSniffedMIMEType(contentType)) {
|
||||
// XXXtt: Report To Console.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mResponseHead->Status() == 206 &&
|
||||
IsOpaqueBlockListedMIMEType(contentType)) {
|
||||
// XXXtt: Report To Console.
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString contentTypeOptionsHeader;
|
||||
if (mResponseHead->GetContentTypeOptionsHeader(contentTypeOptionsHeader) &&
|
||||
contentTypeOptionsHeader.EqualsIgnoreCase("nosniff") &&
|
||||
(IsOpaqueBlockListedMIMEType(contentType) ||
|
||||
contentType.EqualsLiteral(TEXT_PLAIN))) {
|
||||
// XXXtt: Report To Console.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mLoadFlags |= (nsIChannel::LOAD_CALL_CONTENT_SNIFFERS |
|
||||
nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE);
|
||||
mCheckIsOpaqueResponseAllowedAfterSniff = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Result<bool, nsresult>
|
||||
HttpBaseChannel::EnsureOpaqueResponseIsAllowedAfterSniff() {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
if (!mCheckIsOpaqueResponseAllowedAfterSniff) {
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCachedOpaqueResponseBlockingPref);
|
||||
|
||||
nsAutoCString contentType;
|
||||
nsresult rv = GetContentType(contentType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return Err(rv);
|
||||
}
|
||||
|
||||
if (!mResponseHead) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsAutoCString contentTypeOptionsHeader;
|
||||
if (mResponseHead->GetContentTypeOptionsHeader(contentTypeOptionsHeader) &&
|
||||
contentTypeOptionsHeader.EqualsIgnoreCase("nosniff")) {
|
||||
// XXXtt: Report To Console.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mResponseHead->Status() < 200 || mResponseHead->Status() > 299) {
|
||||
// XXXtt: Report To Console.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (contentType.EqualsLiteral(UNKNOWN_CONTENT_TYPE) ||
|
||||
contentType.EqualsLiteral(APPLICATION_OCTET_STREAM)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StringBeginsWith(contentType, "image/"_ns) ||
|
||||
StringBeginsWith(contentType, "video/"_ns) ||
|
||||
StringBeginsWith(contentType, "audio/"_ns)) {
|
||||
// XXXtt: Report To Console.
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXXtt: If response's body parses as JavaScript and does not parse as JSON,
|
||||
// then return true.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::SetCookie(const nsACString& aCookieHeader) {
|
||||
if (mLoadFlags & LOAD_ANONYMOUS) return NS_OK;
|
||||
|
@ -616,6 +616,10 @@ class HttpBaseChannel : public nsHashPropertyBag,
|
||||
|
||||
nsresult ValidateMIMEType();
|
||||
|
||||
bool EnsureOpaqueResponseIsAllowed();
|
||||
|
||||
Result<bool, nsresult> EnsureOpaqueResponseIsAllowedAfterSniff();
|
||||
|
||||
friend class PrivateBrowsingChannel<HttpBaseChannel>;
|
||||
friend class InterceptFailedOnStop;
|
||||
|
||||
@ -881,6 +885,9 @@ class HttpBaseChannel : public nsHashPropertyBag,
|
||||
// Number of internal redirects that has occurred.
|
||||
int8_t mInternalRedirectCount;
|
||||
|
||||
const bool mCachedOpaqueResponseBlockingPref;
|
||||
bool mCheckIsOpaqueResponseAllowedAfterSniff;
|
||||
|
||||
// clang-format off
|
||||
MOZ_ATOMIC_BITFIELDS(mAtomicBitfields3, 8, (
|
||||
(bool, AsyncOpenTimeOverriden, 1),
|
||||
|
@ -1016,10 +1016,23 @@ InterceptedHttpChannel::OnStartRequest(nsIRequest* aRequest) {
|
||||
GetCallback(mProgressSink);
|
||||
}
|
||||
|
||||
if (!EnsureOpaqueResponseIsAllowed()) {
|
||||
// XXXtt: Return an error code or make the response body null.
|
||||
// We silence the error result now because we only want to get how many
|
||||
// response will get allowed or blocked by ORB.
|
||||
}
|
||||
|
||||
if (mPump && mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) {
|
||||
mPump->PeekStream(CallTypeSniffers, static_cast<nsIChannel*>(this));
|
||||
}
|
||||
|
||||
auto isAllowedOrErr = EnsureOpaqueResponseIsAllowedAfterSniff();
|
||||
if (isAllowedOrErr.isErr() || !isAllowedOrErr.inspect()) {
|
||||
// XXXtt: Return an error code or make the response body null.
|
||||
// We silence the error result now because we only want to get how many
|
||||
// response will get allowed or blocked by ORB.
|
||||
}
|
||||
|
||||
nsresult rv = ProcessCrossOriginEmbedderPolicyHeader();
|
||||
if (NS_FAILED(rv)) {
|
||||
mStatus = NS_ERROR_BLOCKED_BY_POLICY;
|
||||
|
@ -124,6 +124,7 @@
|
||||
#include "mozilla/net/AsyncUrlChannelClassifier.h"
|
||||
#include "mozilla/net/CookieJarSettings.h"
|
||||
#include "mozilla/net/NeckoChannelParams.h"
|
||||
#include "mozilla/net/OpaqueResponseUtils.h"
|
||||
#include "mozilla/net/UrlClassifierFeatureFactory.h"
|
||||
#include "HttpTrafficAnalyzer.h"
|
||||
#include "mozilla/net/SocketProcessParent.h"
|
||||
@ -1618,6 +1619,16 @@ nsresult nsHttpChannel::CallOnStartRequest() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
// EnsureOpaqueResponseIsAllowed and EnsureOpauqeResponseIsAllowedAfterSniff
|
||||
// are the checks for Opaque Response Blocking to ensure that we block as many
|
||||
// cross-origin responses with CORS headers as possible that are not either
|
||||
// Javascript or media to avoid leaking their contents through side channels.
|
||||
if (!EnsureOpaqueResponseIsAllowed()) {
|
||||
// XXXtt: Return an error code or make the response body null.
|
||||
// We silence the error result now because we only want to get how many
|
||||
// response will get allowed or blocked by ORB.
|
||||
}
|
||||
|
||||
// Allow consumers to override our content type
|
||||
if (mLoadFlags & LOAD_CALL_CONTENT_SNIFFERS) {
|
||||
// NOTE: We can have both a txn pump and a cache pump when the cache
|
||||
@ -1646,6 +1657,13 @@ nsresult nsHttpChannel::CallOnStartRequest() {
|
||||
}
|
||||
}
|
||||
|
||||
auto isAllowedOrErr = EnsureOpaqueResponseIsAllowedAfterSniff();
|
||||
if (isAllowedOrErr.isErr() || !isAllowedOrErr.inspect()) {
|
||||
// XXXtt: Return an error code or make the response body null.
|
||||
// We silence the error result now because we only want to get how many
|
||||
// response will get allowed or blocked by ORB.
|
||||
}
|
||||
|
||||
// Note that the code below should be synced with the code in
|
||||
// HttpTransactionChild::CanSendODAToContentProcessDirectly(). We MUST make
|
||||
// sure HttpTransactionChild::CanSendODAToContentProcessDirectly() returns
|
||||
@ -9963,6 +9981,20 @@ HttpChannelSecurityWarningReporter* nsHttpChannel::GetWarningReporter() {
|
||||
return mWarningReporter.get();
|
||||
}
|
||||
|
||||
// Should only be called by nsMediaSniffer::GetMIMETypeFromContent and
|
||||
// nsMediaSniffer::GetMIMETypeFromContent when the content type can be
|
||||
// recognized by these sniffers.
|
||||
void nsHttpChannel::DisableIsOpaqueResponseAllowedAfterSniffCheck(
|
||||
SnifferType aType) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
if (mCheckIsOpaqueResponseAllowedAfterSniff) {
|
||||
MOZ_ASSERT(mCachedOpaqueResponseBlockingPref);
|
||||
|
||||
mCheckIsOpaqueResponseAllowedAfterSniff = false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CopyNonDefaultHeaderVisitor final : public nsIHttpHeaderVisitor {
|
||||
|
@ -201,6 +201,9 @@ class nsHttpChannel final : public HttpBaseChannel,
|
||||
|
||||
bool DataSentToChildProcess() { return LoadDataSentToChildProcess(); }
|
||||
|
||||
enum class SnifferType { Media, Image };
|
||||
void DisableIsOpaqueResponseAllowedAfterSniffCheck(SnifferType aType);
|
||||
|
||||
public: /* internal necko use only */
|
||||
uint32_t GetRequestTime() const { return mRequestTime; }
|
||||
|
||||
|
@ -23,3 +23,11 @@ FINAL_LIBRARY = "xul"
|
||||
|
||||
with Files("**"):
|
||||
BUG_COMPONENT = ("Core", "Audio/Video")
|
||||
|
||||
include("/ipc/chromium/chromium-config.mozbuild")
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
# For nsHttpChannel.h
|
||||
"/netwerk/base",
|
||||
"/netwerk/protocol/http",
|
||||
]
|
||||
|
@ -10,10 +10,12 @@
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "mp3sniff.h"
|
||||
#include "nestegg/nestegg.h"
|
||||
#include "nsHttpChannel.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsIChannel.h"
|
||||
#include "nsMediaSniffer.h"
|
||||
#include "nsMimeTypes.h"
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsString.h"
|
||||
|
||||
#include <algorithm>
|
||||
@ -165,6 +167,19 @@ nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest,
|
||||
|
||||
const uint32_t clampedLength = std::min(aLength, MAX_BYTES_SNIFFED);
|
||||
|
||||
auto maybeUpdate = mozilla::MakeScopeExit([&channel]() {
|
||||
if (channel && XRE_IsParentProcess()) {
|
||||
if (RefPtr<mozilla::net::nsHttpChannel> httpChannel =
|
||||
do_QueryObject(channel)) {
|
||||
// If the audio or video type pattern matching algorithm given bytes
|
||||
// does not return undefined, then disable the further check and allow
|
||||
// the response.
|
||||
httpChannel->DisableIsOpaqueResponseAllowedAfterSniffCheck(
|
||||
mozilla::net::nsHttpChannel::SnifferType::Media);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < mozilla::ArrayLength(sSnifferEntries); ++i) {
|
||||
const nsMediaSnifferEntry& currentEntry = sSnifferEntries[i];
|
||||
if (clampedLength < currentEntry.mLength || currentEntry.mLength == 0) {
|
||||
@ -211,6 +226,8 @@ nsMediaSniffer::GetMIMETypeFromContent(nsIRequest* aRequest,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
maybeUpdate.release();
|
||||
|
||||
// Could not sniff the media type, we are required to set it to
|
||||
// application/octet-stream.
|
||||
aSniffedType.AssignLiteral(APPLICATION_OCTET_STREAM);
|
||||
|
Loading…
Reference in New Issue
Block a user