Commit cc67fc68 authored by Lowell Manners's avatar Lowell Manners Committed by Commit Bot

[bfcache] Don't immediately flush pages with related SiteInstances.

Rather than synchronously deleting all pages in the BackForwardCache
when there is a conflicting BrowsingInstance, call
EvictFramesInBrowsingInstance which asynchronously deletes only the
conflicting pages.

Calling evict is safer than immediately deleting frames, which can lead
to UAF bugs.

Change-Id: I4e453c3c1dacc5ed764cc344efbc26f24d7fe115
Bug: 993337
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1844964
Commit-Queue: Lowell Manners <lowell@chromium.org>
Reviewed-by: default avatarAlex Moshchuk <alexmos@chromium.org>
Reviewed-by: default avatarArthur Sonzogni <arthursonzogni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#707310}
parent 3236b343
...@@ -222,6 +222,8 @@ std::string BackForwardCacheImpl::CanStoreDocumentResult::ToString() { ...@@ -222,6 +222,8 @@ std::string BackForwardCacheImpl::CanStoreDocumentResult::ToString() {
return "No: granted media stream access"; return "No: granted media stream access";
case Reason::kSchedulerTrackedFeatureUsed: case Reason::kSchedulerTrackedFeatureUsed:
return "No: scheduler tracked feature is used"; return "No: scheduler tracked feature is used";
case Reason::kConflictingBrowsingInstance:
return "No: conflicting BrowsingInstance";
} }
} }
...@@ -464,6 +466,17 @@ void BackForwardCacheImpl::Flush() { ...@@ -464,6 +466,17 @@ void BackForwardCacheImpl::Flush() {
entries_.clear(); entries_.clear();
} }
void BackForwardCacheImpl::EvictFramesInRelatedSiteInstances(
SiteInstance* site_instance) {
for (std::unique_ptr<Entry>& entry : entries_) {
if (entry->render_frame_host->GetSiteInstance()->IsRelatedSiteInstance(
site_instance))
entry->render_frame_host->EvictFromBackForwardCacheWithReason(
BackForwardCacheMetrics::NotRestoredReason::
kConflictingBrowsingInstance);
}
}
void BackForwardCacheImpl::PostTaskToDestroyEvictedFrames() { void BackForwardCacheImpl::PostTaskToDestroyEvictedFrames() {
base::PostTask(FROM_HERE, {BrowserThread::UI}, base::PostTask(FROM_HERE, {BrowserThread::UI},
base::BindOnce(&BackForwardCacheImpl::DestroyEvictedFrames, base::BindOnce(&BackForwardCacheImpl::DestroyEvictedFrames,
......
...@@ -27,6 +27,7 @@ namespace content { ...@@ -27,6 +27,7 @@ namespace content {
class RenderFrameHostImpl; class RenderFrameHostImpl;
class RenderFrameProxyHost; class RenderFrameProxyHost;
class RenderViewHostImpl; class RenderViewHostImpl;
class SiteInstance;
// BackForwardCache: // BackForwardCache:
// //
...@@ -131,6 +132,10 @@ class CONTENT_EXPORT BackForwardCacheImpl : public BackForwardCache { ...@@ -131,6 +132,10 @@ class CONTENT_EXPORT BackForwardCacheImpl : public BackForwardCache {
// Remove all entries from the BackForwardCache. // Remove all entries from the BackForwardCache.
void Flush(); void Flush();
// Evict all cached pages in the same BrowsingInstance as
// |site_instance|.
void EvictFramesInRelatedSiteInstances(SiteInstance* site_instance);
// Posts a task to destroy all frames in the BackForwardCache that have been // Posts a task to destroy all frames in the BackForwardCache that have been
// marked as evicted. // marked as evicted.
void PostTaskToDestroyEvictedFrames(); void PostTaskToDestroyEvictedFrames();
......
...@@ -58,7 +58,8 @@ class BackForwardCacheMetrics ...@@ -58,7 +58,8 @@ class BackForwardCacheMetrics
kDialog = 17, kDialog = 17,
kGrantedMediaStreamAccess = 18, kGrantedMediaStreamAccess = 18,
kSchedulerTrackedFeatureUsed = 19, kSchedulerTrackedFeatureUsed = 19,
kMaxValue = kSchedulerTrackedFeatureUsed, kConflictingBrowsingInstance = 20,
kMaxValue = kConflictingBrowsingInstance,
}; };
// Please keep in sync with BackForwardCacheHistoryNavigationOutcome in // Please keep in sync with BackForwardCacheHistoryNavigationOutcome in
......
...@@ -2558,18 +2558,30 @@ void NavigationControllerImpl::NavigateToExistingPendingEntry( ...@@ -2558,18 +2558,30 @@ void NavigationControllerImpl::NavigateToExistingPendingEntry(
return; return;
} }
// By design, a page in the BackForwardCache is alone in its BrowsingInstance. // History navigation might try to reuse a specific BrowsingInstance, already
// History navigation might try to reuse a specific SiteInstance, already used // used by a page in the cache. To avoid having two different main frames that
// by a page in the cache. This must not happen. It would fail creating the // live in the same BrowsingInstance, evict the all pages with this
// RenderFrame, because only one main document can live there. For this // BrowsingInstance from the cache.
// reason, the BackForwardCache is flushed. //
// TODO(arthursonzogni): Flushing the entire cache is a bit overkill, this can // For example, take the following scenario:
// be refined to only delete the page (if any) using the same //
// BrowsingInstance. // A1 = Some page on a.com
// A2 = Some other page on a.com
// B3 = An uncacheable page on b.com
//
// Then the following navigations occur:
// A1->A2->B3->A1
// On the navigation from B3 to A1, A2 will remain in the cache (B3 doesn't
// take its place) and A1 will be created in the same BrowsingInstance (and
// SiteInstance), as A2.
//
// If we didn't do anything, both A1 and A2 would remain alive in the same
// BrowsingInstance/SiteInstance, which is unsupported by
// RenderFrameHostManager::CommitPending(). To avoid this conundrum, we evict
// A2 from the cache.
if (pending_entry_->site_instance()) { if (pending_entry_->site_instance()) {
SiteInstance* current = root->current_frame_host()->GetSiteInstance(); back_forward_cache_.EvictFramesInRelatedSiteInstances(
if (!current->IsRelatedSiteInstance(pending_entry_->site_instance())) pending_entry_->site_instance());
back_forward_cache_.Flush();
} }
// If we were navigating to a slow-to-commit page, and the user performs // If we were navigating to a slow-to-commit page, and the user performs
......
...@@ -4766,6 +4766,7 @@ Unknown properties are collapsed to zero. --> ...@@ -4766,6 +4766,7 @@ Unknown properties are collapsed to zero. -->
<int value="17" label="Dialog"/> <int value="17" label="Dialog"/>
<int value="18" label="Granted media stream access"/> <int value="18" label="Granted media stream access"/>
<int value="19" label="Scheduler tracked feature used"/> <int value="19" label="Scheduler tracked feature used"/>
<int value="20" label="Conflicting BrowsingInstance"/>
</enum> </enum>
<enum name="BackForwardNavigationType"> <enum name="BackForwardNavigationType">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment