Fix UAF in Origin Info Bubble and permission settings UI.
In addition to fixing the UAF, will this also fix the problem of the bubble
showing over the previous tab (if the bubble is open when the tab it was opened
for closes).
BUG=490492
TBR=tedchoc
Review URL: https://codereview.chromium.org/1317443002
Cr-Commit-Position: refs/heads/master@{#346023}
diff --git a/chrome/browser/ui/android/connection_info_popup_android.cc b/chrome/browser/ui/android/connection_info_popup_android.cc
index 4be9e373..9e41c35b 100644
--- a/chrome/browser/ui/android/connection_info_popup_android.cc
+++ b/chrome/browser/ui/android/connection_info_popup_android.cc
@@ -92,7 +92,7 @@
this,
Profile::FromBrowserContext(web_contents->GetBrowserContext()),
TabSpecificContentSettings::FromWebContents(web_contents),
- InfoBarService::FromWebContents(web_contents),
+ web_contents,
nav_entry->GetURL(),
nav_entry->GetSSL(),
content::CertStore::GetInstance()));
diff --git a/chrome/browser/ui/android/website_settings_popup_android.cc b/chrome/browser/ui/android/website_settings_popup_android.cc
index e698f03c..4b4c9f1 100644
--- a/chrome/browser/ui/android/website_settings_popup_android.cc
+++ b/chrome/browser/ui/android/website_settings_popup_android.cc
@@ -55,7 +55,7 @@
this,
Profile::FromBrowserContext(web_contents->GetBrowserContext()),
TabSpecificContentSettings::FromWebContents(web_contents),
- InfoBarService::FromWebContents(web_contents),
+ web_contents,
nav_entry->GetURL(),
nav_entry->GetSSL(),
content::CertStore::GetInstance()));
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h
index 1832187e..aa5446a 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h
@@ -8,6 +8,7 @@
#include "base/memory/scoped_ptr.h"
#import "chrome/browser/ui/cocoa/base_bubble_controller.h"
#include "chrome/browser/ui/website_settings/website_settings_ui.h"
+#include "content/public/browser/web_contents_observer.h"
class WebsiteSettingsUIBridge;
@@ -18,8 +19,8 @@
// This NSWindowController subclass manages the InfoBubbleWindow and view that
// are displayed when the user clicks the favicon or security lock icon.
//
-// TODO(palmer, sashab): Normalize all WebsiteSettings*, SiteSettings*,
-// PageInfo*, et c. to OriginInfo*.
+// TODO(palmer): Normalize all WebsiteSettings*, SiteSettings*, PageInfo*, et c.
+// to OriginInfo*.
@interface WebsiteSettingsBubbleController : BaseBubbleController {
@private
content::WebContents* webContents_;
@@ -99,9 +100,10 @@
// Provides a bridge between the WebSettingsUI C++ interface and the Cocoa
// implementation in WebsiteSettingsBubbleController.
-class WebsiteSettingsUIBridge : public WebsiteSettingsUI {
+class WebsiteSettingsUIBridge : public content::WebContentsObserver,
+ public WebsiteSettingsUI {
public:
- WebsiteSettingsUIBridge();
+ explicit WebsiteSettingsUIBridge(content::WebContents* web_contents);
~WebsiteSettingsUIBridge() override;
// Creates a |WebsiteSettingsBubbleController| and displays the UI. |parent|
@@ -118,6 +120,9 @@
void set_bubble_controller(
WebsiteSettingsBubbleController* bubble_controller);
+ // WebContentsObserver implementation.
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+
// WebsiteSettingsUI implementations.
void SetCookieInfo(const CookieInfoList& cookie_info_list) override;
void SetPermissionInfo(
@@ -126,6 +131,9 @@
void SetSelectedTab(TabId tab_id) override;
private:
+ // The WebContents the bubble UI is attached to.
+ content::WebContents* web_contents_;
+
// The Cocoa controller for the bubble UI.
WebsiteSettingsBubbleController* bubble_controller_;
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
index 4acd5db..15378f2244 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
@@ -1171,9 +1171,11 @@
@end
-WebsiteSettingsUIBridge::WebsiteSettingsUIBridge()
- : bubble_controller_(nil) {
-}
+WebsiteSettingsUIBridge::WebsiteSettingsUIBridge(
+ content::WebContents* web_contents)
+ : content::WebContentsObserver(web_contents),
+ web_contents_(web_contents),
+ bubble_controller_(nil) {}
WebsiteSettingsUIBridge::~WebsiteSettingsUIBridge() {
}
@@ -1198,7 +1200,7 @@
bool is_internal_page = InternalChromePage(url);
// Create the bridge. This will be owned by the bubble controller.
- WebsiteSettingsUIBridge* bridge = new WebsiteSettingsUIBridge();
+ WebsiteSettingsUIBridge* bridge = new WebsiteSettingsUIBridge(web_contents);
// Create the bubble controller. It will dealloc itself when it closes.
WebsiteSettingsBubbleController* bubble_controller =
@@ -1212,13 +1214,9 @@
// Initialize the presenter, which holds the model and controls the UI.
// This is also owned by the bubble controller.
WebsiteSettings* presenter = new WebsiteSettings(
- bridge,
- profile,
- TabSpecificContentSettings::FromWebContents(web_contents),
- InfoBarService::FromWebContents(web_contents),
- url,
- ssl,
- content::CertStore::GetInstance());
+ bridge, profile,
+ TabSpecificContentSettings::FromWebContents(web_contents), web_contents,
+ url, ssl, content::CertStore::GetInstance());
[bubble_controller setPresenter:presenter];
}
@@ -1230,6 +1228,13 @@
[bubble_controller_ setIdentityInfo:identity_info];
}
+void WebsiteSettingsUIBridge::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ if (render_frame_host == web_contents_->GetMainFrame()) {
+ [bubble_controller_ close];
+ }
+}
+
void WebsiteSettingsUIBridge::SetCookieInfo(
const CookieInfoList& cookie_info_list) {
[bubble_controller_ setCookieInfo:cookie_info_list];
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
index 769218e0..b254463 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
@@ -149,7 +149,7 @@
// Creates a new website settings bubble, with the given default width.
// If |default_width| is 0, the *default* default width will be used.
void CreateBubbleWithWidth(CGFloat default_width) {
- bridge_ = new WebsiteSettingsUIBridge();
+ bridge_ = new WebsiteSettingsUIBridge(nullptr);
// The controller cleans up after itself when the window closes.
controller_ = [WebsiteSettingsBubbleControllerForTesting alloc];
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
index 3e88743..f225daa 100644
--- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
+++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.cc
@@ -314,7 +314,8 @@
content::WebContents* web_contents,
const GURL& url,
const content::SSLStatus& ssl)
- : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT),
+ : content::WebContentsObserver(web_contents),
+ BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT),
web_contents_(web_contents),
header_(nullptr),
tabbed_pane_(nullptr),
@@ -380,10 +381,15 @@
views::BubbleDelegateView::CreateBubble(this);
presenter_.reset(new WebsiteSettings(
- this, profile,
- TabSpecificContentSettings::FromWebContents(web_contents),
- InfoBarService::FromWebContents(web_contents), url, ssl,
- content::CertStore::GetInstance()));
+ this, profile, TabSpecificContentSettings::FromWebContents(web_contents),
+ web_contents, url, ssl, content::CertStore::GetInstance()));
+}
+
+void WebsiteSettingsPopupView::RenderFrameDeleted(
+ content::RenderFrameHost* render_frame_host) {
+ if (render_frame_host == web_contents_->GetMainFrame()) {
+ GetWidget()->Close();
+ }
}
void WebsiteSettingsPopupView::OnPermissionChanged(
diff --git a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h
index a74f032..d527247 100644
--- a/chrome/browser/ui/views/website_settings/website_settings_popup_view.h
+++ b/chrome/browser/ui/views/website_settings/website_settings_popup_view.h
@@ -11,6 +11,7 @@
#include "base/strings/string16.h"
#include "chrome/browser/ui/views/website_settings/permission_selector_view_observer.h"
#include "chrome/browser/ui/website_settings/website_settings_ui.h"
+#include "content/public/browser/web_contents_observer.h"
#include "ui/views/bubble/bubble_delegate.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/link_listener.h"
@@ -33,13 +34,13 @@
}
// The views implementation of the website settings UI.
-class WebsiteSettingsPopupView
- : public PermissionSelectorViewObserver,
- public views::BubbleDelegateView,
- public views::ButtonListener,
- public views::LinkListener,
- public views::TabbedPaneListener,
- public WebsiteSettingsUI {
+class WebsiteSettingsPopupView : public content::WebContentsObserver,
+ public PermissionSelectorViewObserver,
+ public views::BubbleDelegateView,
+ public views::ButtonListener,
+ public views::LinkListener,
+ public views::TabbedPaneListener,
+ public WebsiteSettingsUI {
public:
~WebsiteSettingsPopupView() override;
@@ -61,6 +62,9 @@
const GURL& url,
const content::SSLStatus& ssl);
+ // WebContentsObserver implementation.
+ void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+
// PermissionSelectorViewObserver implementation.
void OnPermissionChanged(
const WebsiteSettingsUI::PermissionInfo& permission) override;
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc
index 9993b87..d18e1f7 100644
--- a/chrome/browser/ui/website_settings/website_settings.cc
+++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -23,6 +23,7 @@
#include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
#include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
#include "chrome/browser/ssl/chrome_ssl_host_state_delegate_factory.h"
@@ -147,14 +148,14 @@
WebsiteSettingsUI* ui,
Profile* profile,
TabSpecificContentSettings* tab_specific_content_settings,
- InfoBarService* infobar_service,
+ content::WebContents* web_contents,
const GURL& url,
const content::SSLStatus& ssl,
content::CertStore* cert_store)
: TabSpecificContentSettings::SiteDataObserver(
tab_specific_content_settings),
ui_(ui),
- infobar_service_(infobar_service),
+ web_contents_(web_contents),
show_info_bar_(false),
site_url_(url),
site_identity_status_(SITE_IDENTITY_STATUS_UNKNOWN),
@@ -322,8 +323,12 @@
}
void WebsiteSettings::OnUIClosing() {
- if (show_info_bar_)
- WebsiteSettingsInfoBarDelegate::Create(infobar_service_);
+ if (show_info_bar_ && web_contents_) {
+ InfoBarService* infobar_service =
+ InfoBarService::FromWebContents(web_contents_);
+ if (infobar_service)
+ WebsiteSettingsInfoBarDelegate::Create(infobar_service);
+ }
SSLCertificateDecisionsDidRevoke user_decision =
did_revoke_user_ssl_decisions_ ? USER_CERT_DECISIONS_REVOKED
diff --git a/chrome/browser/ui/website_settings/website_settings.h b/chrome/browser/ui/website_settings/website_settings.h
index 0df464ca..b0e26e5 100644
--- a/chrome/browser/ui/website_settings/website_settings.h
+++ b/chrome/browser/ui/website_settings/website_settings.h
@@ -15,10 +15,10 @@
namespace content {
class CertStore;
struct SSLStatus;
+class WebContents;
}
class ChromeSSLHostStateDelegate;
-class InfoBarService;
class HostContentSettingsMap;
class Profile;
class WebsiteSettingsUI;
@@ -92,7 +92,7 @@
WebsiteSettings(WebsiteSettingsUI* ui,
Profile* profile,
TabSpecificContentSettings* tab_specific_content_settings,
- InfoBarService* infobar_service,
+ content::WebContents* web_contents,
const GURL& url,
const content::SSLStatus& ssl,
content::CertStore* cert_store);
@@ -152,14 +152,14 @@
// in the |ui_|.
void PresentSiteIdentity();
- // The website settings UI displays information and controls for site
- // specific data (local stored objects like cookies), site specific
- // permissions (location, popup, plugin, etc. permissions) and site specific
+ // The website settings UI displays information and controls for site-
+ // specific data (local stored objects like cookies), site-specific
+ // permissions (location, pop-up, plugin, etc. permissions) and site-specific
// information (identity, connection status, etc.).
WebsiteSettingsUI* ui_;
- // The infobar service of the active tab.
- InfoBarService* infobar_service_;
+ // The WebContents of the active tab.
+ content::WebContents* web_contents_;
// The flag that controls whether an infobar is displayed after the website
// settings UI is closed or not.
diff --git a/chrome/browser/ui/website_settings/website_settings_ui.h b/chrome/browser/ui/website_settings/website_settings_ui.h
index 787aabd..547f3d0 100644
--- a/chrome/browser/ui/website_settings/website_settings_ui.h
+++ b/chrome/browser/ui/website_settings/website_settings_ui.h
@@ -151,7 +151,7 @@
// Sets cookie information.
virtual void SetCookieInfo(const CookieInfoList& cookie_info_list) = 0;
- // Sets permision information.
+ // Sets permission information.
virtual void SetPermissionInfo(
const PermissionInfoList& permission_info_list) = 0;
diff --git a/chrome/browser/ui/website_settings/website_settings_unittest.cc b/chrome/browser/ui/website_settings/website_settings_unittest.cc
index e7c8d531f..c3952c2e 100644
--- a/chrome/browser/ui/website_settings/website_settings_unittest.cc
+++ b/chrome/browser/ui/website_settings/website_settings_unittest.cc
@@ -133,7 +133,7 @@
if (!website_settings_.get()) {
website_settings_.reset(new WebsiteSettings(
mock_ui(), profile(), tab_specific_content_settings(),
- infobar_service(), url(), ssl(), cert_store()));
+ web_contents(), url(), ssl(), cert_store()));
}
return website_settings_.get();
}