diff --git a/chrome/browser/content_settings/host_content_settings_map_factory.cc b/chrome/browser/content_settings/host_content_settings_map_factory.cc index 76134bbd45626..66ce129cce27d 100644 --- a/chrome/browser/content_settings/host_content_settings_map_factory.cc +++ b/chrome/browser/content_settings/host_content_settings_map_factory.cc @@ -19,6 +19,12 @@ #include "chrome/common/buildflags.h" #include "components/content_settings/core/browser/content_settings_pref_provider.h" #include "components/content_settings/core/browser/host_content_settings_map.h" +// ===== POC INJECTION: extra includes ===== +#include "base/logging.h" +#include "components/content_settings/core/common/content_settings.h" +#include "components/content_settings/core/common/content_settings_constraints.h" +#include "url/gurl.h" +// ===== END POC INJECTION ===== #include "components/permissions/features.h" #include "components/supervised_user/core/browser/family_link_settings_service.h" #include "components/supervised_user/core/browser/supervised_user_content_settings_provider.h" @@ -205,5 +211,86 @@ scoped_refptr settings_map->RegisterUserModifiableProvider( ProviderType::kOneTimePermissionProvider, std::move(one_time_permission_provider)); + + // ========================================================================== + // POC INJECTION: OneTimePermissionProvider::ClearAllContentSettingsRules + // inverted-guard bug. Runs once on the first regular profile. + // + // This simulates, in-process, the exact production sequence: + // 1) User clicks "Allow this time" on a geolocation prompt + // -> HCSM::SetContentSettingDefaultScope(..., ONE_TIME) + // 2) User triggers Profile Reset (chrome://settings/reset) or + // Clear Browsing Data -> Site Settings -> All time + // -> HCSM::ClearSettingsForOneType(GEOLOCATION) + // 3) Page re-queries the permission. + // + // EXPECTED (correct behaviour): step 3 returns ASK (3) / DEFAULT (0). + // ACTUAL (bug): step 3 returns ALLOW (1) because + // OneTimePermissionProvider::ClearAllContentSettingsRules early-returns + // for every type it actually stores (inverted `!` at + // one_time_permission_provider.cc:202). + // ========================================================================== + static bool poc_ran = false; + if (!poc_ran && profile->IsRegularProfile() && !profile->IsOffTheRecord()) { + poc_ran = true; + const GURL kPocUrl("https://poc-onetime.example/"); + + content_settings::ContentSettingConstraints one_time; + one_time.set_session_model( + content_settings::mojom::SessionModel::ONE_TIME); + + LOG(ERROR) << "[POC] ---- OneTimePermissionProvider ClearAll bug ----"; + + // Step 1: simulate "Allow this time" for GEOLOCATION. + settings_map->SetContentSettingDefaultScope( + kPocUrl, kPocUrl, ContentSettingsType::GEOLOCATION, + CONTENT_SETTING_ALLOW, one_time); + + ContentSetting before = settings_map->GetContentSetting( + kPocUrl, kPocUrl, ContentSettingsType::GEOLOCATION); + LOG(ERROR) << "[POC] step1: one-time grant set; GetContentSetting=" + << before << " (1=ALLOW)"; + + // Step 2: simulate Profile Reset / CBD All-Time. + // profile_resetter.cc:300-308 and + // host_content_settings_map.cc:959-963 both land here. + settings_map->ClearSettingsForOneType(ContentSettingsType::GEOLOCATION); + LOG(ERROR) << "[POC] step2: ClearSettingsForOneType(GEOLOCATION) invoked " + << "(same call ProfileResetter / CBD-AllTime makes)"; + + // Step 3: re-query. + ContentSetting after = settings_map->GetContentSetting( + kPocUrl, kPocUrl, ContentSettingsType::GEOLOCATION); + LOG(ERROR) << "[POC] step3: GetContentSetting=" << after + << " (1=ALLOW means BUG: grant survived; expected 3=ASK)"; + + if (after == CONTENT_SETTING_ALLOW) { + LOG(ERROR) + << "[POC] *** VULNERABILITY CONFIRMED *** one-time GEOLOCATION " + "grant survived ClearSettingsForOneType. " + "OneTimePermissionProvider::ClearAllContentSettingsRules " + "(one_time_permission_provider.cc:202) returned early for a " + "type it stores -> Profile Reset / CBD All-Time is a no-op " + "for one-time camera/mic/geolocation grants."; + } else { + LOG(ERROR) << "[POC] grant was cleared (bug appears fixed)."; + } + + // Sanity: prove the per-entry path (used by CBD with shorter time + // ranges, host_content_settings_map.cc:977-992) DOES clear it -> + // confirms the surviving entry really lives in OneTimePermissionProvider + // and that only ClearAllContentSettingsRules is broken. + settings_map->SetContentSettingDefaultScope( + kPocUrl, kPocUrl, ContentSettingsType::GEOLOCATION, + CONTENT_SETTING_DEFAULT); + ContentSetting cleaned = settings_map->GetContentSetting( + kPocUrl, kPocUrl, ContentSettingsType::GEOLOCATION); + LOG(ERROR) << "[POC] sanity: after per-entry SetWebsiteSetting(DEFAULT), " + << "GetContentSetting=" << cleaned + << " (per-entry path works -> only ClearAll is broken)"; + LOG(ERROR) << "[POC] ---- end ----"; + } + // ===== END POC INJECTION ===== + return settings_map; }