Commit message: None
CVE: CVE-2018-6031
CWE: CWE-416
Vulnerability description: Use after free in PDFium in Google Chrome prior to 64.0.3282.119 allowed a remote attacker to potentially exploit heap corruption via a crafted PDF file.

Project: Chrome

bool PDFiumEngine::CheckPageAvailable(int index, std::vector<int>* pending) {
  if (!doc_)
    return false;

  const int num_pages = static_cast<int>(pages_.size());
  if (index < num_pages && pages_[index]->available())
    return true;

  if (!FPDFAvail_IsPageAvail(fpdf_availability_, index, &download_hints_)) {
    if (!base::ContainsValue(*pending, index))
      pending->push_back(index);
    return false;
  }

  if (index < num_pages)
    pages_[index]->set_available(true);
  if (default_page_size_.IsEmpty())
    default_page_size_ = GetPageSize(index);
  return true;
}

Project: Chrome

int PDFiumEngine::GetCharCount(int page_index) {
  DCHECK(PageIndexInBounds(page_index));
  return pages_[page_index]->GetCharCount();
}

Project: Chrome

bool IsFormTextArea(PDFiumPage::Area area, int form_type) {
  if (form_type == FPDF_FORMFIELD_UNKNOWN)
    return false;

  DCHECK_EQ(area, PDFiumPage::FormTypeToArea(form_type));
  return area == PDFiumPage::FORM_TEXT_AREA;
}

Project: Chrome

void PDFiumEngine::LoadPages() {
  if (pages_.empty()) {
    if (!doc_loader_->IsDocumentComplete()) {
      CheckPageAvailable(FPDFAvail_GetFirstPageNum(doc_), &pending_pages_);
    }
    LoadPageInfo(false);
  }
}

Project: Chrome

bool PDFiumEngine::OnLeftMouseDown(const pp::MouseInputEvent& event) {
  SetMouseLeftButtonDown(true);

  auto selection_invalidator =
      std::make_unique<SelectionChangeInvalidator>(this);
  selection_.clear();

  int page_index = -1;
  int char_index = -1;
  int form_type = FPDF_FORMFIELD_UNKNOWN;
  PDFiumPage::LinkTarget target;
  pp::Point point = event.GetPosition();
  PDFiumPage::Area area =
      GetCharIndex(point, &page_index, &char_index, &form_type, &target);
  DCHECK_GE(form_type, FPDF_FORMFIELD_UNKNOWN);
  mouse_down_state_.Set(area, target);

  if (IsLinkArea(area))
    return true;

  if (page_index != -1) {
    last_page_mouse_down_ = page_index;
    double page_x;
    double page_y;
    DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);

    bool is_form_text_area = IsFormTextArea(area, form_type);
    FPDF_PAGE page = pages_[page_index]->GetPage();
    bool is_editable_form_text_area =
        is_form_text_area &&
        IsPointInEditableFormTextArea(page, page_x, page_y, form_type);

    FORM_OnLButtonDown(form_, page, 0, page_x, page_y);
    if (form_type != FPDF_FORMFIELD_UNKNOWN) {
      selection_invalidator.reset();

      SetInFormTextArea(is_form_text_area);
      editable_form_text_area_ = is_editable_form_text_area;
      return true;  // Return now before we get into the selection code.
    }
  }
  SetInFormTextArea(false);

  if (area != PDFiumPage::TEXT_AREA)
    return true;  // Return true so WebKit doesn't do its own highlighting.

  if (event.GetClickCount() == 1)
    OnSingleClick(page_index, char_index);
  else if (event.GetClickCount() == 2 || event.GetClickCount() == 3)
    OnMultipleClick(event.GetClickCount(), page_index, char_index);

  return true;
}

Project: Chrome

bool PDFiumEngine::OnMouseDown(const pp::MouseInputEvent& event) {
  pp::MouseInputEvent normalized_event =
      NormalizeMouseEvent(client_->GetPluginInstance(), event);
  if (normalized_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_LEFT)
    return OnLeftMouseDown(normalized_event);
  if (normalized_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_MIDDLE)
    return OnMiddleMouseDown(normalized_event);
  if (normalized_event.GetButton() == PP_INPUTEVENT_MOUSEBUTTON_RIGHT)
    return OnRightMouseDown(normalized_event);
  return false;
}

Project: Chrome

void PDFiumEngine::OnMultipleClick(int click_count,
                                   int page_index,
                                   int char_index) {
  DCHECK_GE(click_count, 2);
  bool is_double_click = click_count == 2;

  int start_index = char_index;
  do {
    base::char16 cur = pages_[page_index]->GetCharAtIndex(start_index);
    if (FindMultipleClickBoundary(is_double_click, cur))
      break;
  } while (--start_index >= 0);
  if (start_index)
    start_index++;

  int end_index = char_index;
  int total = pages_[page_index]->GetCharCount();
  while (end_index++ <= total) {
    base::char16 cur = pages_[page_index]->GetCharAtIndex(end_index);
    if (FindMultipleClickBoundary(is_double_click, cur))
      break;
  }

  selection_.push_back(PDFiumRange(pages_[page_index].get(), start_index,
                                   end_index - start_index));
}

Project: Chrome

void PDFiumEngine::OnSelectionChanged() {
  DCHECK(!in_form_text_area_);
  pp::PDF::SetSelectedText(GetPluginInstance(), GetSelectedText().c_str());

  pp::Rect left(std::numeric_limits<int32_t>::max(),
                std::numeric_limits<int32_t>::max(), 0, 0);
  pp::Rect right;
  for (auto& sel : selection_) {
    const std::vector<pp::Rect>& screen_rects = sel.GetScreenRects(
        GetVisibleRect().point(), current_zoom_, current_rotation_);
    for (const auto& rect : screen_rects) {
      if (IsAboveOrDirectlyLeftOf(rect, left))
        left = rect;
      if (IsAboveOrDirectlyLeftOf(right, rect))
        right = rect;
    }
  }
  right.set_x(right.x() + right.width());
  if (left.IsEmpty()) {
    left.set_x(0);
    left.set_y(0);
  }
  client_->SelectionChanged(left, right);
}

Project: Chrome

PDFiumEngine::PDFiumEngine(PDFEngine::Client* client)
    : client_(client),
      current_zoom_(1.0),
      current_rotation_(0),
      doc_(nullptr),
      form_(nullptr),
      defer_page_unload_(false),
      selecting_(false),
      mouse_down_state_(PDFiumPage::NONSELECTABLE_AREA,
                        PDFiumPage::LinkTarget()),
      in_form_text_area_(false),
      editable_form_text_area_(false),
      mouse_left_button_down_(false),
      permissions_(0),
      permissions_handler_revision_(-1),
      fpdf_availability_(nullptr),
      last_page_mouse_down_(-1),
      most_visible_page_(-1),
      called_do_document_action_(false),
      render_grayscale_(false),
      render_annots_(true) {
  find_factory_.Initialize(this);
  password_factory_.Initialize(this);

  file_access_.m_FileLen = 0;
  file_access_.m_GetBlock = &GetBlock;
  file_access_.m_Param = this;

  file_availability_.version = 1;
  file_availability_.IsDataAvail = &IsDataAvail;
  file_availability_.engine = this;

  download_hints_.version = 1;
  download_hints_.AddSegment = &AddSegment;
  download_hints_.engine = this;

  FPDF_FORMFILLINFO::version = 1;
  FPDF_FORMFILLINFO::m_pJsPlatform = this;
  FPDF_FORMFILLINFO::Release = nullptr;
  FPDF_FORMFILLINFO::FFI_Invalidate = Form_Invalidate;
  FPDF_FORMFILLINFO::FFI_OutputSelectedRect = Form_OutputSelectedRect;
  FPDF_FORMFILLINFO::FFI_SetCursor = Form_SetCursor;
  FPDF_FORMFILLINFO::FFI_SetTimer = Form_SetTimer;
  FPDF_FORMFILLINFO::FFI_KillTimer = Form_KillTimer;
  FPDF_FORMFILLINFO::FFI_GetLocalTime = Form_GetLocalTime;
  FPDF_FORMFILLINFO::FFI_OnChange = Form_OnChange;
  FPDF_FORMFILLINFO::FFI_GetPage = Form_GetPage;
  FPDF_FORMFILLINFO::FFI_GetCurrentPage = Form_GetCurrentPage;
  FPDF_FORMFILLINFO::FFI_GetRotation = Form_GetRotation;
  FPDF_FORMFILLINFO::FFI_ExecuteNamedAction = Form_ExecuteNamedAction;
  FPDF_FORMFILLINFO::FFI_SetTextFieldFocus = Form_SetTextFieldFocus;
  FPDF_FORMFILLINFO::FFI_DoURIAction = Form_DoURIAction;
  FPDF_FORMFILLINFO::FFI_DoGoToAction = Form_DoGoToAction;
#if defined(PDF_ENABLE_XFA)
  FPDF_FORMFILLINFO::version = 2;
  FPDF_FORMFILLINFO::FFI_EmailTo = Form_EmailTo;
  FPDF_FORMFILLINFO::FFI_DisplayCaret = Form_DisplayCaret;
  FPDF_FORMFILLINFO::FFI_SetCurrentPage = Form_SetCurrentPage;
  FPDF_FORMFILLINFO::FFI_GetCurrentPageIndex = Form_GetCurrentPageIndex;
  FPDF_FORMFILLINFO::FFI_GetPageViewRect = Form_GetPageViewRect;
  FPDF_FORMFILLINFO::FFI_GetPlatform = Form_GetPlatform;
  FPDF_FORMFILLINFO::FFI_PageEvent = nullptr;
  FPDF_FORMFILLINFO::FFI_PopupMenu = Form_PopupMenu;
  FPDF_FORMFILLINFO::FFI_PostRequestURL = Form_PostRequestURL;
  FPDF_FORMFILLINFO::FFI_PutRequestURL = Form_PutRequestURL;
  FPDF_FORMFILLINFO::FFI_UploadTo = Form_UploadTo;
  FPDF_FORMFILLINFO::FFI_DownloadFromURL = Form_DownloadFromURL;
  FPDF_FORMFILLINFO::FFI_OpenFile = Form_OpenFile;
  FPDF_FORMFILLINFO::FFI_GotoURL = Form_GotoURL;
  FPDF_FORMFILLINFO::FFI_GetLanguage = Form_GetLanguage;
#endif  // defined(PDF_ENABLE_XFA)
  IPDF_JSPLATFORM::version = 3;
  IPDF_JSPLATFORM::app_alert = Form_Alert;
  IPDF_JSPLATFORM::app_beep = Form_Beep;
  IPDF_JSPLATFORM::app_response = Form_Response;
  IPDF_JSPLATFORM::Doc_getFilePath = Form_GetFilePath;
  IPDF_JSPLATFORM::Doc_mail = Form_Mail;
  IPDF_JSPLATFORM::Doc_print = Form_Print;
  IPDF_JSPLATFORM::Doc_submitForm = Form_SubmitForm;
  IPDF_JSPLATFORM::Doc_gotoPage = Form_GotoPage;
  IPDF_JSPLATFORM::Field_browse = nullptr;

  IFSDK_PAUSE::version = 1;
  IFSDK_PAUSE::user = nullptr;
  IFSDK_PAUSE::NeedToPauseNow = Pause_NeedToPauseNow;

#if defined(OS_LINUX)
  pp::Instance* instance = client_->GetPluginInstance();
  if (instance)
    g_last_instance_id = instance->pp_instance();
#endif
}

Project: Chrome

pp::Resource PDFiumEngine::PrintPages(
    const PP_PrintPageNumberRange_Dev* page_ranges,
    uint32_t page_range_count,
    const PP_PrintSettings_Dev& print_settings) {
  ScopedSubstFont scoped_subst_font(this);
  if ((print_settings.format & PP_PRINTOUTPUTFORMAT_PDF) &&
      HasPermission(PERMISSION_PRINT_HIGH_QUALITY)) {
    return PrintPagesAsPDF(page_ranges, page_range_count, print_settings);
  }
  if (HasPermission(PERMISSION_PRINT_LOW_QUALITY))
    return PrintPagesAsRasterPDF(page_ranges, page_range_count, print_settings);
  return pp::Resource();
}

Project: Chrome

void Release(FPDF_SYSFONTINFO* sysfontinfo) {
  auto* fontinfo_with_metrics =
      static_cast<FPDF_SYSFONTINFO_WITHMETRICS*>(sysfontinfo);
  if (!fontinfo_with_metrics->default_sysfontinfo->Release)
    return;
  fontinfo_with_metrics->default_sysfontinfo->Release(
      fontinfo_with_metrics->default_sysfontinfo);
}

Project: Chrome

bool PDFiumEngine::TryLoadingDoc(const std::string& password,
                                 bool* needs_password) {
  *needs_password = false;
  if (doc_) {
    FPDFAvail_IsDocAvail(fpdf_availability_, &download_hints_);
    return true;
  }

  const char* password_cstr = nullptr;
  if (!password.empty()) {
    password_cstr = password.c_str();
    password_tries_remaining_--;
  }
  if (doc_loader_->IsDocumentComplete() &&
      !FPDFAvail_IsLinearized(fpdf_availability_)) {
    doc_ = FPDF_LoadCustomDocument(&file_access_, password_cstr);
  } else {
    doc_ = FPDFAvail_GetDocument(fpdf_availability_, password_cstr);
  }
  if (!doc_) {
    if (FPDF_GetLastError() == FPDF_ERR_PASSWORD)
      *needs_password = true;
    return false;
  }

  FPDFAvail_IsDocAvail(fpdf_availability_, &download_hints_);
  return true;
}