Commit message: None
CVE: CVE-2011-3234
CWE: CWE-119
Vulnerability description: Google Chrome before 14.0.835.163 does not properly handle boxes, which allows remote attackers to cause a denial of service (out-of-bounds read) via unspecified vectors.

Project: Chrome

void ExtensionPrefs::AddGrantedPermissions(
    const std::string& extension_id,
    const bool full_access,
    const std::set<std::string>& api_permissions,
    const URLPatternSet& host_extent) {
  CHECK(Extension::IdIsValid(extension_id));

  UpdateExtensionPref(extension_id, kPrefGrantedPermissionsAll,
                      Value::CreateBooleanValue(full_access));

  if (!api_permissions.empty()) {
    AddToExtensionPrefStringSet(
        extension_id, kPrefGrantedPermissionsAPI, api_permissions);
  }

  if (!host_extent.is_empty()) {
    std::set<std::string> host_permissions;
    ExtentToStringSet(host_extent, &host_permissions);

    AddToExtensionPrefStringSet(
        extension_id, kPrefGrantedPermissionsHost, host_permissions);
  }
}

Project: Chrome

static void CleanupBadExtensionKeys(const FilePath& root_dir,
                                    PrefService* prefs) {
  const DictionaryValue* dictionary =
      prefs->GetDictionary(ExtensionPrefs::kExtensionsPref);
  std::map<std::string, std::string> remapped_keys;
  for (DictionaryValue::key_iterator i = dictionary->begin_keys();
       i != dictionary->end_keys(); ++i) {
    DictionaryValue* ext;
    if (!dictionary->GetDictionaryWithoutPathExpansion(*i, &ext))
      continue;

    int location;
    FilePath::StringType path_str;
    if (!ext->GetInteger(kPrefLocation, &location) ||
        !ext->GetString(kPrefPath, &path_str)) {
      continue;
    }

    if (location != Extension::LOAD)
      continue;

    const std::string& prefs_id(*i);
    FilePath path(path_str);
    if (!path.IsAbsolute()) {
      path = root_dir.Append(path);
    }
    std::string computed_id = Extension::GenerateIdForPath(path);

    if (prefs_id != computed_id) {
      remapped_keys[prefs_id] = computed_id;
    }
  }

  if (!remapped_keys.empty()) {
    DictionaryPrefUpdate update(prefs, ExtensionPrefs::kExtensionsPref);
    DictionaryValue* update_dictionary = update.Get();
    for (std::map<std::string, std::string>::const_iterator i =
            remapped_keys.begin();
        i != remapped_keys.end();
        ++i) {
      if (update_dictionary->HasKey(i->second)) {
        CHECK(update_dictionary->RemoveWithoutPathExpansion(i->first, NULL));
        continue;
      }
      Value* extension_prefs = NULL;
      CHECK(update_dictionary->RemoveWithoutPathExpansion(
          i->first, &extension_prefs));
      update_dictionary->SetWithoutPathExpansion(i->second, extension_prefs);
    }

    prefs->ScheduleSavePersistentPrefs();
  }
}

Project: Chrome

void ExtensionPrefs::DeleteExtensionPrefs(const std::string& extension_id) {
  DictionaryPrefUpdate update(prefs_, kExtensionsPref);
  DictionaryValue* dict = update.Get();
  if (dict->HasKey(extension_id)) {
    dict->Remove(extension_id, NULL);
    SavePrefs();
  }
  extension_pref_value_map_->UnregisterExtension(extension_id);
  content_settings_store_->UnregisterExtension(extension_id);
}

Project: Chrome

ExtensionPrefs::ExtensionPrefs(
    PrefService* prefs,
    const FilePath& root_dir,
    ExtensionPrefValueMap* extension_pref_value_map)
    : prefs_(prefs),
      install_directory_(root_dir),
      extension_pref_value_map_(extension_pref_value_map),
      content_settings_store_(new ExtensionContentSettingsStore()) {
  CleanupBadExtensionKeys(root_dir, prefs_);

  MakePathsRelative();

  InitPrefStore();

  content_settings_store_->AddObserver(this);
}

Project: Chrome

static void ExtentToStringSet(const URLPatternSet& host_extent,
                              std::set<std::string>* result) {
  URLPatternList patterns = host_extent.patterns();
  URLPatternList::const_iterator i;

  for (i = patterns.begin(); i != patterns.end(); ++i)
    result->insert(i->GetAsString());
}

Project: Chrome

int ExtensionPrefs::GetAppLaunchIndex(const std::string& extension_id) {
  int value;
  if (ReadExtensionPrefInteger(extension_id, kPrefAppLaunchIndex, &value))
    return value;

  return -1;
}

Project: Chrome

Extension::State ExtensionPrefs::GetExtensionState(
    const std::string& extension_id) const {
  const DictionaryValue* extension = GetExtensionPref(extension_id);

  if (!extension)
    return Extension::ENABLED;

  int state = -1;
  if (!extension->GetInteger(kPrefState, &state) ||
      state < 0 || state >= Extension::NUM_STATES) {
    LOG(ERROR) << "Bad or missing pref 'state' for extension '"
               << extension_id << "'";
    return Extension::ENABLED;
  }
  return static_cast<Extension::State>(state);
}

Project: Chrome

bool ExtensionPrefs::GetGrantedPermissions(
    const std::string& extension_id,
    bool* full_access,
    std::set<std::string>* api_permissions,
    URLPatternSet* host_extent) {
  CHECK(Extension::IdIsValid(extension_id));

  const DictionaryValue* ext = GetExtensionPref(extension_id);
  if (!ext || !ext->GetBoolean(kPrefGrantedPermissionsAll, full_access))
    return false;

  ReadExtensionPrefStringSet(
      extension_id, kPrefGrantedPermissionsAPI, api_permissions);

  std::set<std::string> host_permissions;
  ReadExtensionPrefStringSet(
      extension_id, kPrefGrantedPermissionsHost, &host_permissions);
  bool allow_file_access = AllowFileAccess(extension_id);

  for (std::set<std::string>::iterator i = host_permissions.begin();
       i != host_permissions.end(); ++i) {
    URLPattern pattern(
        Extension::kValidHostPermissionSchemes |
        UserScript::kValidUserScriptSchemes);

    if (URLPattern::PARSE_SUCCESS != pattern.Parse(
            *i, URLPattern::PARSE_LENIENT)) {
      NOTREACHED();  // Corrupt prefs?  Hand editing?
    } else {
      if (!allow_file_access && pattern.MatchesScheme(chrome::kFileScheme)) {
        pattern.set_valid_schemes(
            pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
      }
      host_extent->AddPattern(pattern);
    }
  }

  return true;
}

Project: Chrome

extension_misc::LaunchContainer ExtensionPrefs::GetLaunchContainer(
    const Extension* extension,
    ExtensionPrefs::LaunchType default_pref_value) {
  extension_misc::LaunchContainer manifest_launch_container =
      extension->launch_container();

  const extension_misc::LaunchContainer kInvalidLaunchContainer =
      static_cast<extension_misc::LaunchContainer>(-1);

  extension_misc::LaunchContainer result = kInvalidLaunchContainer;

  if (manifest_launch_container == extension_misc::LAUNCH_PANEL) {
    result = extension_misc::LAUNCH_PANEL;

  } else if (manifest_launch_container == extension_misc::LAUNCH_TAB) {
    ExtensionPrefs::LaunchType prefs_launch_type =
        GetLaunchType(extension->id(), default_pref_value);

    if (prefs_launch_type == ExtensionPrefs::LAUNCH_WINDOW) {
      result = extension_misc::LAUNCH_WINDOW;

    } else {
      result = extension_misc::LAUNCH_TAB;
    }
  } else {
    NOTREACHED() << manifest_launch_container;
  }

  if (result == kInvalidLaunchContainer) {
    DLOG(FATAL) << "Failed to set a launch container.";
    result = extension_misc::LAUNCH_TAB;
  }

  return result;
}

Project: Chrome

int ExtensionPrefs::GetNextAppLaunchIndex() {
  const DictionaryValue* extensions = prefs_->GetDictionary(kExtensionsPref);
  if (!extensions)
    return 0;

  int max_value = -1;
  for (DictionaryValue::key_iterator extension_id = extensions->begin_keys();
       extension_id != extensions->end_keys(); ++extension_id) {
    int value = GetAppLaunchIndex(*extension_id);
    if (value > max_value)
      max_value = value;
  }
  return max_value + 1;
}

Project: Chrome

int ExtensionPrefs::GetPageIndex(const std::string& extension_id) {
  int value = -1;
  ReadExtensionPrefInteger(extension_id, kPrefPageIndex, &value);
  return value;
}

Project: Chrome

void ExtensionPrefs::InitPrefStore() {
  ExtensionIdSet extension_ids;
  GetExtensions(&extension_ids);
  for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
       ext_id != extension_ids.end(); ++ext_id) {
    ScopedExtensionPrefUpdate update(prefs_, *ext_id);
    update.Get();
  }

  FixMissingPrefs(extension_ids);
  for (ExtensionIdSet::iterator ext_id = extension_ids.begin();
       ext_id != extension_ids.end(); ++ext_id) {
    extension_pref_value_map_->RegisterExtension(
        *ext_id,
        GetInstallTime(*ext_id),
        GetExtensionState(*ext_id) == Extension::ENABLED);
    content_settings_store_->RegisterExtension(
        *ext_id,
        GetInstallTime(*ext_id),
        GetExtensionState(*ext_id) == Extension::ENABLED);

    const DictionaryValue* prefs = GetExtensionControlledPrefs(*ext_id, false);
    for (DictionaryValue::key_iterator i = prefs->begin_keys();
         i != prefs->end_keys(); ++i) {
      Value* value;
      if (!prefs->GetWithoutPathExpansion(*i, &value))
        continue;
      extension_pref_value_map_->SetExtensionPref(
          *ext_id, *i, kExtensionPrefsScopeRegular, value->DeepCopy());
    }

    prefs = GetExtensionControlledPrefs(*ext_id, true);
    for (DictionaryValue::key_iterator i = prefs->begin_keys();
         i != prefs->end_keys(); ++i) {
      Value* value;
      if (!prefs->GetWithoutPathExpansion(*i, &value))
        continue;
      extension_pref_value_map_->SetExtensionPref(
          *ext_id, *i, kExtensionPrefsScopeIncognitoPersistent,
          value->DeepCopy());
    }

    const DictionaryValue* extension_prefs = GetExtensionPref(*ext_id);
    DCHECK(extension_prefs);
    ListValue* content_settings = NULL;
    if (extension_prefs->GetList(kPrefContentSettings,
                                 &content_settings)) {
      content_settings_store_->SetExtensionContentSettingsFromList(
          *ext_id, content_settings,
          kExtensionPrefsScopeRegular);
    }
    if (extension_prefs->GetList(kPrefIncognitoContentSettings,
                                 &content_settings)) {
      content_settings_store_->SetExtensionContentSettingsFromList(
          *ext_id, content_settings,
          kExtensionPrefsScopeIncognitoPersistent);
    }
  }

  extension_pref_value_map_->NotifyInitializationCompleted();
}

Project: Chrome

bool ExtensionPrefs::IsExtensionAllowedByPolicy(
    const std::string& extension_id) {
  std::string string_value;

  const ListValue* blacklist =
      prefs_->GetList(prefs::kExtensionInstallDenyList);
  if (!blacklist || blacklist->empty())
    return true;

  const ListValue* whitelist =
      prefs_->GetList(prefs::kExtensionInstallAllowList);
  if (whitelist) {
    for (ListValue::const_iterator it = whitelist->begin();
         it != whitelist->end(); ++it) {
      if (!(*it)->GetAsString(&string_value))
        LOG(WARNING) << "Failed to read whitelist string.";
      else if (string_value == extension_id)
        return true;
    }
  }

  if (blacklist) {
    for (ListValue::const_iterator it = blacklist->begin();
         it != blacklist->end(); ++it) {
      if (!(*it)->GetAsString(&string_value)) {
        LOG(WARNING) << "Failed to read blacklist string.";
      } else {
        if (string_value == "*")
          return false;  // Only whitelisted extensions are allowed.
        if (string_value == extension_id)
          return false;
      }
    }
  }

  return true;
}

Project: Chrome

bool ExtensionPrefs::IsExternalExtensionUninstalled(
    const std::string& id) const {
  const DictionaryValue* extension = GetExtensionPref(id);
  if (!extension)
    return false;
  int state = 0;
  return extension->GetInteger(kPrefState, &state) &&
         state == static_cast<int>(Extension::EXTERNAL_EXTENSION_UNINSTALLED);
}

Project: Chrome

void ExtensionPrefs::MakePathsAbsolute(DictionaryValue* dict) {
  if (!dict || dict->empty())
    return;

  for (DictionaryValue::key_iterator i = dict->begin_keys();
       i != dict->end_keys(); ++i) {
    DictionaryValue* extension_dict = NULL;
    if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict)) {
      NOTREACHED();
      continue;
    }

    int location_value;
    if (extension_dict->GetInteger(kPrefLocation, &location_value) &&
        location_value == Extension::LOAD) {
      continue;
    }

    FilePath::StringType path_string;
    if (!extension_dict->GetString(kPrefPath, &path_string))
      continue;

    DCHECK(!FilePath(path_string).IsAbsolute());
    extension_dict->SetString(
        kPrefPath, install_directory_.Append(path_string).value());
  }
}

Project: Chrome

void ExtensionPrefs::MakePathsRelative() {
  const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref);
  if (!dict || dict->empty())
    return;

  std::set<std::string> absolute_keys;
  for (DictionaryValue::key_iterator i = dict->begin_keys();
       i != dict->end_keys(); ++i) {
    DictionaryValue* extension_dict = NULL;
    if (!dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict))
      continue;
    int location_value;
    if (extension_dict->GetInteger(kPrefLocation, &location_value) &&
        location_value == Extension::LOAD) {
      continue;
    }
    FilePath::StringType path_string;
    if (!extension_dict->GetString(kPrefPath, &path_string))
      continue;
    FilePath path(path_string);
    if (path.IsAbsolute())
      absolute_keys.insert(*i);
  }
  if (absolute_keys.empty())
    return;

  DictionaryPrefUpdate update(prefs_, kExtensionsPref);
  const DictionaryValue* update_dict = update.Get();
  for (std::set<std::string>::iterator i = absolute_keys.begin();
       i != absolute_keys.end(); ++i) {
    DictionaryValue* extension_dict = NULL;
    update_dict->GetDictionaryWithoutPathExpansion(*i, &extension_dict);
    FilePath::StringType path_string;
    extension_dict->GetString(kPrefPath, &path_string);
    FilePath path(path_string);
    extension_dict->SetString(kPrefPath,
        MakePathRelative(install_directory_, path));
  }
  SavePrefs();
}

Project: Chrome

void ExtensionPrefs::OnExtensionInstalled(
    const Extension* extension, Extension::State initial_state) {
  const std::string& id = extension->id();
  CHECK(Extension::IdIsValid(id));
  ScopedExtensionPrefUpdate update(prefs_, id);
  DictionaryValue* extension_dict = update.Get();
  const base::Time install_time = GetCurrentTime();
  extension_dict->Set(kPrefState, Value::CreateIntegerValue(initial_state));
  extension_dict->Set(kPrefLocation,
                      Value::CreateIntegerValue(extension->location()));
  extension_dict->Set(kPrefInstallTime,
                      Value::CreateStringValue(
                          base::Int64ToString(install_time.ToInternalValue())));
  extension_dict->Set(kPrefPreferences, new DictionaryValue());
  extension_dict->Set(kPrefIncognitoPreferences, new DictionaryValue());
  extension_dict->Set(kPrefContentSettings, new ListValue());
  extension_dict->Set(kPrefIncognitoContentSettings, new ListValue());

  FilePath::StringType path = MakePathRelative(install_directory_,
      extension->path());
  extension_dict->Set(kPrefPath, Value::CreateStringValue(path));
  if (extension->location() != Extension::LOAD) {
    extension_dict->Set(kPrefManifest,
                        extension->manifest_value()->DeepCopy());
  }
  extension_dict->Set(kPrefAppLaunchIndex,
                      Value::CreateIntegerValue(GetNextAppLaunchIndex()));
  extension_pref_value_map_->RegisterExtension(
      id, install_time, initial_state == Extension::ENABLED);
  content_settings_store_->RegisterExtension(
      id, install_time, initial_state == Extension::ENABLED);
}

Project: Chrome

bool ExtensionPrefs::ReadExtensionPrefBoolean(
    const std::string& extension_id, const std::string& pref_key) {
  const DictionaryValue* ext = GetExtensionPref(extension_id);
  if (!ext) {
    return false;
  }
  return ReadBooleanFromPref(ext, pref_key);
}

Project: Chrome

bool ExtensionPrefs::ReadExtensionPrefList(
    const std::string& extension_id, const std::string& pref_key,
    const ListValue** out_value) {
  const DictionaryValue* ext = GetExtensionPref(extension_id);
  ListValue* out = NULL;
  if (!ext || !ext->GetList(pref_key, &out))
    return false;
  *out_value = out;

  return out_value != NULL;
}

Project: Chrome

bool ExtensionPrefs::ReadExtensionPrefStringSet(
    const std::string& extension_id,
    const std::string& pref_key,
    std::set<std::string>* result) {
  const ListValue* value = NULL;
  if (!ReadExtensionPrefList(extension_id, pref_key, &value))
    return false;

  result->clear();

  for (size_t i = 0; i < value->GetSize(); ++i) {
    std::string item;
    if (!value->GetString(i, &item))
      return false;
    result->insert(item);
  }

  return true;
}

Project: Chrome

void ExtensionPrefs::SetAppLaunchIndex(const std::string& extension_id,
                                       int index) {
  DCHECK_GE(index, 0);
  UpdateExtensionPref(extension_id, kPrefAppLaunchIndex,
                      Value::CreateIntegerValue(index));
}

Project: Chrome

void ExtensionPrefs::SetAppLauncherOrder(
    const std::vector<std::string>& extension_ids) {
  for (size_t i = 0; i < extension_ids.size(); ++i)
    SetAppLaunchIndex(extension_ids.at(i), i);

  NotificationService::current()->Notify(
      NotificationType::EXTENSION_LAUNCHER_REORDERED,
      Source<ExtensionPrefs>(this),
      NotificationService::NoDetails());
}

Project: Chrome

void ExtensionPrefs::SetBrowserActionVisibility(const Extension* extension,
                                                bool visible) {
  if (GetBrowserActionVisibility(extension) == visible)
    return;

  UpdateExtensionPref(extension->id(), kBrowserActionVisible,
                      Value::CreateBooleanValue(visible));
  NotificationService::current()->Notify(
      NotificationType::EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
      Source<ExtensionPrefs>(this),
      Details<const Extension>(extension));
}

Project: Chrome

void ExtensionPrefs::SetPageIndex(const std::string& extension_id, int index) {
  CHECK_GE(index, 0);
  UpdateExtensionPref(extension_id, kPrefPageIndex,
                      Value::CreateIntegerValue(index));
}

Project: Chrome

void ExtensionPrefs::UpdateExtensionPref(const std::string& extension_id,
                                         const std::string& key,
                                         Value* data_value) {
  if (!Extension::IdIsValid(extension_id)) {
    NOTREACHED() << "Invalid extension_id " << extension_id;
    return;
  }
  ScopedExtensionPrefUpdate update(prefs_, extension_id);
  update->Set(key, data_value);
}

Project: Chrome

void ExtensionPrefs::UpdateManifest(const Extension* extension) {
  if (extension->location() != Extension::LOAD) {
    const DictionaryValue* extension_dict = GetExtensionPref(extension->id());
    if (!extension_dict)
      return;
    DictionaryValue* old_manifest = NULL;
    bool update_required =
        !extension_dict->GetDictionary(kPrefManifest, &old_manifest) ||
        !extension->manifest_value()->Equals(old_manifest);
    if (update_required) {
      UpdateExtensionPref(extension->id(), kPrefManifest,
                          extension->manifest_value()->DeepCopy());
    }
  }
}