1 // Copyright 2014 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "fxjs/cfx_globaldata.h"
8
9 #include <utility>
10
11 #include "core/fdrm/fx_crypt.h"
12 #include "core/fxcrt/stl_util.h"
13 #include "third_party/base/numerics/safe_conversions.h"
14
15 namespace {
16
17 constexpr size_t kMinGlobalDataBytes = 12;
18 constexpr size_t kMaxGlobalDataBytes = 4 * 1024 - 8;
19 constexpr uint16_t kMagic = ('X' << 8) | 'F';
20 constexpr uint16_t kMaxVersion = 2;
21
22 const uint8_t kRC4KEY[] = {
23 0x19, 0xa8, 0xe8, 0x01, 0xf6, 0xa8, 0xb6, 0x4d, 0x82, 0x04, 0x45, 0x6d,
24 0xb4, 0xcf, 0xd7, 0x77, 0x67, 0xf9, 0x75, 0x9f, 0xf0, 0xe0, 0x1e, 0x51,
25 0xee, 0x46, 0xfd, 0x0b, 0xc9, 0x93, 0x25, 0x55, 0x4a, 0xee, 0xe0, 0x16,
26 0xd0, 0xdf, 0x8c, 0xfa, 0x2a, 0xa9, 0x49, 0xfd, 0x97, 0x1c, 0x0e, 0x22,
27 0x13, 0x28, 0x7c, 0xaf, 0xc4, 0xfc, 0x9c, 0x12, 0x65, 0x8c, 0x4e, 0x5b,
28 0x04, 0x75, 0x89, 0xc9, 0xb1, 0xed, 0x50, 0xca, 0x96, 0x6f, 0x1a, 0x7a,
29 0xfe, 0x58, 0x5d, 0xec, 0x19, 0x4a, 0xf6, 0x35, 0x6a, 0x97, 0x14, 0x00,
30 0x0e, 0xd0, 0x6b, 0xbb, 0xd5, 0x75, 0x55, 0x8b, 0x6e, 0x6b, 0x19, 0xa0,
31 0xf8, 0x77, 0xd5, 0xa3};
32
33 CFX_GlobalData* g_pInstance = nullptr;
34
35 // Returns true if non-empty, setting sPropName
TrimPropName(ByteString * sPropName)36 bool TrimPropName(ByteString* sPropName) {
37 sPropName->Trim();
38 return sPropName->GetLength() != 0;
39 }
40
MakeNameTypeString(const ByteString & name,CFX_Value::DataType eType,BinaryBuffer * result)41 void MakeNameTypeString(const ByteString& name,
42 CFX_Value::DataType eType,
43 BinaryBuffer* result) {
44 uint32_t dwNameLen = pdfium::base::checked_cast<uint32_t>(name.GetLength());
45 result->AppendUint32(dwNameLen);
46 result->AppendString(name);
47 result->AppendUint16(static_cast<uint16_t>(eType));
48 }
49
MakeByteString(const ByteString & name,const CFX_KeyValue & pData,BinaryBuffer * result)50 bool MakeByteString(const ByteString& name,
51 const CFX_KeyValue& pData,
52 BinaryBuffer* result) {
53 switch (pData.nType) {
54 case CFX_Value::DataType::kNumber: {
55 MakeNameTypeString(name, pData.nType, result);
56 result->AppendDouble(pData.dData);
57 return true;
58 }
59 case CFX_Value::DataType::kBoolean: {
60 MakeNameTypeString(name, pData.nType, result);
61 result->AppendUint16(static_cast<uint16_t>(pData.bData));
62 return true;
63 }
64 case CFX_Value::DataType::kString: {
65 MakeNameTypeString(name, pData.nType, result);
66 uint32_t dwDataLen =
67 pdfium::base::checked_cast<uint32_t>(pData.sData.GetLength());
68 result->AppendUint32(dwDataLen);
69 result->AppendString(pData.sData);
70 return true;
71 }
72 case CFX_Value::DataType::kNull: {
73 MakeNameTypeString(name, pData.nType, result);
74 return true;
75 }
76 // Arrays don't get persisted per JS spec page 484.
77 case CFX_Value::DataType::kObject:
78 default:
79 break;
80 }
81 return false;
82 }
83
84 } // namespace
85
86 // static
GetRetainedInstance(Delegate * pDelegate)87 CFX_GlobalData* CFX_GlobalData::GetRetainedInstance(Delegate* pDelegate) {
88 if (!g_pInstance) {
89 g_pInstance = new CFX_GlobalData(pDelegate);
90 }
91 ++g_pInstance->m_RefCount;
92 return g_pInstance;
93 }
94
Release()95 bool CFX_GlobalData::Release() {
96 if (--m_RefCount)
97 return false;
98
99 delete g_pInstance;
100 g_pInstance = nullptr;
101 return true;
102 }
103
CFX_GlobalData(Delegate * pDelegate)104 CFX_GlobalData::CFX_GlobalData(Delegate* pDelegate) : m_pDelegate(pDelegate) {
105 LoadGlobalPersistentVariables();
106 }
107
~CFX_GlobalData()108 CFX_GlobalData::~CFX_GlobalData() {
109 SaveGlobalPersisitentVariables();
110 }
111
FindGlobalVariable(const ByteString & propname)112 CFX_GlobalData::iterator CFX_GlobalData::FindGlobalVariable(
113 const ByteString& propname) {
114 for (auto it = m_arrayGlobalData.begin(); it != m_arrayGlobalData.end();
115 ++it) {
116 if ((*it)->data.sKey == propname)
117 return it;
118 }
119 return m_arrayGlobalData.end();
120 }
121
GetGlobalVariable(const ByteString & propname)122 CFX_GlobalData::Element* CFX_GlobalData::GetGlobalVariable(
123 const ByteString& propname) {
124 auto iter = FindGlobalVariable(propname);
125 return iter != m_arrayGlobalData.end() ? iter->get() : nullptr;
126 }
127
SetGlobalVariableNumber(ByteString sPropName,double dData)128 void CFX_GlobalData::SetGlobalVariableNumber(ByteString sPropName,
129 double dData) {
130 if (!TrimPropName(&sPropName))
131 return;
132
133 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
134 if (pData) {
135 pData->data.nType = CFX_Value::DataType::kNumber;
136 pData->data.dData = dData;
137 return;
138 }
139 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
140 pNewData->data.sKey = std::move(sPropName);
141 pNewData->data.nType = CFX_Value::DataType::kNumber;
142 pNewData->data.dData = dData;
143 m_arrayGlobalData.push_back(std::move(pNewData));
144 }
145
SetGlobalVariableBoolean(ByteString sPropName,bool bData)146 void CFX_GlobalData::SetGlobalVariableBoolean(ByteString sPropName,
147 bool bData) {
148 if (!TrimPropName(&sPropName))
149 return;
150
151 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
152 if (pData) {
153 pData->data.nType = CFX_Value::DataType::kBoolean;
154 pData->data.bData = bData;
155 return;
156 }
157 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
158 pNewData->data.sKey = std::move(sPropName);
159 pNewData->data.nType = CFX_Value::DataType::kBoolean;
160 pNewData->data.bData = bData;
161 m_arrayGlobalData.push_back(std::move(pNewData));
162 }
163
SetGlobalVariableString(ByteString sPropName,const ByteString & sData)164 void CFX_GlobalData::SetGlobalVariableString(ByteString sPropName,
165 const ByteString& sData) {
166 if (!TrimPropName(&sPropName))
167 return;
168
169 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
170 if (pData) {
171 pData->data.nType = CFX_Value::DataType::kString;
172 pData->data.sData = sData;
173 return;
174 }
175 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
176 pNewData->data.sKey = std::move(sPropName);
177 pNewData->data.nType = CFX_Value::DataType::kString;
178 pNewData->data.sData = sData;
179 m_arrayGlobalData.push_back(std::move(pNewData));
180 }
181
SetGlobalVariableObject(ByteString sPropName,std::vector<std::unique_ptr<CFX_KeyValue>> array)182 void CFX_GlobalData::SetGlobalVariableObject(
183 ByteString sPropName,
184 std::vector<std::unique_ptr<CFX_KeyValue>> array) {
185 if (!TrimPropName(&sPropName))
186 return;
187
188 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
189 if (pData) {
190 pData->data.nType = CFX_Value::DataType::kObject;
191 pData->data.objData = std::move(array);
192 return;
193 }
194 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
195 pNewData->data.sKey = std::move(sPropName);
196 pNewData->data.nType = CFX_Value::DataType::kObject;
197 pNewData->data.objData = std::move(array);
198 m_arrayGlobalData.push_back(std::move(pNewData));
199 }
200
SetGlobalVariableNull(ByteString sPropName)201 void CFX_GlobalData::SetGlobalVariableNull(ByteString sPropName) {
202 if (!TrimPropName(&sPropName))
203 return;
204
205 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
206 if (pData) {
207 pData->data.nType = CFX_Value::DataType::kNull;
208 return;
209 }
210 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
211 pNewData->data.sKey = std::move(sPropName);
212 pNewData->data.nType = CFX_Value::DataType::kNull;
213 m_arrayGlobalData.push_back(std::move(pNewData));
214 }
215
SetGlobalVariablePersistent(ByteString sPropName,bool bPersistent)216 bool CFX_GlobalData::SetGlobalVariablePersistent(ByteString sPropName,
217 bool bPersistent) {
218 if (!TrimPropName(&sPropName))
219 return false;
220
221 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
222 if (!pData)
223 return false;
224
225 pData->bPersistent = bPersistent;
226 return true;
227 }
228
DeleteGlobalVariable(ByteString sPropName)229 bool CFX_GlobalData::DeleteGlobalVariable(ByteString sPropName) {
230 if (!TrimPropName(&sPropName))
231 return false;
232
233 auto iter = FindGlobalVariable(sPropName);
234 if (iter == m_arrayGlobalData.end())
235 return false;
236
237 m_arrayGlobalData.erase(iter);
238 return true;
239 }
240
GetSize() const241 int32_t CFX_GlobalData::GetSize() const {
242 return fxcrt::CollectionSize<int32_t>(m_arrayGlobalData);
243 }
244
GetAt(int index)245 CFX_GlobalData::Element* CFX_GlobalData::GetAt(int index) {
246 if (index < 0 || index >= GetSize())
247 return nullptr;
248 return m_arrayGlobalData[index].get();
249 }
250
LoadGlobalPersistentVariables()251 bool CFX_GlobalData::LoadGlobalPersistentVariables() {
252 if (!m_pDelegate)
253 return false;
254
255 bool ret;
256 {
257 // Span can't outlive call to BufferDone().
258 absl::optional<pdfium::span<uint8_t>> buffer = m_pDelegate->LoadBuffer();
259 if (!buffer.has_value() || buffer.value().empty())
260 return false;
261
262 ret = LoadGlobalPersistentVariablesFromBuffer(buffer.value());
263 }
264 m_pDelegate->BufferDone();
265 return ret;
266 }
267
LoadGlobalPersistentVariablesFromBuffer(pdfium::span<uint8_t> buffer)268 bool CFX_GlobalData::LoadGlobalPersistentVariablesFromBuffer(
269 pdfium::span<uint8_t> buffer) {
270 if (buffer.size() < kMinGlobalDataBytes)
271 return false;
272
273 CRYPT_ArcFourCryptBlock(buffer, kRC4KEY);
274
275 uint8_t* p = buffer.data();
276 uint16_t wType = *((uint16_t*)p);
277 p += sizeof(uint16_t);
278 if (wType != kMagic)
279 return false;
280
281 uint16_t wVersion = *((uint16_t*)p);
282 p += sizeof(uint16_t);
283 if (wVersion > kMaxVersion)
284 return false;
285
286 uint32_t dwCount = *((uint32_t*)p);
287 p += sizeof(uint32_t);
288
289 uint32_t dwSize = *((uint32_t*)p);
290 p += sizeof(uint32_t);
291
292 if (dwSize != buffer.size() - sizeof(uint16_t) * 2 - sizeof(uint32_t) * 2)
293 return false;
294
295 for (int32_t i = 0, sz = dwCount; i < sz; i++) {
296 if (p > buffer.end())
297 break;
298
299 uint32_t dwNameLen = *((uint32_t*)p);
300 p += sizeof(uint32_t);
301 if (p + dwNameLen > buffer.end())
302 break;
303
304 ByteString sEntry = ByteString(p, dwNameLen);
305 p += sizeof(char) * dwNameLen;
306
307 CFX_Value::DataType wDataType =
308 static_cast<CFX_Value::DataType>(*((uint16_t*)p));
309 p += sizeof(uint16_t);
310
311 switch (wDataType) {
312 case CFX_Value::DataType::kNumber: {
313 double dData = 0;
314 switch (wVersion) {
315 case 1: {
316 uint32_t dwData = *((uint32_t*)p);
317 p += sizeof(uint32_t);
318 dData = dwData;
319 } break;
320 case 2: {
321 dData = *((double*)p);
322 p += sizeof(double);
323 } break;
324 }
325 SetGlobalVariableNumber(sEntry, dData);
326 SetGlobalVariablePersistent(sEntry, true);
327 } break;
328 case CFX_Value::DataType::kBoolean: {
329 uint16_t wData = *((uint16_t*)p);
330 p += sizeof(uint16_t);
331 SetGlobalVariableBoolean(sEntry, (bool)(wData == 1));
332 SetGlobalVariablePersistent(sEntry, true);
333 } break;
334 case CFX_Value::DataType::kString: {
335 uint32_t dwLength = *((uint32_t*)p);
336 p += sizeof(uint32_t);
337 if (p + dwLength > buffer.end())
338 break;
339
340 SetGlobalVariableString(sEntry, ByteString(p, dwLength));
341 SetGlobalVariablePersistent(sEntry, true);
342 p += sizeof(char) * dwLength;
343 } break;
344 case CFX_Value::DataType::kNull: {
345 SetGlobalVariableNull(sEntry);
346 SetGlobalVariablePersistent(sEntry, true);
347 } break;
348 case CFX_Value::DataType::kObject:
349 default:
350 // Arrays aren't allowed in these buffers, nor are unrecoginzed tags.
351 return false;
352 }
353 }
354 return true;
355 }
356
SaveGlobalPersisitentVariables()357 bool CFX_GlobalData::SaveGlobalPersisitentVariables() {
358 if (!m_pDelegate)
359 return false;
360
361 uint32_t nCount = 0;
362 BinaryBuffer sData;
363 for (const auto& pElement : m_arrayGlobalData) {
364 if (!pElement->bPersistent)
365 continue;
366
367 BinaryBuffer sElement;
368 if (!MakeByteString(pElement->data.sKey, pElement->data, &sElement))
369 continue;
370
371 if (sData.GetSize() + sElement.GetSize() > kMaxGlobalDataBytes)
372 break;
373
374 sData.AppendSpan(sElement.GetSpan());
375 nCount++;
376 }
377
378 BinaryBuffer sFile;
379 sFile.AppendUint16(kMagic);
380 sFile.AppendUint16(kMaxVersion);
381 sFile.AppendUint32(nCount);
382
383 uint32_t dwSize = pdfium::base::checked_cast<uint32_t>(sData.GetSize());
384 sFile.AppendUint32(dwSize);
385 sFile.AppendSpan(sData.GetSpan());
386
387 CRYPT_ArcFourCryptBlock(sFile.GetMutableSpan(), kRC4KEY);
388 return m_pDelegate->StoreBuffer(sFile.GetSpan());
389 }
390
391 CFX_GlobalData::Element::Element() = default;
392
393 CFX_GlobalData::Element::~Element() = default;
394