• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "testing/fuzzers/pdfium_fuzzer_helper.h"
6 
7 #include <assert.h>
8 #include <limits.h>
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <memory>
17 #include <sstream>
18 #include <string>
19 #include <tuple>
20 #include <utility>
21 
22 #include "public/cpp/fpdf_scopers.h"
23 #include "public/fpdf_dataavail.h"
24 #include "public/fpdf_ext.h"
25 #include "public/fpdf_text.h"
26 #include "third_party/base/span.h"
27 
28 namespace {
29 
30 class FuzzerTestLoader {
31  public:
FuzzerTestLoader(pdfium::span<const char> span)32   explicit FuzzerTestLoader(pdfium::span<const char> span) : m_Span(span) {}
33 
GetBlock(void * param,unsigned long pos,unsigned char * pBuf,unsigned long size)34   static int GetBlock(void* param,
35                       unsigned long pos,
36                       unsigned char* pBuf,
37                       unsigned long size) {
38     FuzzerTestLoader* pLoader = static_cast<FuzzerTestLoader*>(param);
39     if (pos + size < pos || pos + size > pLoader->m_Span.size()) {
40       NOTREACHED();
41       return 0;
42     }
43 
44     memcpy(pBuf, &pLoader->m_Span[pos], size);
45     return 1;
46   }
47 
48  private:
49   const pdfium::span<const char> m_Span;
50 };
51 
ExampleAppAlert(IPDF_JSPLATFORM *,FPDF_WIDESTRING,FPDF_WIDESTRING,int,int)52 int ExampleAppAlert(IPDF_JSPLATFORM*,
53                     FPDF_WIDESTRING,
54                     FPDF_WIDESTRING,
55                     int,
56                     int) {
57   return 0;
58 }
59 
ExampleAppResponse(IPDF_JSPLATFORM *,FPDF_WIDESTRING question,FPDF_WIDESTRING title,FPDF_WIDESTRING default_value,FPDF_WIDESTRING label,FPDF_BOOL is_password,void * response,int length)60 int ExampleAppResponse(IPDF_JSPLATFORM*,
61                        FPDF_WIDESTRING question,
62                        FPDF_WIDESTRING title,
63                        FPDF_WIDESTRING default_value,
64                        FPDF_WIDESTRING label,
65                        FPDF_BOOL is_password,
66                        void* response,
67                        int length) {
68   // UTF-16, always LE regardless of platform.
69   uint8_t* ptr = static_cast<uint8_t*>(response);
70   ptr[0] = 'N';
71   ptr[1] = 0;
72   ptr[2] = 'o';
73   ptr[3] = 0;
74   return 4;
75 }
76 
ExampleDocGotoPage(IPDF_JSPLATFORM *,int pageNumber)77 void ExampleDocGotoPage(IPDF_JSPLATFORM*, int pageNumber) {}
78 
ExampleDocMail(IPDF_JSPLATFORM *,void * mailData,int length,FPDF_BOOL UI,FPDF_WIDESTRING To,FPDF_WIDESTRING Subject,FPDF_WIDESTRING CC,FPDF_WIDESTRING BCC,FPDF_WIDESTRING Msg)79 void ExampleDocMail(IPDF_JSPLATFORM*,
80                     void* mailData,
81                     int length,
82                     FPDF_BOOL UI,
83                     FPDF_WIDESTRING To,
84                     FPDF_WIDESTRING Subject,
85                     FPDF_WIDESTRING CC,
86                     FPDF_WIDESTRING BCC,
87                     FPDF_WIDESTRING Msg) {}
88 
Is_Data_Avail(FX_FILEAVAIL * pThis,size_t offset,size_t size)89 FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
90   return true;
91 }
92 
Add_Segment(FX_DOWNLOADHINTS * pThis,size_t offset,size_t size)93 void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {}
94 
GetRenderingAndFormFlagFromData(const char * data,size_t len)95 std::pair<int, int> GetRenderingAndFormFlagFromData(const char* data,
96                                                     size_t len) {
97   std::string data_str = std::string(data, len);
98   std::size_t data_hash = std::hash<std::string>()(data_str);
99 
100   // The largest flag value is 0x4FFF, so just take 16 bits from |data_hash| at
101   // a time.
102   int render_flags = data_hash & 0xffff;
103   int form_flags = (data_hash >> 16) & 0xffff;
104   return std::make_pair(render_flags, form_flags);
105 }
106 
107 }  // namespace
108 
109 PDFiumFuzzerHelper::PDFiumFuzzerHelper() = default;
110 
111 PDFiumFuzzerHelper::~PDFiumFuzzerHelper() = default;
112 
OnFormFillEnvLoaded(FPDF_DOCUMENT doc)113 bool PDFiumFuzzerHelper::OnFormFillEnvLoaded(FPDF_DOCUMENT doc) {
114   return true;
115 }
116 
RenderPdf(const char * data,size_t len)117 void PDFiumFuzzerHelper::RenderPdf(const char* data, size_t len) {
118   int render_flags;
119   int form_flags;
120   std::tie(render_flags, form_flags) =
121       GetRenderingAndFormFlagFromData(data, len);
122 
123   IPDF_JSPLATFORM platform_callbacks;
124   memset(&platform_callbacks, '\0', sizeof(platform_callbacks));
125   platform_callbacks.version = 3;
126   platform_callbacks.app_alert = ExampleAppAlert;
127   platform_callbacks.app_response = ExampleAppResponse;
128   platform_callbacks.Doc_gotoPage = ExampleDocGotoPage;
129   platform_callbacks.Doc_mail = ExampleDocMail;
130 
131   FPDF_FORMFILLINFO form_callbacks;
132   memset(&form_callbacks, '\0', sizeof(form_callbacks));
133   form_callbacks.version = GetFormCallbackVersion();
134   form_callbacks.m_pJsPlatform = &platform_callbacks;
135 
136   FuzzerTestLoader loader({data, len});
137   FPDF_FILEACCESS file_access;
138   memset(&file_access, '\0', sizeof(file_access));
139   file_access.m_FileLen = static_cast<unsigned long>(len);
140   file_access.m_GetBlock = FuzzerTestLoader::GetBlock;
141   file_access.m_Param = &loader;
142 
143   FX_FILEAVAIL file_avail;
144   memset(&file_avail, '\0', sizeof(file_avail));
145   file_avail.version = 1;
146   file_avail.IsDataAvail = Is_Data_Avail;
147 
148   FX_DOWNLOADHINTS hints;
149   memset(&hints, '\0', sizeof(hints));
150   hints.version = 1;
151   hints.AddSegment = Add_Segment;
152 
153   ScopedFPDFAvail pdf_avail(FPDFAvail_Create(&file_avail, &file_access));
154 
155   int nRet = PDF_DATA_NOTAVAIL;
156   bool bIsLinearized = false;
157   ScopedFPDFDocument doc;
158   if (FPDFAvail_IsLinearized(pdf_avail.get()) == PDF_LINEARIZED) {
159     doc.reset(FPDFAvail_GetDocument(pdf_avail.get(), nullptr));
160     if (doc) {
161       while (nRet == PDF_DATA_NOTAVAIL)
162         nRet = FPDFAvail_IsDocAvail(pdf_avail.get(), &hints);
163 
164       if (nRet == PDF_DATA_ERROR)
165         return;
166 
167       nRet = FPDFAvail_IsFormAvail(pdf_avail.get(), &hints);
168       if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL)
169         return;
170 
171       bIsLinearized = true;
172     }
173   } else {
174     doc.reset(FPDF_LoadCustomDocument(&file_access, nullptr));
175   }
176 
177   if (!doc)
178     return;
179 
180   (void)FPDF_GetDocPermissions(doc.get());
181 
182   ScopedFPDFFormHandle form(
183       FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks));
184   if (!OnFormFillEnvLoaded(doc.get()))
185     return;
186 
187   FPDF_SetFormFieldHighlightColor(form.get(), FPDF_FORMFIELD_UNKNOWN, 0xFFE4DD);
188   FPDF_SetFormFieldHighlightAlpha(form.get(), 100);
189   FORM_DoDocumentJSAction(form.get());
190   FORM_DoDocumentOpenAction(form.get());
191 
192   int page_count = FPDF_GetPageCount(doc.get());
193   for (int i = 0; i < page_count; ++i) {
194     if (bIsLinearized) {
195       nRet = PDF_DATA_NOTAVAIL;
196       while (nRet == PDF_DATA_NOTAVAIL)
197         nRet = FPDFAvail_IsPageAvail(pdf_avail.get(), i, &hints);
198 
199       if (nRet == PDF_DATA_ERROR)
200         return;
201     }
202     RenderPage(doc.get(), form.get(), i, render_flags, form_flags);
203   }
204   OnRenderFinished(doc.get());
205   FORM_DoDocumentAAction(form.get(), FPDFDOC_AACTION_WC);
206 }
207 
RenderPage(FPDF_DOCUMENT doc,FPDF_FORMHANDLE form,int page_index,int render_flags,int form_flags)208 bool PDFiumFuzzerHelper::RenderPage(FPDF_DOCUMENT doc,
209                                     FPDF_FORMHANDLE form,
210                                     int page_index,
211                                     int render_flags,
212                                     int form_flags) {
213   ScopedFPDFPage page(FPDF_LoadPage(doc, page_index));
214   if (!page)
215     return false;
216 
217   ScopedFPDFTextPage text_page(FPDFText_LoadPage(page.get()));
218   FORM_OnAfterLoadPage(page.get(), form);
219   FORM_DoPageAAction(page.get(), form, FPDFPAGE_AACTION_OPEN);
220 
221   const double scale = 1.0;
222   int width = static_cast<int>(FPDF_GetPageWidthF(page.get()) * scale);
223   int height = static_cast<int>(FPDF_GetPageHeightF(page.get()) * scale);
224   ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, 0));
225   if (bitmap) {
226     FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, 0xFFFFFFFF);
227     FPDF_RenderPageBitmap(bitmap.get(), page.get(), 0, 0, width, height, 0,
228                           render_flags);
229     FPDF_FFLDraw(form, bitmap.get(), page.get(), 0, 0, width, height, 0,
230                  form_flags);
231   }
232   FORM_DoPageAAction(page.get(), form, FPDFPAGE_AACTION_CLOSE);
233   FORM_OnBeforeClosePage(page.get(), form);
234   return !!bitmap;
235 }
236