Commit message: None
CVE: CVE-2018-6171
CWE: CWE-416
Vulnerability description: Use after free in Bluetooth in Google Chrome prior to 68.0.3440.75 allowed an attacker who convinced a user to install a malicious extension to obtain potentially sensitive information from process memory via a crafted Chrome Extension.

Project: Chrome

int BluetoothSocketAsyncApiFunction::AddSocket(BluetoothApiSocket* socket) {
  return manager_->Add(socket);
}

Project: Chrome

    BluetoothSocketAbstractConnectFunction() {}

Project: Chrome

BluetoothSocketAsyncApiFunction::BluetoothSocketAsyncApiFunction() {}

Project: Chrome

BluetoothSocketCloseFunction::BluetoothSocketCloseFunction() {}

Project: Chrome

BluetoothSocketConnectFunction::BluetoothSocketConnectFunction() {}

Project: Chrome

BluetoothSocketCreateFunction::BluetoothSocketCreateFunction() {}

Project: Chrome

BluetoothSocketDisconnectFunction::BluetoothSocketDisconnectFunction() {}

Project: Chrome

BluetoothSocketGetInfoFunction::BluetoothSocketGetInfoFunction() {}

Project: Chrome

BluetoothSocketListenFunction::BluetoothSocketListenFunction() {}

Project: Chrome

    BluetoothSocketListenUsingL2capFunction() {}

Project: Chrome

    BluetoothSocketListenUsingRfcommFunction() {}

Project: Chrome

BluetoothSocketSendFunction::BluetoothSocketSendFunction()
    : io_buffer_size_(0) {}

Project: Chrome

BluetoothSocketSetPausedFunction::BluetoothSocketSetPausedFunction() {}

Project: Chrome

BluetoothSocketUpdateFunction::BluetoothSocketUpdateFunction() {}

Project: Chrome

void BluetoothSocketConnectFunction::ConnectToService(
    device::BluetoothDevice* device,
    const device::BluetoothUUID& uuid) {
  device->ConnectToService(
      uuid,
      base::Bind(&BluetoothSocketConnectFunction::OnConnect, this),
      base::Bind(&BluetoothSocketConnectFunction::OnConnectError, this));
}

Project: Chrome

bool BluetoothSocketListenUsingRfcommFunction::CreateParams() {
  params_ = bluetooth_socket::ListenUsingRfcomm::Params::Create(*args_);
  return params_ != nullptr;
}

Project: Chrome

BluetoothSocketListenUsingRfcommFunction::CreateResults() {
  return bluetooth_socket::ListenUsingRfcomm::Results::Create();
}

Project: Chrome

BluetoothSocketListenUsingL2capFunction::CreateResults() {
  return bluetooth_socket::ListenUsingL2cap::Results::Create();
}

Project: Chrome

void BluetoothSocketListenUsingRfcommFunction::CreateService(
    scoped_refptr<device::BluetoothAdapter> adapter,
    const device::BluetoothUUID& uuid,
    std::unique_ptr<std::string> name,
    const device::BluetoothAdapter::CreateServiceCallback& callback,
    const device::BluetoothAdapter::CreateServiceErrorCallback&
        error_callback) {
  device::BluetoothAdapter::ServiceOptions service_options;
  service_options.name = std::move(name);

  ListenOptions* options = params_->options.get();
  if (options) {
    if (options->channel.get())
      service_options.channel.reset(new int(*(options->channel)));
  }

  adapter->CreateRfcommService(uuid, service_options, callback, error_callback);
}

Project: Chrome

SocketInfo CreateSocketInfo(int socket_id, BluetoothApiSocket* socket) {
  DCHECK_CURRENTLY_ON(BluetoothApiSocket::kThreadId);
  SocketInfo socket_info;
  socket_info.socket_id = socket_id;
  if (socket->name()) {
    socket_info.name.reset(new std::string(*socket->name()));
  }
  socket_info.persistent = socket->persistent();
  if (socket->buffer_size() > 0) {
    socket_info.buffer_size.reset(new int(socket->buffer_size()));
  }
  socket_info.paused = socket->paused();
  socket_info.connected = socket->IsConnected();

  if (socket->IsConnected())
    socket_info.address.reset(new std::string(socket->device_address()));
  socket_info.uuid.reset(new std::string(socket->uuid().canonical_value()));

  return socket_info;
}

Project: Chrome

BluetoothApiSocket* BluetoothSocketAsyncApiFunction::GetSocket(
    int api_resource_id) {
  return manager_->Get(extension_id(), api_resource_id);
}

Project: Chrome

base::hash_set<int>* BluetoothSocketAsyncApiFunction::GetSocketIds() {
  return manager_->GetResourceIds(extension_id());
}

Project: Chrome

bool IsValidPsm(int psm) {
  if (psm <= 0)
    return false;

  std::vector<int16_t> octets;
  while (psm > 0) {
     octets.push_back(psm & 0xFF);
     psm = psm >> 8;
  }

  if (octets.size() < 2U)
    return false;

  if ((octets.front() & 0x01) != 1)
    return false;

  if ((octets.back() & 0x01) != 0)
    return false;

  return true;
}

Project: Chrome

void BluetoothSocketAbstractConnectFunction::OnConnect(
    scoped_refptr<device::BluetoothSocket> socket) {
  DCHECK_CURRENTLY_ON(work_thread_id());

  BluetoothApiSocket* api_socket = GetSocket(params_->socket_id);
  if (!api_socket) {
    Respond(Error(kSocketNotFoundError));
    return;
  }

  api_socket->AdoptConnectedSocket(socket,
                                   params_->address,
                                   device::BluetoothUUID(params_->uuid));
  socket_event_dispatcher_->OnSocketConnect(extension_id(),
                                            params_->socket_id);

  Respond(ArgumentList(bluetooth_socket::Connect::Results::Create()));
}

Project: Chrome

void BluetoothSocketAbstractConnectFunction::OnConnectError(
    const std::string& message) {
  DCHECK_CURRENTLY_ON(work_thread_id());
  Respond(Error(message));
}

Project: Chrome

void BluetoothSocketListenFunction::OnCreateService(
    scoped_refptr<device::BluetoothSocket> socket) {
  DCHECK_CURRENTLY_ON(work_thread_id());

  BluetoothApiSocket* api_socket = GetSocket(socket_id());
  if (!api_socket) {
    Respond(Error(kSocketNotFoundError));
    return;
  }

  api_socket->AdoptListeningSocket(socket,
                                   device::BluetoothUUID(uuid()));
  socket_event_dispatcher_->OnSocketListen(extension_id(), socket_id());
  Respond(ArgumentList(CreateResults()));
}

Project: Chrome

void BluetoothSocketListenFunction::OnCreateServiceError(
    const std::string& message) {
  DCHECK_CURRENTLY_ON(work_thread_id());
  Respond(Error(message));
}

Project: Chrome

void BluetoothSocketSendFunction::OnError(
    BluetoothApiSocket::ErrorReason reason,
    const std::string& message) {
  DCHECK_CURRENTLY_ON(work_thread_id());
  Respond(Error(message));
}

Project: Chrome

void BluetoothSocketListenFunction::OnGetAdapter(
    scoped_refptr<device::BluetoothAdapter> adapter) {
  DCHECK_CURRENTLY_ON(work_thread_id());
  BluetoothApiSocket* socket = GetSocket(socket_id());
  if (!socket) {
    Respond(Error(kSocketNotFoundError));
    return;
  }

  device::BluetoothUUID bluetooth_uuid(uuid());
  if (!bluetooth_uuid.IsValid()) {
    Respond(Error(kInvalidUuidError));
    return;
  }

  BluetoothPermissionRequest param(uuid());
  if (!BluetoothManifestData::CheckRequest(extension(), param)) {
    Respond(Error(kPermissionDeniedError));
    return;
  }

  std::unique_ptr<std::string> name;
  if (socket->name())
    name.reset(new std::string(*socket->name()));

  CreateService(
      adapter, bluetooth_uuid, std::move(name),
      base::Bind(&BluetoothSocketListenFunction::OnCreateService, this),
      base::Bind(&BluetoothSocketListenFunction::OnCreateServiceError, this));
}

Project: Chrome

void BluetoothSocketDisconnectFunction::OnSuccess() {
  DCHECK_CURRENTLY_ON(work_thread_id());
  Respond(ArgumentList(bluetooth_socket::Disconnect::Results::Create()));
}

Project: Chrome

bool BluetoothSocketAsyncApiFunction::PreRunValidation(std::string* error) {
  if (!UIThreadExtensionFunction::PreRunValidation(error))
    return false;

  if (!BluetoothManifestData::CheckSocketPermitted(extension())) {
    *error = kPermissionDeniedError;
    return false;
  }

  manager_ = ApiResourceManager<BluetoothApiSocket>::Get(browser_context());
  DCHECK(manager_)
      << "There is no socket manager. "
         "If this assertion is failing during a test, then it is likely that "
         "TestExtensionSystem is failing to provide an instance of "
         "ApiResourceManager<BluetoothApiSocket>.";

  if (!manager_) {
    *error = "There is no socket manager.";
    return false;
  }
  return true;
}

Project: Chrome

bool BluetoothSocketListenFunction::PreRunValidation(std::string* error) {
  if (!BluetoothSocketAsyncApiFunction::PreRunValidation(error))
    return false;
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  EXTENSION_FUNCTION_PRERUN_VALIDATE(CreateParams());
  socket_event_dispatcher_ = GetSocketEventDispatcher(browser_context());
  return socket_event_dispatcher_ != nullptr;
}

Project: Chrome

bool BluetoothSocketAbstractConnectFunction::PreRunValidation(
    std::string* error) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (!BluetoothSocketAsyncApiFunction::PreRunValidation(error))
    return false;

  params_ = bluetooth_socket::Connect::Params::Create(*args_);
  EXTENSION_FUNCTION_PRERUN_VALIDATE(params_.get());

  socket_event_dispatcher_ = GetSocketEventDispatcher(browser_context());
  return socket_event_dispatcher_ != nullptr;
}

Project: Chrome

void BluetoothSocketAsyncApiFunction::RemoveSocket(int api_resource_id) {
  manager_->Remove(extension_id(), api_resource_id);
}

Project: Chrome

ExtensionFunction::ResponseAction BluetoothSocketCreateFunction::Run() {
  DCHECK_CURRENTLY_ON(work_thread_id());

  auto params = bluetooth_socket::Create::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params.get());

  BluetoothApiSocket* socket = new BluetoothApiSocket(extension_id());

  bluetooth_socket::SocketProperties* properties = params->properties.get();
  if (properties)
    SetSocketProperties(socket, properties);

  bluetooth_socket::CreateInfo create_info;
  create_info.socket_id = AddSocket(socket);
  return RespondNow(
      ArgumentList(bluetooth_socket::Create::Results::Create(create_info)));
}

Project: Chrome

ExtensionFunction::ResponseAction BluetoothSocketUpdateFunction::Run() {
  auto params = bluetooth_socket::Update::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params.get());

  BluetoothApiSocket* socket = GetSocket(params->socket_id);
  if (!socket)
    return RespondNow(Error(kSocketNotFoundError));

  SetSocketProperties(socket, &params->properties);
  return RespondNow(ArgumentList(bluetooth_socket::Update::Results::Create()));
}

Project: Chrome

ExtensionFunction::ResponseAction BluetoothSocketSetPausedFunction::Run() {
  auto params = bluetooth_socket::SetPaused::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params.get());

  BluetoothSocketEventDispatcher* socket_event_dispatcher =
      GetSocketEventDispatcher(browser_context());
  if (!socket_event_dispatcher)
    return RespondNow(Error("Could not get socket event dispatcher."));

  BluetoothApiSocket* socket = GetSocket(params->socket_id);
  if (!socket)
    return RespondNow(Error(kSocketNotFoundError));

  if (socket->paused() != params->paused) {
    socket->set_paused(params->paused);
    if (!params->paused) {
      socket_event_dispatcher->OnSocketResume(extension_id(),
                                              params->socket_id);
    }
  }

  return RespondNow(
      ArgumentList(bluetooth_socket::SetPaused::Results::Create()));
}

Project: Chrome

BluetoothSocketAbstractConnectFunction::Run() {
  DCHECK_CURRENTLY_ON(work_thread_id());
  device::BluetoothAdapterFactory::GetAdapter(
      base::Bind(&BluetoothSocketAbstractConnectFunction::OnGetAdapter, this));
  return did_respond() ? AlreadyResponded() : RespondLater();
}

Project: Chrome

ExtensionFunction::ResponseAction BluetoothSocketDisconnectFunction::Run() {
  DCHECK_CURRENTLY_ON(work_thread_id());

  auto params = bluetooth_socket::Disconnect::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params.get());

  BluetoothApiSocket* socket = GetSocket(params->socket_id);
  if (!socket)
    return RespondNow(Error(kSocketNotFoundError));

  socket->Disconnect(base::Bind(&BluetoothSocketDisconnectFunction::OnSuccess,
                                this));
  return did_respond() ? AlreadyResponded() : RespondLater();
}

Project: Chrome

ExtensionFunction::ResponseAction BluetoothSocketCloseFunction::Run() {
  auto params = bluetooth_socket::Close::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params.get());
  BluetoothApiSocket* socket = GetSocket(params->socket_id);
  if (!socket)
    return RespondNow(Error(kSocketNotFoundError));

  RemoveSocket(params->socket_id);
  return RespondNow(ArgumentList(bluetooth_socket::Close::Results::Create()));
}

Project: Chrome

ExtensionFunction::ResponseAction BluetoothSocketGetInfoFunction::Run() {
  auto params = bluetooth_socket::GetInfo::Params::Create(*args_);
  EXTENSION_FUNCTION_VALIDATE(params.get());

  BluetoothApiSocket* socket = GetSocket(params->socket_id);
  if (!socket)
    return RespondNow(Error(kSocketNotFoundError));

  return RespondNow(ArgumentList(bluetooth_socket::GetInfo::Results::Create(
      CreateSocketInfo(params->socket_id, socket))));
}

Project: Chrome

ExtensionFunction::ResponseAction BluetoothSocketGetSocketsFunction::Run() {
  std::vector<bluetooth_socket::SocketInfo> socket_infos;
  base::hash_set<int>* resource_ids = GetSocketIds();
  if (resource_ids) {
    for (int socket_id : *resource_ids) {
      BluetoothApiSocket* socket = GetSocket(socket_id);
      if (socket) {
        socket_infos.push_back(CreateSocketInfo(socket_id, socket));
      }
    }
  }
  return RespondNow(ArgumentList(
      bluetooth_socket::GetSockets::Results::Create(socket_infos)));
}

Project: Chrome

void SetSocketProperties(BluetoothApiSocket* socket,
                         SocketProperties* properties) {
  if (properties->name.get()) {
    socket->set_name(*properties->name);
  }
  if (properties->persistent.get()) {
    socket->set_persistent(*properties->persistent);
  }
  if (properties->buffer_size.get()) {
    socket->set_buffer_size(*properties->buffer_size);
  }
}

Project: Chrome

int BluetoothSocketListenUsingRfcommFunction::socket_id() const {
  return params_->socket_id;
}

Project: Chrome

int BluetoothSocketListenUsingL2capFunction::socket_id() const {
  return params_->socket_id;
}

Project: Chrome

const std::string& BluetoothSocketListenUsingRfcommFunction::uuid() const {
  return params_->uuid;
}

Project: Chrome

BluetoothSocketAsyncApiFunction::work_thread_id() const {
  return BluetoothApiSocket::kThreadId;
}

Project: Chrome

    ~BluetoothSocketAbstractConnectFunction() {}

Project: Chrome

BluetoothSocketAsyncApiFunction::~BluetoothSocketAsyncApiFunction() {}

Project: Chrome

BluetoothSocketConnectFunction::~BluetoothSocketConnectFunction() {}

Project: Chrome

BluetoothSocketCreateFunction::~BluetoothSocketCreateFunction() {}

Project: Chrome

BluetoothSocketDisconnectFunction::~BluetoothSocketDisconnectFunction() {}

Project: Chrome

BluetoothSocketGetInfoFunction::~BluetoothSocketGetInfoFunction() {}

Project: Chrome

BluetoothSocketGetSocketsFunction::~BluetoothSocketGetSocketsFunction() {}

Project: Chrome

    ~BluetoothSocketListenUsingL2capFunction() {}

Project: Chrome

    ~BluetoothSocketListenUsingRfcommFunction() {}

Project: Chrome

BluetoothSocketSendFunction::~BluetoothSocketSendFunction() {}

Project: Chrome

BluetoothSocketSetPausedFunction::~BluetoothSocketSetPausedFunction() {}

Project: Chrome

BluetoothSocketUpdateFunction::~BluetoothSocketUpdateFunction() {}