Bug 1555036 - If there is a Cross-Origin-Opener-Policy mismatch and the SANDBOXED_AUXILIARY_NAVIGATION is set navigate to a network error r=mayhemer
authorValentin Gosu <valentin.gosu@gmail.com>
Fri, 14 Jun 2019 21:48:51 +0000
changeset 478960 311baee18a93f0564bf0928f913a9ce6faef0332
parent 478959 ae4f5a5b9febd67246deceeb18438d6c15ead307
child 478961 285673afaa99a6097e244fb0c1ba0b2b6945893d
push id36155
push userapavel@mozilla.com
push dateSat, 15 Jun 2019 09:53:16 +0000
treeherdermozilla-central@dd19d57a81d5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1555036
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1555036 - If there is a Cross-Origin-Opener-Policy mismatch and the SANDBOXED_AUXILIARY_NAVIGATION is set navigate to a network error r=mayhemer Differential Revision: https://phabricator.services.mozilla.com/D34420
docshell/base/nsDocShell.cpp
modules/libpref/init/StaticPrefList.h
modules/libpref/init/all.js
netwerk/ipc/NeckoChannelParams.ipdlh
netwerk/protocol/http/ClassifierDummyChannel.cpp
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
netwerk/protocol/http/nsIHttpChannelInternal.idl
netwerk/protocol/viewsource/nsViewSourceChannel.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -10480,16 +10480,24 @@ nsresult nsDocShell::DoChannelLoad(nsICh
   nsLoadFlags loadFlags = 0;
   (void)aChannel->GetLoadFlags(&loadFlags);
   loadFlags |=
       nsIChannel::LOAD_DOCUMENT_URI | nsIChannel::LOAD_CALL_CONTENT_SNIFFERS;
 
   if (SandboxFlagsImplyCookies(mSandboxFlags)) {
     loadFlags |= nsIRequest::LOAD_DOCUMENT_NEEDS_COOKIE;
   }
+
+  if (mSandboxFlags & SANDBOXED_AUXILIARY_NAVIGATION) {
+    nsCOMPtr<nsIHttpChannelInternal> httpChannel(do_QueryInterface(aChannel));
+    if (httpChannel) {
+      httpChannel->SetHasSandboxedAuxiliaryNavigations(true);
+    }
+  }
+
   // Load attributes depend on load type...
   switch (mLoadType) {
     case LOAD_HISTORY: {
       // Only send VALIDATE_NEVER if mLSHE's URI was never changed via
       // push/replaceState (bug 669671).
       bool uriModified = false;
       if (mLSHE) {
         uriModified = mLSHE->GetURIWasModified();
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -918,16 +918,25 @@ VARCACHE_PREF(
 // Cross-Origin header will fail to load
 VARCACHE_PREF(
   Live,
   "browser.tabs.remote.useCrossOriginPolicy",
   browser_tabs_remote_useCrossOriginPolicy,
   bool, false
 )
 
+// When this pref is enabled top level loads with a mismatched
+// Cross-Origin-Opener-Policy header will be loaded in a separate process.
+VARCACHE_PREF(
+  Live,
+  "browser.tabs.remote.useCrossOriginOpenerPolicy",
+  browser_tabs_remote_useCrossOriginOpenerPolicy,
+  bool, false
+)
+
 // When this pref is enabled, the browser will check no-cors responses that
 // have the Cross-Origin-Resource-Policy header and will fail the request if
 // the origin of the resource's loading document doesn't match the origin
 // (or base domain) of the loaded resource.
 VARCACHE_PREF(
   Live,
   "browser.tabs.remote.useCORP",
   browser_tabs_remote_useCORP,
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3179,20 +3179,16 @@ pref("browser.tabs.remote.separatePrivil
 // Pref to control whether we use a separate privileged content process
 // for certain mozilla webpages (which are listed in the following pref).
 pref("browser.tabs.remote.separatePrivilegedMozillaWebContentProcess", false);
 
 // The domains we will isolate into the Mozilla Content Process. Comma-separated
 // full domains: any subdomains of the domains listed will also be allowed.
 pref("browser.tabs.remote.separatedMozillaDomains", "addons.mozilla.org,accounts.firefox.com");
 
-// When this pref is enabled top level loads with a mismatched
-// Cross-Origin-Opener-Policy header will be loaded in a separate process.
-pref("browser.tabs.remote.useCrossOriginOpenerPolicy", false);
-
 // Enable the use of display-lists for SVG hit-testing and painting.
 pref("svg.display-lists.hit-testing.enabled", true);
 pref("svg.display-lists.painting.enabled", true);
 
 // Is support for the new getBBox method from SVG 2 enabled?
 // See https://svgwg.org/svg2-draft/single-page.html#types-SVGBoundingBoxOptions
 pref("svg.new-getBBox.enabled", false);
 
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -269,16 +269,17 @@ struct HttpChannelOpenArgs
   TimeStamp                   launchServiceWorkerStart;
   TimeStamp                   launchServiceWorkerEnd;
   TimeStamp                   dispatchFetchEventStart;
   TimeStamp                   dispatchFetchEventEnd;
   TimeStamp                   handleFetchEventStart;
   TimeStamp                   handleFetchEventEnd;
   bool                        forceMainDocumentChannel;
   TimeStamp                   navigationStartTimeStamp;
+  bool                        hasSandboxedAuxiliaryNavigations;
 };
 
 struct HttpChannelConnectArgs
 {
   uint32_t registrarId;
   bool shouldIntercept;
 };
 
--- a/netwerk/protocol/http/ClassifierDummyChannel.cpp
+++ b/netwerk/protocol/http/ClassifierDummyChannel.cpp
@@ -622,15 +622,22 @@ NS_IMETHODIMP
 ClassifierDummyChannel::CancelByURLClassifier(nsresult aErrorCode) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 void ClassifierDummyChannel::SetIPv4Disabled() {}
 
 void ClassifierDummyChannel::SetIPv6Disabled() {}
 
+bool ClassifierDummyChannel::GetHasSandboxedAuxiliaryNavigations() {
+  return false;
+}
+
+void ClassifierDummyChannel::SetHasSandboxedAuxiliaryNavigations(
+    bool aHasSandboxedAuxiliaryNavigations) {}
+
 NS_IMETHODIMP ClassifierDummyChannel::GetCrossOriginOpenerPolicy(
     nsILoadInfo::CrossOriginOpenerPolicy* aPolicy) {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -204,16 +204,17 @@ HttpBaseChannel::HttpBaseChannel()
       mAllRedirectsSameOrigin(true),
       mAllRedirectsPassTimingAllowCheck(true),
       mResponseCouldBeSynthesized(false),
       mBlockAuthPrompt(false),
       mAllowStaleCacheContent(false),
       mAddedAsNonTailRequest(false),
       mAsyncOpenWaitingForStreamLength(false),
       mUpgradableToSecure(true),
+      mHasSandboxedNavigations(false),
       mTlsFlags(0),
       mSuspendCount(0),
       mInitialRwin(0),
       mProxyResolveFlags(0),
       mContentDispositionHint(UINT32_MAX),
       mCorsMode(nsIHttpChannelInternal::CORS_MODE_NO_CORS),
       mRedirectMode(nsIHttpChannelInternal::REDIRECT_MODE_FOLLOW),
       mLastRedirectFlags(0),
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -312,16 +312,23 @@ class HttpBaseChannel : public nsHashPro
   NS_IMETHOD SetLastRedirectFlags(uint32_t aValue) override;
   NS_IMETHOD GetNavigationStartTimeStamp(TimeStamp* aTimeStamp) override;
   NS_IMETHOD SetNavigationStartTimeStamp(TimeStamp aTimeStamp) override;
   NS_IMETHOD CancelByURLClassifier(nsresult aErrorCode) override;
   virtual void SetIPv4Disabled(void) override;
   virtual void SetIPv6Disabled(void) override;
   NS_IMETHOD GetCrossOriginOpenerPolicy(
       nsILoadInfo::CrossOriginOpenerPolicy* aPolicy) override;
+  virtual bool GetHasSandboxedAuxiliaryNavigations() override {
+    return mHasSandboxedNavigations;
+  }
+  virtual void SetHasSandboxedAuxiliaryNavigations(
+      bool aHasSandboxedAuxiliaryNavigations) override {
+    mHasSandboxedNavigations = aHasSandboxedAuxiliaryNavigations;
+  }
 
   inline void CleanRedirectCacheChainIfNecessary() {
     mRedirectedCachekeys = nullptr;
   }
   NS_IMETHOD HTTPUpgrade(const nsACString& aProtocolName,
                          nsIHttpUpgradeListener* aListener) override;
 
   // nsISupportsPriority
@@ -726,16 +733,19 @@ class HttpBaseChannel : public nsHashPro
   // AsyncOpen() will be retriggered when InputStreamLengthHelper execs the
   // callback, passing the stream length value.
   uint32_t mAsyncOpenWaitingForStreamLength : 1;
 
   // Defaults to true.  This is set to false when it is no longer possible
   // to upgrade the request to a secure channel.
   uint32_t mUpgradableToSecure : 1;
 
+  // Is true if the docshell has the SANDBOXED_AUXILIARY_NAVIGATION flag set.
+  uint32_t mHasSandboxedNavigations : 1;
+
   // An opaque flags for non-standard behavior of the TLS system.
   // It is unlikely this will need to be set outside of telemetry studies
   // relating to the TLS implementation.
   uint32_t mTlsFlags;
 
   // Current suspension depth for this channel object
   uint32_t mSuspendCount;
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -2902,16 +2902,18 @@ nsresult HttpChannelChild::ContinueAsync
   openArgs.dispatchFetchEventStart() = mDispatchFetchEventStart;
   openArgs.dispatchFetchEventEnd() = mDispatchFetchEventEnd;
   openArgs.handleFetchEventStart() = mHandleFetchEventStart;
   openArgs.handleFetchEventEnd() = mHandleFetchEventEnd;
 
   openArgs.forceMainDocumentChannel() = mForceMainDocumentChannel;
 
   openArgs.navigationStartTimeStamp() = navigationStartTimeStamp;
+  openArgs.hasSandboxedAuxiliaryNavigations() =
+      GetHasSandboxedAuxiliaryNavigations();
 
   // This must happen before the constructor message is sent. Otherwise messages
   // from the parent could arrive quickly and be delivered to the wrong event
   // target.
   SetEventTarget();
 
   // The socket transport in the chrome process now holds a logical ref to us
   // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -145,17 +145,18 @@ bool HttpChannelParent::Init(const HttpC
           a.initialRwin(), a.blockAuthPrompt(),
           a.suspendAfterSynthesizeResponse(), a.allowStaleCacheContent(),
           a.contentTypeHint(), a.corsMode(), a.redirectMode(), a.channelId(),
           a.integrityMetadata(), a.contentWindowId(),
           a.preferredAlternativeTypes(), a.topLevelOuterContentWindowId(),
           a.launchServiceWorkerStart(), a.launchServiceWorkerEnd(),
           a.dispatchFetchEventStart(), a.dispatchFetchEventEnd(),
           a.handleFetchEventStart(), a.handleFetchEventEnd(),
-          a.forceMainDocumentChannel(), a.navigationStartTimeStamp());
+          a.forceMainDocumentChannel(), a.navigationStartTimeStamp(),
+          a.hasSandboxedAuxiliaryNavigations());
     }
     case HttpChannelCreationArgs::THttpChannelConnectArgs: {
       const HttpChannelConnectArgs& cArgs = aArgs.get_HttpChannelConnectArgs();
       return ConnectChannel(cArgs.registrarId(), cArgs.shouldIntercept());
     }
     default:
       MOZ_ASSERT_UNREACHABLE("unknown open type");
       return false;
@@ -403,17 +404,18 @@ bool HttpChannelParent::DoAsyncOpen(
     const uint64_t& aTopLevelOuterContentWindowId,
     const TimeStamp& aLaunchServiceWorkerStart,
     const TimeStamp& aLaunchServiceWorkerEnd,
     const TimeStamp& aDispatchFetchEventStart,
     const TimeStamp& aDispatchFetchEventEnd,
     const TimeStamp& aHandleFetchEventStart,
     const TimeStamp& aHandleFetchEventEnd,
     const bool& aForceMainDocumentChannel,
-    const TimeStamp& aNavigationStartTimeStamp) {
+    const TimeStamp& aNavigationStartTimeStamp,
+    const bool& hasSandboxedAuxiliaryNavigations) {
   nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
   if (!uri) {
     // URIParams does MOZ_ASSERT if null, but we need to protect opt builds from
     // null deref here.
     return false;
   }
   nsCOMPtr<nsIURI> originalUri = DeserializeURI(aOriginalURI);
   nsCOMPtr<nsIURI> docUri = DeserializeURI(aDocURI);
@@ -487,16 +489,20 @@ bool HttpChannelParent::DoAsyncOpen(
 
   if (aLoadFlags != nsIRequest::LOAD_NORMAL)
     httpChannel->SetLoadFlags(aLoadFlags);
 
   if (aForceMainDocumentChannel) {
     httpChannel->SetIsMainDocumentChannel(true);
   }
 
+  if (hasSandboxedAuxiliaryNavigations) {
+    httpChannel->SetHasSandboxedAuxiliaryNavigations(true);
+  }
+
   for (uint32_t i = 0; i < requestHeaders.Length(); i++) {
     if (requestHeaders[i].mEmpty) {
       httpChannel->SetEmptyRequestHeader(requestHeaders[i].mHeader);
     } else {
       httpChannel->SetRequestHeader(requestHeaders[i].mHeader,
                                     requestHeaders[i].mValue,
                                     requestHeaders[i].mMerge);
     }
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -167,17 +167,18 @@ class HttpChannelParent final : public n
       const uint64_t& aTopLevelOuterContentWindowId,
       const TimeStamp& aLaunchServiceWorkerStart,
       const TimeStamp& aLaunchServiceWorkerEnd,
       const TimeStamp& aDispatchFetchEventStart,
       const TimeStamp& aDispatchFetchEventEnd,
       const TimeStamp& aHandleFetchEventStart,
       const TimeStamp& aHandleFetchEventEnd,
       const bool& aForceMainDocumentChannel,
-      const TimeStamp& aNavigationStartTimeStamp);
+      const TimeStamp& aNavigationStartTimeStamp,
+      const bool& hasSandboxedAuxiliaryNavigations);
 
   virtual mozilla::ipc::IPCResult RecvSetPriority(
       const int16_t& priority) override;
   virtual mozilla::ipc::IPCResult RecvSetClassOfService(
       const uint32_t& cos) override;
   virtual mozilla::ipc::IPCResult RecvSetCacheTokenCachedCharset(
       const nsCString& charset) override;
   virtual mozilla::ipc::IPCResult RecvSuspend() override;
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -2573,16 +2573,25 @@ nsresult nsHttpChannel::ContinueProcessR
   if (NS_FAILED(rv)) {
     mStatus = NS_ERROR_DOM_CORP_FAILED;
     HandleAsyncAbort();
     return NS_OK;
   }
 
   rv = NS_OK;
   if (!mCanceled) {
+    ComputeCrossOriginOpenerPolicyMismatch();
+    if (mHasCrossOriginOpenerPolicyMismatch &&
+        GetHasSandboxedAuxiliaryNavigations()) {
+      // this navigates the doc's browsing context to a network error.
+      mStatus = NS_ERROR_BLOCKED_BY_POLICY;
+      HandleAsyncAbort();
+      return NS_OK;
+    }
+
     // notify "http-on-may-change-process" observers
     gHttpHandler->OnMayChangeProcess(this);
 
     if (mRedirectContentProcessIdPromise) {
       MOZ_ASSERT(!mOnStartRequestCalled);
 
       PushRedirectAsyncFunc(&nsHttpChannel::ContinueProcessResponse2);
       rv = StartCrossProcessRedirect();
@@ -7352,16 +7361,19 @@ nsresult nsHttpChannel::StartCrossProces
                                         mCrossProcessRedirectIdentifier);
 
   // This will suspend the channel
   rv = WaitForRedirectCallback();
 
   return rv;
 }
 
+// See https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
+// This method runs steps 1-4 of the algorithm to compare
+// cross-origin-opener policies
 static bool CompareCrossOriginOpenerPolicies(
     nsILoadInfo::CrossOriginOpenerPolicy documentPolicy,
     nsIPrincipal* documentOrigin,
     nsILoadInfo::CrossOriginOpenerPolicy resultPolicy,
     nsIPrincipal* resultOrigin) {
   if (documentPolicy == nsILoadInfo::OPENER_POLICY_NULL &&
       resultPolicy == nsILoadInfo::OPENER_POLICY_NULL) {
     return true;
@@ -7389,24 +7401,37 @@ static bool CompareCrossOriginOpenerPoli
     if (siteOriginA == siteOriginB) {
       return true;
     }
   }
 
   return false;
 }
 
+// This method returns the cached result of running the Cross-Origin-Opener
+// policy compare algorithm by calling ComputeCrossOriginOpenerPolicyMismatch
 NS_IMETHODIMP
 nsHttpChannel::HasCrossOriginOpenerPolicyMismatch(bool* aMismatch) {
   MOZ_ASSERT(aMismatch);
   if (!aMismatch) {
     return NS_ERROR_INVALID_ARG;
   }
 
-  *aMismatch = false;
+  *aMismatch = mHasCrossOriginOpenerPolicyMismatch;
+  return NS_OK;
+}
+
+// This runs steps 1-5 of the algorithm when navigating a top level document.
+// See https://gist.github.com/annevk/6f2dd8c79c77123f39797f6bdac43f3e
+nsresult nsHttpChannel::ComputeCrossOriginOpenerPolicyMismatch() {
+  mHasCrossOriginOpenerPolicyMismatch = false;
+  if (!StaticPrefs::browser_tabs_remote_useCrossOriginOpenerPolicy()) {
+    return NS_OK;
+  }
+
   // Only consider Cross-Origin-Opener-Policy for toplevel document loads.
   if (mLoadInfo->GetExternalContentPolicyType() !=
       nsIContentPolicy::TYPE_DOCUMENT) {
     return NS_OK;
   }
 
   // Maybe the channel failed and we have no response head?
   nsHttpResponseHead* head =
@@ -7460,27 +7485,27 @@ nsHttpChannel::HasCrossOriginOpenerPolic
   // If one of the following is false:
   //   - document's unsafe-allow-outgoing is true
   //   - resultPolicy is null
   //   - doc is the initial about:blank document
   // then we have a mismatch.
 
   if (!(documentPolicy &
         nsILoadInfo::OPENER_POLICY_UNSAFE_ALLOW_OUTGOING_FLAG)) {
-    *aMismatch = true;
+    mHasCrossOriginOpenerPolicyMismatch = true;
     return NS_OK;
   }
 
   if (resultPolicy != nsILoadInfo::OPENER_POLICY_NULL) {
-    *aMismatch = true;
+    mHasCrossOriginOpenerPolicyMismatch = true;
     return NS_OK;
   }
 
   if (!ctx->Canonical()->GetCurrentWindowGlobal()->IsInitialDocument()) {
-    *aMismatch = true;
+    mHasCrossOriginOpenerPolicyMismatch = true;
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 nsresult nsHttpChannel::GetResponseCrossOriginPolicy(
     nsILoadInfo::CrossOriginPolicy* aResponseCrossOriginPolicy) {
@@ -7737,16 +7762,26 @@ nsHttpChannel::OnStartRequest(nsIRequest
     return NS_OK;
   }
 
   // before we check for redirects, check if the load should be shifted into a
   // new process.
   rv = NS_OK;
   if (!mCanceled) {
     // notify "http-on-may-change-process" observers
+    ComputeCrossOriginOpenerPolicyMismatch();
+
+    if (mHasCrossOriginOpenerPolicyMismatch &&
+        GetHasSandboxedAuxiliaryNavigations()) {
+      // this navigates the doc's browsing context to a network error.
+      mStatus = NS_ERROR_BLOCKED_BY_POLICY;
+      HandleAsyncAbort();
+      return NS_OK;
+    }
+
     gHttpHandler->OnMayChangeProcess(this);
 
     if (mRedirectContentProcessIdPromise) {
       PushRedirectAsyncFunc(&nsHttpChannel::ContinueOnStartRequest1);
       rv = StartCrossProcessRedirect();
       if (NS_SUCCEEDED(rv)) {
         return NS_OK;
       }
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -480,16 +480,18 @@ class nsHttpChannel final : public HttpB
    */
   void ProcessSecurityReport(nsresult status);
 
   nsresult GetResponseCrossOriginPolicy(
       nsILoadInfo::CrossOriginPolicy* aResponseCrossOriginPolicy);
   nsresult ProcessCrossOriginHeader();
   nsresult ProcessCrossOriginResourcePolicyHeader();
 
+  nsresult ComputeCrossOriginOpenerPolicyMismatch();
+
   /**
    * A function to process a single security header (STS or PKP), assumes
    * some basic sanity checks have been applied to the channel. Called
    * from ProcessSecurityHeaders.
    */
   MOZ_MUST_USE nsresult ProcessSingleSecurityHeader(
       uint32_t aType, nsITransportSecurityInfo* aSecInfo, uint32_t aFlags);
 
@@ -730,16 +732,20 @@ class nsHttpChannel final : public HttpB
   // True only when we have determined this channel should be isolated for
   // anti-tracking purposes.  Can never ben true unless mHasBeenIsolatedChecked
   // is true.
   uint32_t mIsIsolated : 1;
 
   // True only when we have computed the value of the top window origin.
   uint32_t mTopWindowOriginComputed : 1;
 
+  // True if this is a navigation to a page with a different cross origin
+  // opener policy ( see ComputeCrossOriginOpenerPolicyMismatch )
+  uint32_t mHasCrossOriginOpenerPolicyMismatch : 1;
+
   // The origin of the top window, only valid when mTopWindowOriginComputed is
   // true.
   nsCString mTopWindowOrigin;
 
   nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
 
   // Needed for accurate DNS timing
   RefPtr<nsDNSPrefetch> mDNSPrefetch;
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -375,9 +375,11 @@ interface nsIHttpChannelInternal : nsISu
     /**
      * The channel will be loaded over IPv4, disabling IPv6.
      */
     [noscript, notxpcom, nostdcall]
     void setIPv6Disabled();
 
     [noscript]
     nsILoadInfo_CrossOriginOpenerPolicy getCrossOriginOpenerPolicy();
+
+    [notxpcom, nostdcall] attribute boolean hasSandboxedAuxiliaryNavigations;
 };
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -1047,8 +1047,23 @@ void nsViewSourceChannel::SetIPv4Disable
   }
 }
 
 void nsViewSourceChannel::SetIPv6Disabled() {
   if (mHttpChannelInternal) {
     mHttpChannelInternal->SetIPv6Disabled();
   }
 }
+
+bool nsViewSourceChannel::GetHasSandboxedAuxiliaryNavigations() {
+  if (mHttpChannelInternal) {
+    return mHttpChannelInternal->GetHasSandboxedAuxiliaryNavigations();
+  }
+  return false;
+}
+
+void nsViewSourceChannel::SetHasSandboxedAuxiliaryNavigations(
+    bool aHasSandboxedAuxiliaryNavigations) {
+  if (mHttpChannelInternal) {
+    mHttpChannelInternal->SetHasSandboxedAuxiliaryNavigations(
+        aHasSandboxedAuxiliaryNavigations);
+  }
+}