Commit message: None
CVE: CVE-2012-5111
Vulnerability description: Google Chrome before 22.0.1229.92 does not monitor for crashes of Pepper plug-ins, which has unspecified impact and remote attack vectors.

Project: Chrome

PluginInfoMessageFilter::Context::Context()
    : render_process_id_(0),
      resource_context_(NULL),
      host_content_settings_map_(NULL) {
}

Project: Chrome

bool PluginInfoMessageFilter::Context::FindEnabledPlugin(
    int render_view_id,
    const GURL& url,
    const GURL& top_origin_url,
    const std::string& mime_type,
    ChromeViewHostMsg_GetPluginInfo_Status* status,
    WebPluginInfo* plugin,
    std::string* actual_mime_type) const {
  bool allow_wildcard = true;
  std::vector<WebPluginInfo> matching_plugins;
  std::vector<std::string> mime_types;
  PluginService::GetInstance()->GetPluginInfoArray(
      url, mime_type, allow_wildcard, &matching_plugins, &mime_types);
  content::PluginServiceFilter* filter =
      PluginService::GetInstance()->GetFilter();
  bool found = false;
  for (size_t i = 0; i < matching_plugins.size(); ++i) {
    bool enabled = !filter || filter->ShouldUsePlugin(render_process_id_,
                                                      render_view_id,
                                                      resource_context_,
                                                      url,
                                                      top_origin_url,
                                                      &matching_plugins[i]);
    if (!found || enabled) {
      *plugin = matching_plugins[i];
      *actual_mime_type = mime_types[i];
      if (enabled) {
        return true;
      }
      found = true;
    }
  }

  if (found)
    status->value = ChromeViewHostMsg_GetPluginInfo_Status::kDisabled;
  else
    status->value = ChromeViewHostMsg_GetPluginInfo_Status::kNotFound;
  return false;
}

Project: Chrome

void PluginInfoMessageFilter::Context::GetPluginContentSetting(
    const WebPluginInfo& plugin,
    const GURL& policy_url,
    const GURL& plugin_url,
    const std::string& resource,
    ContentSetting* setting,
    bool* uses_default_content_setting) const {
  bool is_nacl_plugin = (plugin.name == ASCIIToUTF16(
      chrome::ChromeContentClient::kNaClPluginName));

  scoped_ptr<base::Value> value;
  content_settings::SettingInfo info;
  bool uses_plugin_specific_setting = false;
  if (is_nacl_plugin) {
    value.reset(
        host_content_settings_map_->GetWebsiteSetting(
            policy_url, policy_url, CONTENT_SETTINGS_TYPE_JAVASCRIPT,
            std::string(), &info));
  } else {
    value.reset(
        host_content_settings_map_->GetWebsiteSetting(
            policy_url, plugin_url, CONTENT_SETTINGS_TYPE_PLUGINS, resource,
            &info));
    if (value.get()) {
      uses_plugin_specific_setting = true;
    } else {
      value.reset(host_content_settings_map_->GetWebsiteSetting(
          policy_url, plugin_url, CONTENT_SETTINGS_TYPE_PLUGINS, std::string(),
          &info));
    }
  }
  *setting = content_settings::ValueToContentSetting(value.get());
  *uses_default_content_setting =
      !uses_plugin_specific_setting &&
      info.primary_pattern == ContentSettingsPattern::Wildcard() &&
      info.secondary_pattern == ContentSettingsPattern::Wildcard();
}

Project: Chrome

void PluginInfoMessageFilter::GotPluginFinder(
    const GetPluginInfo_Params& params,
    IPC::Message* reply_msg,
    ChromeViewHostMsg_GetPluginInfo_Output output,
    PluginFinder* plugin_finder) {
  context_.DecidePluginStatus(params, output.plugin, plugin_finder,
                              &output.status, &output.group_identifier,
                              &output.group_name);
  ChromeViewHostMsg_GetPluginInfo::WriteReplyParams(reply_msg, output);
  Send(reply_msg);
}

Project: Chrome

void PluginInfoMessageFilter::OnDestruct() const {
  const_cast<PluginInfoMessageFilter*>(this)->
      weak_ptr_factory_.DetachFromThread();
  const_cast<PluginInfoMessageFilter*>(this)->
      weak_ptr_factory_.InvalidateWeakPtrs();

  content::BrowserThread::DeleteOnUIThread::Destruct(this);
}

Project: Chrome

void PluginInfoMessageFilter::OnGetPluginInfo(
    int render_view_id,
    const GURL& url,
    const GURL& top_origin_url,
    const std::string& mime_type,
    IPC::Message* reply_msg) {
  GetPluginInfo_Params params = {
    render_view_id,
    url,
    top_origin_url,
    mime_type
  };
  PluginService::GetInstance()->GetPlugins(
      base::Bind(&PluginInfoMessageFilter::PluginsLoaded,
                 weak_ptr_factory_.GetWeakPtr(),
                 params, reply_msg));
}

Project: Chrome

bool PluginInfoMessageFilter::OnMessageReceived(const IPC::Message& message,
                                                bool* message_was_ok) {
  IPC_BEGIN_MESSAGE_MAP_EX(PluginInfoMessageFilter, message, *message_was_ok)
    IPC_MESSAGE_HANDLER_DELAY_REPLY(ChromeViewHostMsg_GetPluginInfo,
                                    OnGetPluginInfo)
    IPC_MESSAGE_UNHANDLED(return false)
  IPC_END_MESSAGE_MAP()
  return true;
}

Project: Chrome

PluginInfoMessageFilter::PluginInfoMessageFilter(
    int render_process_id,
    Profile* profile)
    : context_(render_process_id, profile),
      weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
}

Project: Chrome

void PluginInfoMessageFilter::PluginsLoaded(
    const GetPluginInfo_Params& params,
    IPC::Message* reply_msg,
    const std::vector<WebPluginInfo>& plugins) {
  ChromeViewHostMsg_GetPluginInfo_Output output;
  if (!context_.FindEnabledPlugin(params.render_view_id, params.url,
                                  params.top_origin_url, params.mime_type,
                                  &output.status, &output.plugin,
                                  &output.actual_mime_type)) {
    ChromeViewHostMsg_GetPluginInfo::WriteReplyParams(reply_msg, output);
    Send(reply_msg);
    return;
  }

  PluginFinder::Get(base::Bind(&PluginInfoMessageFilter::GotPluginFinder, this,
                               params, reply_msg, output));
}

Project: Chrome

PluginInfoMessageFilter::Context::~Context() {
}

Project: Chrome

PluginInfoMessageFilter::~PluginInfoMessageFilter() {}

Project: Chrome

PpapiPluginProcessHost* PpapiPluginProcessHost::CreateBrokerHost(
    const content::PepperPluginInfo& info) {
  PpapiPluginProcessHost* plugin_host =
      new PpapiPluginProcessHost();
  if (plugin_host->Init(info))
    return plugin_host;

  NOTREACHED();  // Init is not expected to fail.
  return NULL;
}

Project: Chrome

PpapiPluginProcessHost* PpapiPluginProcessHost::CreatePluginHost(
    const content::PepperPluginInfo& info,
    const FilePath& profile_data_directory,
    net::HostResolver* host_resolver) {
  PpapiPluginProcessHost* plugin_host = new PpapiPluginProcessHost(
      info, profile_data_directory, host_resolver);
  if (plugin_host->Init(info))
    return plugin_host;

  NOTREACHED();  // Init is not expected to fail.
  return NULL;
}

Project: Chrome

void PpapiPluginProcessHost::DidCreateOutOfProcessInstance(
    int plugin_process_id,
    int32 pp_instance,
    int render_process_id,
    int render_view_id) {
  for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
    if (iter->process_.get() &&
        iter->process_->GetData().id == plugin_process_id) {
      iter->host_impl_->AddInstanceForView(pp_instance,
                                           render_process_id, render_view_id);
      return;
    }
  }
  DCHECK(plugin_process_id == 0)
      << "Renderer sent a bad plugin process host ID";
}

Project: Chrome

void PpapiPluginProcessHost::DidDeleteOutOfProcessInstance(
    int plugin_process_id,
    int32 pp_instance) {
  for (PpapiPluginProcessHostIterator iter; !iter.Done(); ++iter) {
    if (iter->process_.get() &&
        iter->process_->GetData().id == plugin_process_id) {
      iter->host_impl_->DeleteInstanceForView(pp_instance);
      return;
    }
  }
}

Project: Chrome

bool PpapiPluginProcessHost::Init(const content::PepperPluginInfo& info) {
  plugin_path_ = info.path;
  if (info.name.empty()) {
    process_->SetName(plugin_path_.BaseName().LossyDisplayName());
  } else {
    process_->SetName(UTF8ToUTF16(info.name));
  }

  std::string channel_id = process_->GetHost()->CreateChannel();
  if (channel_id.empty())
    return false;

  const CommandLine& browser_command_line = *CommandLine::ForCurrentProcess();
  CommandLine::StringType plugin_launcher =
      browser_command_line.GetSwitchValueNative(switches::kPpapiPluginLauncher);

#if defined(OS_LINUX)
  int flags = plugin_launcher.empty() ? ChildProcessHost::CHILD_ALLOW_SELF :
                                        ChildProcessHost::CHILD_NORMAL;
#else
  int flags = ChildProcessHost::CHILD_NORMAL;
#endif
  FilePath exe_path = ChildProcessHost::GetChildPath(flags);
  if (exe_path.empty())
    return false;

  CommandLine* cmd_line = new CommandLine(exe_path);
  cmd_line->AppendSwitchASCII(switches::kProcessType,
                              is_broker_ ? switches::kPpapiBrokerProcess
                                         : switches::kPpapiPluginProcess);
  cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);

  static const char* kCommonForwardSwitches[] = {
    switches::kVModule
  };
  cmd_line->CopySwitchesFrom(browser_command_line, kCommonForwardSwitches,
                             arraysize(kCommonForwardSwitches));

  if (!is_broker_) {
    static const char* kPluginForwardSwitches[] = {
      switches::kNoSandbox,
      switches::kDisableSeccompFilterSandbox,
      switches::kPpapiFlashArgs,
      switches::kPpapiStartupDialog
    };
    cmd_line->CopySwitchesFrom(browser_command_line, kPluginForwardSwitches,
                               arraysize(kPluginForwardSwitches));
  }

  std::string locale =
      content::GetContentClient()->browser()->GetApplicationLocale();
  if (!locale.empty()) {
    cmd_line->AppendSwitchASCII(switches::kLang, locale);
  }

  if (!plugin_launcher.empty())
    cmd_line->PrependWrapper(plugin_launcher);

#if defined(OS_POSIX)
  bool use_zygote = !is_broker_ && plugin_launcher.empty() && info.is_sandboxed;
  if (!info.is_sandboxed)
    cmd_line->AppendSwitchASCII(switches::kNoSandbox, "");
#endif  // OS_POSIX
  process_->Launch(
#if defined(OS_WIN)
      FilePath(),
#elif defined(OS_POSIX)
      use_zygote,
      base::EnvironmentVector(),
#endif
      cmd_line);
  return true;
}

Project: Chrome

void PpapiPluginProcessHost::OnChannelConnected(int32 peer_pid) {
  Send(new PpapiMsg_LoadPlugin(plugin_path_));

  for (size_t i = 0; i < pending_requests_.size(); i++)
    RequestPluginChannel(pending_requests_[i]);
  pending_requests_.clear();
}

Project: Chrome

void PpapiPluginProcessHost::OnChannelError() {
  DVLOG(1) << "PpapiPluginProcessHost" << (is_broker_ ? "[broker]" : "")
           << "::OnChannelError()";
  CancelRequests();
}

Project: Chrome

  virtual void OnConnectionTypeChanged(
      net::NetworkChangeNotifier::ConnectionType type) {
    process_host_->Send(new PpapiMsg_SetNetworkState(
        type != net::NetworkChangeNotifier::CONNECTION_NONE));
  }

Project: Chrome

 bool PpapiPluginProcessHost::OnMessageReceived(const IPC::Message& msg) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(PpapiPluginProcessHost, msg)
    IPC_MESSAGE_HANDLER(PpapiHostMsg_ChannelCreated,
                        OnRendererPluginChannelCreated)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  DCHECK(handled);
  return handled;
}

Project: Chrome

void PpapiPluginProcessHost::OnRendererPluginChannelCreated(
    const IPC::ChannelHandle& channel_handle) {
  if (sent_requests_.empty())
    return;

  Client* client = sent_requests_.front();
  sent_requests_.pop();

  client->OnPpapiChannelOpened(channel_handle, process_->GetData().id);
}

Project: Chrome

void PpapiPluginProcessHost::OpenChannelToPlugin(Client* client) {
  if (process_->GetHost()->IsChannelOpening()) {
    pending_requests_.push_back(client);
    return;
  }

  RequestPluginChannel(client);
}

Project: Chrome

  explicit PluginNetworkObserver(PpapiPluginProcessHost* process_host)
      : process_host_(process_host) {
    net::NetworkChangeNotifier::AddIPAddressObserver(this);
    net::NetworkChangeNotifier::AddConnectionTypeObserver(this);
  }

Project: Chrome

PpapiPluginProcessHost::PpapiPluginProcessHost()
    : is_broker_(true) {
  process_.reset(new BrowserChildProcessHostImpl(
      content::PROCESS_TYPE_PPAPI_BROKER, this));

  ppapi::PpapiPermissions permissions;  // No permissions.
  host_impl_ = new content::BrowserPpapiHostImpl(this, permissions);
}

Project: Chrome

bool PpapiPluginProcessHost::Send(IPC::Message* message) {
  return process_->Send(message);
}

Project: Chrome

  ~PluginNetworkObserver() {
    net::NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
    net::NetworkChangeNotifier::RemoveIPAddressObserver(this);
  }

Project: Chrome

PpapiPluginProcessHost::~PpapiPluginProcessHost() {
  DVLOG(1) << "PpapiPluginProcessHost" << (is_broker_ ? "[broker]" : "")
           << "~PpapiPluginProcessHost()";
  CancelRequests();
}