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 break;
79 }
80 return false;
81 }
82
83 } // namespace
84
85 // static
GetRetainedInstance(Delegate * pDelegate)86 CFX_GlobalData* CFX_GlobalData::GetRetainedInstance(Delegate* pDelegate) {
87 if (!g_pInstance) {
88 g_pInstance = new CFX_GlobalData(pDelegate);
89 }
90 ++g_pInstance->m_RefCount;
91 return g_pInstance;
92 }
93
Release()94 bool CFX_GlobalData::Release() {
95 if (--m_RefCount)
96 return false;
97
98 delete g_pInstance;
99 g_pInstance = nullptr;
100 return true;
101 }
102
CFX_GlobalData(Delegate * pDelegate)103 CFX_GlobalData::CFX_GlobalData(Delegate* pDelegate) : m_pDelegate(pDelegate) {
104 LoadGlobalPersistentVariables();
105 }
106
~CFX_GlobalData()107 CFX_GlobalData::~CFX_GlobalData() {
108 SaveGlobalPersisitentVariables();
109 }
110
FindGlobalVariable(const ByteString & propname)111 CFX_GlobalData::iterator CFX_GlobalData::FindGlobalVariable(
112 const ByteString& propname) {
113 for (auto it = m_arrayGlobalData.begin(); it != m_arrayGlobalData.end();
114 ++it) {
115 if ((*it)->data.sKey == propname)
116 return it;
117 }
118 return m_arrayGlobalData.end();
119 }
120
GetGlobalVariable(const ByteString & propname)121 CFX_GlobalData::Element* CFX_GlobalData::GetGlobalVariable(
122 const ByteString& propname) {
123 auto iter = FindGlobalVariable(propname);
124 return iter != m_arrayGlobalData.end() ? iter->get() : nullptr;
125 }
126
SetGlobalVariableNumber(ByteString sPropName,double dData)127 void CFX_GlobalData::SetGlobalVariableNumber(ByteString sPropName,
128 double dData) {
129 if (!TrimPropName(&sPropName))
130 return;
131
132 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
133 if (pData) {
134 pData->data.nType = CFX_Value::DataType::kNumber;
135 pData->data.dData = dData;
136 return;
137 }
138 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
139 pNewData->data.sKey = std::move(sPropName);
140 pNewData->data.nType = CFX_Value::DataType::kNumber;
141 pNewData->data.dData = dData;
142 m_arrayGlobalData.push_back(std::move(pNewData));
143 }
144
SetGlobalVariableBoolean(ByteString sPropName,bool bData)145 void CFX_GlobalData::SetGlobalVariableBoolean(ByteString sPropName,
146 bool bData) {
147 if (!TrimPropName(&sPropName))
148 return;
149
150 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
151 if (pData) {
152 pData->data.nType = CFX_Value::DataType::kBoolean;
153 pData->data.bData = bData;
154 return;
155 }
156 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
157 pNewData->data.sKey = std::move(sPropName);
158 pNewData->data.nType = CFX_Value::DataType::kBoolean;
159 pNewData->data.bData = bData;
160 m_arrayGlobalData.push_back(std::move(pNewData));
161 }
162
SetGlobalVariableString(ByteString sPropName,const ByteString & sData)163 void CFX_GlobalData::SetGlobalVariableString(ByteString sPropName,
164 const ByteString& sData) {
165 if (!TrimPropName(&sPropName))
166 return;
167
168 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
169 if (pData) {
170 pData->data.nType = CFX_Value::DataType::kString;
171 pData->data.sData = sData;
172 return;
173 }
174 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
175 pNewData->data.sKey = std::move(sPropName);
176 pNewData->data.nType = CFX_Value::DataType::kString;
177 pNewData->data.sData = sData;
178 m_arrayGlobalData.push_back(std::move(pNewData));
179 }
180
SetGlobalVariableObject(ByteString sPropName,std::vector<std::unique_ptr<CFX_KeyValue>> array)181 void CFX_GlobalData::SetGlobalVariableObject(
182 ByteString sPropName,
183 std::vector<std::unique_ptr<CFX_KeyValue>> array) {
184 if (!TrimPropName(&sPropName))
185 return;
186
187 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
188 if (pData) {
189 pData->data.nType = CFX_Value::DataType::kObject;
190 pData->data.objData = std::move(array);
191 return;
192 }
193 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
194 pNewData->data.sKey = std::move(sPropName);
195 pNewData->data.nType = CFX_Value::DataType::kObject;
196 pNewData->data.objData = std::move(array);
197 m_arrayGlobalData.push_back(std::move(pNewData));
198 }
199
SetGlobalVariableNull(ByteString sPropName)200 void CFX_GlobalData::SetGlobalVariableNull(ByteString sPropName) {
201 if (!TrimPropName(&sPropName))
202 return;
203
204 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
205 if (pData) {
206 pData->data.nType = CFX_Value::DataType::kNull;
207 return;
208 }
209 auto pNewData = std::make_unique<CFX_GlobalData::Element>();
210 pNewData->data.sKey = std::move(sPropName);
211 pNewData->data.nType = CFX_Value::DataType::kNull;
212 m_arrayGlobalData.push_back(std::move(pNewData));
213 }
214
SetGlobalVariablePersistent(ByteString sPropName,bool bPersistent)215 bool CFX_GlobalData::SetGlobalVariablePersistent(ByteString sPropName,
216 bool bPersistent) {
217 if (!TrimPropName(&sPropName))
218 return false;
219
220 CFX_GlobalData::Element* pData = GetGlobalVariable(sPropName);
221 if (!pData)
222 return false;
223
224 pData->bPersistent = bPersistent;
225 return true;
226 }
227
DeleteGlobalVariable(ByteString sPropName)228 bool CFX_GlobalData::DeleteGlobalVariable(ByteString sPropName) {
229 if (!TrimPropName(&sPropName))
230 return false;
231
232 auto iter = FindGlobalVariable(sPropName);
233 if (iter == m_arrayGlobalData.end())
234 return false;
235
236 m_arrayGlobalData.erase(iter);
237 return true;
238 }
239
GetSize() const240 int32_t CFX_GlobalData::GetSize() const {
241 return fxcrt::CollectionSize<int32_t>(m_arrayGlobalData);
242 }
243
GetAt(int index)244 CFX_GlobalData::Element* CFX_GlobalData::GetAt(int index) {
245 if (index < 0 || index >= GetSize())
246 return nullptr;
247 return m_arrayGlobalData[index].get();
248 }
249
LoadGlobalPersistentVariables()250 bool CFX_GlobalData::LoadGlobalPersistentVariables() {
251 if (!m_pDelegate)
252 return false;
253
254 bool ret;
255 {
256 // Span can't outlive call to BufferDone().
257 absl::optional<pdfium::span<uint8_t>> buffer = m_pDelegate->LoadBuffer();
258 if (!buffer.has_value() || buffer.value().empty())
259 return false;
260
261 ret = LoadGlobalPersistentVariablesFromBuffer(buffer.value());
262 }
263 m_pDelegate->BufferDone();
264 return ret;
265 }
266
LoadGlobalPersistentVariablesFromBuffer(pdfium::span<uint8_t> buffer)267 bool CFX_GlobalData::LoadGlobalPersistentVariablesFromBuffer(
268 pdfium::span<uint8_t> buffer) {
269 if (buffer.size() < kMinGlobalDataBytes)
270 return false;
271
272 CRYPT_ArcFourCryptBlock(buffer, kRC4KEY);
273
274 uint8_t* p = buffer.data();
275 uint16_t wType = *((uint16_t*)p);
276 p += sizeof(uint16_t);
277 if (wType != kMagic)
278 return false;
279
280 uint16_t wVersion = *((uint16_t*)p);
281 p += sizeof(uint16_t);
282 if (wVersion > kMaxVersion)
283 return false;
284
285 uint32_t dwCount = *((uint32_t*)p);
286 p += sizeof(uint32_t);
287
288 uint32_t dwSize = *((uint32_t*)p);
289 p += sizeof(uint32_t);
290
291 if (dwSize != buffer.size() - sizeof(uint16_t) * 2 - sizeof(uint32_t) * 2)
292 return false;
293
294 for (int32_t i = 0, sz = dwCount; i < sz; i++) {
295 if (p + sizeof(uint32_t) >= buffer.end()) {
296 break;
297 }
298
299 uint32_t dwNameLen = 0;
300 memcpy(&dwNameLen, p, sizeof(uint32_t));
301 p += sizeof(uint32_t);
302 if (p + dwNameLen > buffer.end())
303 break;
304
305 ByteString sEntry = ByteString(p, dwNameLen);
306 p += sizeof(char) * dwNameLen;
307
308 uint16_t wDataType = 0;
309 memcpy(&wDataType, p, sizeof(uint16_t));
310 p += sizeof(uint16_t);
311
312 CFX_Value::DataType eDataType = static_cast<CFX_Value::DataType>(wDataType);
313
314 switch (eDataType) {
315 case CFX_Value::DataType::kNumber: {
316 double dData = 0;
317 switch (wVersion) {
318 case 1: {
319 uint32_t dwData = 0;
320 memcpy(&dwData, p, sizeof(uint32_t));
321 p += sizeof(uint32_t);
322 dData = dwData;
323 } break;
324 case 2: {
325 dData = 0;
326 memcpy(&dData, p, sizeof(double));
327 p += sizeof(double);
328 } break;
329 }
330 SetGlobalVariableNumber(sEntry, dData);
331 SetGlobalVariablePersistent(sEntry, true);
332 } break;
333 case CFX_Value::DataType::kBoolean: {
334 uint16_t wData = 0;
335 memcpy(&wData, p, sizeof(uint16_t));
336 p += sizeof(uint16_t);
337 SetGlobalVariableBoolean(sEntry, (bool)(wData == 1));
338 SetGlobalVariablePersistent(sEntry, true);
339 } break;
340 case CFX_Value::DataType::kString: {
341 uint32_t dwLength = 0;
342 memcpy(&dwLength, p, sizeof(uint32_t));
343 p += sizeof(uint32_t);
344 if (p + dwLength > buffer.end())
345 break;
346
347 SetGlobalVariableString(sEntry, ByteString(p, dwLength));
348 SetGlobalVariablePersistent(sEntry, true);
349 p += sizeof(char) * dwLength;
350 } break;
351 case CFX_Value::DataType::kNull: {
352 SetGlobalVariableNull(sEntry);
353 SetGlobalVariablePersistent(sEntry, true);
354 } break;
355 case CFX_Value::DataType::kObject:
356 // Arrays aren't allowed in these buffers, nor are unrecognized tags.
357 return false;
358 }
359 }
360 return true;
361 }
362
SaveGlobalPersisitentVariables()363 bool CFX_GlobalData::SaveGlobalPersisitentVariables() {
364 if (!m_pDelegate)
365 return false;
366
367 uint32_t nCount = 0;
368 BinaryBuffer sData;
369 for (const auto& pElement : m_arrayGlobalData) {
370 if (!pElement->bPersistent)
371 continue;
372
373 BinaryBuffer sElement;
374 if (!MakeByteString(pElement->data.sKey, pElement->data, &sElement))
375 continue;
376
377 if (sData.GetSize() + sElement.GetSize() > kMaxGlobalDataBytes)
378 break;
379
380 sData.AppendSpan(sElement.GetSpan());
381 nCount++;
382 }
383
384 BinaryBuffer sFile;
385 sFile.AppendUint16(kMagic);
386 sFile.AppendUint16(kMaxVersion);
387 sFile.AppendUint32(nCount);
388
389 uint32_t dwSize = pdfium::base::checked_cast<uint32_t>(sData.GetSize());
390 sFile.AppendUint32(dwSize);
391 sFile.AppendSpan(sData.GetSpan());
392
393 CRYPT_ArcFourCryptBlock(sFile.GetMutableSpan(), kRC4KEY);
394 return m_pDelegate->StoreBuffer(sFile.GetSpan());
395 }
396
397 CFX_GlobalData::Element::Element() = default;
398
399 CFX_GlobalData::Element::~Element() = default;
400