1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "package_file.h"
17
18 #include <fstream>
19
20 #include "db_errno.h"
21 #include "value_hash_calc.h"
22 #include "parcel.h"
23 #include "platform_specific.h"
24
25 namespace DistributedDB {
26 using std::string;
27 using std::vector;
28 using std::list;
29 using std::ifstream;
30 using std::ofstream;
31 using std::ios;
32 using std::ios_base;
33
34 namespace {
35 constexpr uint32_t MAX_FILE_NAME_LEN = 256;
36 constexpr uint32_t CHECKSUM_LEN = SHA256_DIGEST_LENGTH;
37 constexpr uint32_t CHECKSUM_BLOCK_SIZE = 64;
38 constexpr uint32_t DEVICE_ID_LEN = SHA256_DIGEST_LENGTH;
39 constexpr uint32_t MAGIC_LEN = 16;
40 constexpr uint32_t CURRENT_VERSION = 0;
41 constexpr uint64_t BUFFER_LEN = 4096;
42 const string MAGIC = "HW package file";
43 const string FILE_SEPARATOR = "/";
44 const string INVALID_FILE_WORDS = "..";
45
46 const uint32_t FILE_HEADER_LEN = MAGIC_LEN + CHECKSUM_LEN + DEVICE_ID_LEN + Parcel::GetUInt32Len() * 3;
47 const uint32_t FILE_CONTEXT_LEN = MAX_FILE_NAME_LEN + Parcel::GetUInt32Len() * 2 + Parcel::GetUInt64Len() * 2;
48 }
49
50 struct FileContext {
51 char fileName[MAX_FILE_NAME_LEN] = {0};
52 uint32_t fileType = 0;
53 uint32_t parentID = 0;
54 uint64_t fileLen = 0;
55 uint64_t offset = 0;
56 };
57
Clear(ofstream & target,const string & targetFile)58 static void Clear(ofstream &target, const string &targetFile)
59 {
60 if (target.is_open()) {
61 target.close();
62 }
63 if (OS::RemoveFile(targetFile.c_str()) != E_OK) {
64 LOGE("Remove file failed.");
65 }
66 return;
67 }
68
GetChecksum(const string & file,vector<char> & result)69 static int GetChecksum(const string &file, vector<char> &result)
70 {
71 ifstream fileHandle(file, ios::in | ios::binary);
72 if (!fileHandle.good()) {
73 LOGE("[GetChecksum]Error fileHandle!");
74 return -E_INVALID_PATH;
75 }
76 ValueHashCalc calc;
77 int errCode = calc.Initialize();
78 if (errCode != E_OK) {
79 LOGE("[GetChecksum]Calc Initialize fail!");
80 return errCode;
81 }
82 fileHandle.seekg(static_cast<int64_t>(MAGIC_LEN + Parcel::GetUInt32Len() + CHECKSUM_LEN), ios_base::beg);
83 vector<uint8_t> buffer(CHECKSUM_BLOCK_SIZE, 0);
84 bool readEnd = false;
85 while (!readEnd) {
86 fileHandle.read(reinterpret_cast<char *>(buffer.data()), buffer.size());
87 if (fileHandle.eof()) {
88 readEnd = true;
89 } else if (!fileHandle.good()) {
90 LOGE("[GetChecksum]fileHandle error!");
91 return -E_INVALID_PATH;
92 }
93 errCode = calc.Update(buffer);
94 if (errCode != E_OK) {
95 LOGE("[GetChecksum]Calc Update fail!");
96 return errCode;
97 }
98 buffer.assign(CHECKSUM_BLOCK_SIZE, 0);
99 }
100 vector<uint8_t> resultBuf;
101 errCode = calc.GetResult(resultBuf);
102 if (errCode != E_OK) {
103 LOGE("[GetChecksum]Calc GetResult fail!");
104 return errCode;
105 }
106 result.assign(resultBuf.begin(), resultBuf.end());
107 return E_OK;
108 }
109
GetFileContexts(const string & sourcePath,list<FileContext> & fileContexts)110 static int GetFileContexts(const string &sourcePath, list<FileContext> &fileContexts)
111 {
112 list<OS::FileAttr> files;
113 int errCode = OS::GetFileAttrFromPath(sourcePath, files, false);
114 if (errCode != E_OK) {
115 LOGE("[GetFileContexts] get file attr from path fail, errCode = [%d]", errCode);
116 return errCode;
117 }
118 FileContext fileContext;
119 int countLimit = 0;
120 for (auto file = files.begin(); file != files.end(); file++, countLimit++) {
121 if (countLimit > 20) { // Limit number of files 20 for security
122 LOGE("Too deep access for get file context!");
123 return -E_INVALID_PATH;
124 }
125
126 if (file->fileType != OS::FILE && file->fileType != OS::PATH) {
127 continue;
128 }
129
130 errCode = memset_s(fileContext.fileName, MAX_FILE_NAME_LEN, 0, MAX_FILE_NAME_LEN);
131 if (errCode != EOK) {
132 return -E_SECUREC_ERROR;
133 }
134
135 if (file->fileName.size() >= MAX_FILE_NAME_LEN) {
136 LOGE("file name is too long!");
137 return -E_INVALID_FILE;
138 }
139
140 errCode = memcpy_s(fileContext.fileName, MAX_FILE_NAME_LEN, file->fileName.c_str(), file->fileName.size());
141 if (errCode != EOK) {
142 return -E_SECUREC_ERROR;
143 }
144
145 fileContext.fileLen = file->fileLen;
146 fileContext.fileType = file->fileType;
147 fileContexts.push_back(fileContext);
148 }
149 LOGD("Get file contexts, fileContexts size is [%zu]", fileContexts.size());
150 return E_OK;
151 }
152
FileContentCopy(ifstream & sourceFile,ofstream & targetFile,uint64_t fileLen)153 static int FileContentCopy(ifstream &sourceFile, ofstream &targetFile, uint64_t fileLen)
154 {
155 uint64_t leftLen = fileLen;
156 vector<char> buffer(BUFFER_LEN, 0);
157 while (leftLen > 0) {
158 uint64_t readLen = (leftLen > BUFFER_LEN) ? BUFFER_LEN : leftLen;
159 sourceFile.read(buffer.data(), readLen);
160 if (!sourceFile.good()) {
161 LOGE("[FileContentCopy] SourceFile error! sys[%d]", errno);
162 return -E_INVALID_PATH;
163 }
164 targetFile.write(buffer.data(), readLen);
165 if (!targetFile.good()) {
166 LOGE("[FileContentCopy] TargetFile error! sys[%d]", errno);
167 return -E_INVALID_PATH;
168 }
169 leftLen -= readLen;
170 }
171 return E_OK;
172 }
173
PackFileHeader(ofstream & targetFile,const FileInfo & fileInfo,uint32_t fileNum)174 static int PackFileHeader(ofstream &targetFile, const FileInfo &fileInfo, uint32_t fileNum)
175 {
176 if (fileInfo.deviceID.size() != DEVICE_ID_LEN) {
177 return -E_INVALID_ARGS;
178 }
179 vector<uint8_t> buffer(FILE_HEADER_LEN, 0);
180 vector<char> checksum(CHECKSUM_LEN, 0);
181 Parcel parcel(buffer.data(), FILE_HEADER_LEN);
182
183 int errCode = parcel.WriteBlob(MAGIC.c_str(), MAGIC_LEN);
184 if (errCode != E_OK) {
185 return errCode;
186 }
187 // before current version package version is always 0
188 errCode = parcel.WriteUInt32(CURRENT_VERSION);
189 if (errCode != E_OK) {
190 return errCode;
191 }
192 errCode = parcel.WriteBlob(checksum.data(), CHECKSUM_LEN);
193 if (errCode != E_OK) {
194 return errCode;
195 }
196 errCode = parcel.WriteBlob(fileInfo.deviceID.c_str(), DEVICE_ID_LEN);
197 if (errCode != E_OK) {
198 return errCode;
199 }
200 errCode = parcel.WriteUInt32(fileInfo.dbType);
201 if (errCode != E_OK) {
202 return errCode;
203 }
204 errCode = parcel.WriteUInt32(fileNum);
205 if (errCode != E_OK) {
206 return errCode;
207 }
208 targetFile.write(reinterpret_cast<char *>(buffer.data()), buffer.size());
209 if (!targetFile.good()) {
210 return -E_INVALID_PATH;
211 }
212 return E_OK;
213 }
214
CheckMagicHeader(Parcel & fileHeaderParcel)215 static int CheckMagicHeader(Parcel &fileHeaderParcel)
216 {
217 vector<char> buffer(MAGIC_LEN, 0);
218 (void)fileHeaderParcel.ReadBlob(buffer.data(), MAGIC_LEN);
219 if (fileHeaderParcel.IsError()) {
220 LOGE("[CheckMagicHeader]fileHeaderParcel error!");
221 return -E_PARSE_FAIL;
222 }
223 if (memcmp(MAGIC.c_str(), buffer.data(), MAGIC_LEN) != 0) {
224 return -E_INVALID_FILE;
225 }
226 return E_OK;
227 }
228
UnpackFileHeader(ifstream & sourceFile,const string & sourceFileName,FileInfo & fileInfo,uint32_t & fileNum)229 static int UnpackFileHeader(ifstream &sourceFile, const string &sourceFileName, FileInfo &fileInfo, uint32_t &fileNum)
230 {
231 vector<uint8_t> fileHeader(FILE_HEADER_LEN, 0);
232 sourceFile.read(reinterpret_cast<char *>(fileHeader.data()), FILE_HEADER_LEN);
233 if (!sourceFile.good()) {
234 LOGE("UnpackFileHeader sourceFile error!");
235 return -E_INVALID_FILE;
236 }
237 Parcel parcel(fileHeader.data(), FILE_HEADER_LEN);
238 int errCode = CheckMagicHeader(parcel);
239 if (errCode != E_OK) {
240 return errCode;
241 }
242 uint32_t version;
243 vector<char> buffer(CHECKSUM_LEN, 0);
244 (void)parcel.ReadUInt32(version);
245 (void)parcel.ReadBlob(buffer.data(), CHECKSUM_LEN);
246 if (parcel.IsError()) {
247 LOGE("UnpackFileHeader parcel version error!");
248 return -E_PARSE_FAIL;
249 }
250 vector<char> checksum(CHECKSUM_LEN, 0);
251 errCode = GetChecksum(sourceFileName, checksum);
252 if (errCode != E_OK) {
253 LOGE("Get checksum failed.");
254 return errCode;
255 }
256 if (buffer != checksum) {
257 LOGE("Checksum check failed.");
258 return -E_INVALID_FILE;
259 }
260 buffer.resize(DEVICE_ID_LEN);
261 (void)parcel.ReadBlob(buffer.data(), DEVICE_ID_LEN);
262 if (parcel.IsError()) {
263 return -E_PARSE_FAIL;
264 }
265 fileInfo.deviceID.resize(DEVICE_ID_LEN);
266 fileInfo.deviceID.assign(buffer.begin(), buffer.end());
267 (void)parcel.ReadUInt32(fileInfo.dbType);
268 (void)parcel.ReadUInt32(fileNum);
269 if (parcel.IsError()) {
270 LOGE("UnpackFileHeader parcel dbType error!");
271 return -E_PARSE_FAIL;
272 }
273 return E_OK;
274 }
275
PackFileContext(ofstream & targetFile,const FileContext & fileContext)276 static int PackFileContext(ofstream &targetFile, const FileContext &fileContext)
277 {
278 vector<uint8_t> buffer(FILE_CONTEXT_LEN, 0);
279 Parcel parcel(buffer.data(), FILE_CONTEXT_LEN);
280 int errCode = parcel.WriteBlob(fileContext.fileName, MAX_FILE_NAME_LEN);
281 if (errCode != E_OK) {
282 LOGE("PackFileContext fileContext fileName error!");
283 return errCode;
284 }
285 errCode = parcel.WriteUInt32(fileContext.fileType);
286 if (errCode != E_OK) {
287 return errCode;
288 }
289 errCode = parcel.WriteUInt32(0);
290 if (errCode != E_OK) {
291 return errCode;
292 }
293 errCode = parcel.WriteUInt64(fileContext.fileLen);
294 if (errCode != E_OK) {
295 return errCode;
296 }
297 errCode = parcel.WriteUInt64(fileContext.offset);
298 if (errCode != E_OK) {
299 return errCode;
300 }
301 targetFile.write(reinterpret_cast<char *>(buffer.data()), buffer.size());
302 if (!targetFile.good()) {
303 return -E_INVALID_PATH;
304 }
305 return E_OK;
306 }
307
UnpackFileContext(ifstream & sourceFile,FileContext & fileContext)308 static int UnpackFileContext(ifstream &sourceFile, FileContext &fileContext)
309 {
310 vector<uint8_t> buffer(FILE_CONTEXT_LEN, 0);
311 sourceFile.read(reinterpret_cast<char *>(buffer.data()), buffer.size());
312 if (!sourceFile.good()) {
313 return -E_INVALID_PATH;
314 }
315 Parcel parcel(buffer.data(), FILE_CONTEXT_LEN);
316 (void)parcel.ReadBlob(fileContext.fileName, MAX_FILE_NAME_LEN);
317 (void)parcel.ReadUInt32(fileContext.fileType);
318 (void)parcel.ReadUInt32(fileContext.parentID);
319 (void)parcel.ReadUInt64(fileContext.fileLen);
320 (void)parcel.ReadUInt64(fileContext.offset);
321 if (parcel.IsError()) {
322 return -E_PARSE_FAIL;
323 }
324 return E_OK;
325 }
326
PackFileContent(ofstream & targetFile,const string & sourcePath,const FileContext & fileContext)327 static int PackFileContent(ofstream &targetFile, const string &sourcePath, const FileContext &fileContext)
328 {
329 if (fileContext.fileType != OS::FILE) {
330 return E_OK;
331 }
332 string fileName = sourcePath + fileContext.fileName;
333 ifstream file(fileName, ios::in | ios::binary);
334 if (!file.good()) {
335 LOGE("[PackFileContent] File error! sys[%d]", errno);
336 return -E_INVALID_PATH;
337 }
338 file.seekg(0, ios_base::end);
339 if (!file.good()) {
340 LOGE("[PackFileContent]file error after seekg! sys[%d]", errno);
341 return -E_INVALID_PATH;
342 }
343 if (file.tellg() < 0) {
344 LOGE("[PackFileContent]file error after tellg! sys[%d]", errno);
345 return -E_INVALID_PATH;
346 }
347 uint64_t fileLen = static_cast<uint64_t>(file.tellg());
348 file.seekg(0, ios_base::beg);
349 if (!file.good()) {
350 LOGE("[PackFileContent]file error after seekg fileLen! sys[%d]", errno);
351 return -E_INVALID_PATH;
352 }
353
354 return FileContentCopy(file, targetFile, fileLen);
355 }
356
UnpackFileContent(ifstream & sourceFile,const string & targetPath,const FileContext & fileContext)357 static int UnpackFileContent(ifstream &sourceFile, const string &targetPath, const FileContext &fileContext)
358 {
359 if (fileContext.fileType != OS::FILE) {
360 return E_OK;
361 }
362
363 string fileName = fileContext.fileName;
364 fileName = targetPath + FILE_SEPARATOR + fileName;
365
366 // check if fileName contains the words ".."
367 std::string::size_type pos = fileName.find(INVALID_FILE_WORDS);
368 if (pos != std::string::npos) {
369 LOGE("[UnpackFileContent]fileName contains the words double dot!!!");
370 return -E_INVALID_PATH;
371 }
372
373 ofstream file(fileName, ios::out | ios::binary);
374 if (!file.good()) {
375 file.close();
376 LOGE("[UnpackFileContent]Get checksum failed.");
377 return -E_INVALID_PATH;
378 }
379 int errCode = FileContentCopy(sourceFile, file, fileContext.fileLen);
380 file.close();
381 return errCode;
382 }
383
WriteChecksum(const string & targetFile)384 static int WriteChecksum(const string &targetFile)
385 {
386 vector<char> checksum(CHECKSUM_LEN, 0);
387 int errCode = GetChecksum(targetFile, checksum);
388 if (errCode != E_OK) {
389 LOGE("Get checksum failed.");
390 return errCode;
391 }
392 ofstream targetHandle(targetFile, ios::in | ios::out | ios::binary);
393 if (!targetHandle.good()) {
394 Clear(targetHandle, targetFile);
395 LOGE("[WriteChecksum]targetHandle error, sys err [%d]", errno);
396 return -E_INVALID_PATH;
397 }
398 targetHandle.seekp(static_cast<int64_t>(MAGIC_LEN + Parcel::GetUInt32Len()), ios_base::beg);
399 if (!targetHandle.good()) {
400 Clear(targetHandle, targetFile);
401 LOGE("[WriteChecksum]targetHandle error after seekp, sys err [%d]", errno);
402 return -E_INVALID_PATH;
403 }
404 targetHandle.write(checksum.data(), checksum.size());
405 if (!targetHandle.good()) {
406 Clear(targetHandle, targetFile);
407 LOGE("[WriteChecksum]targetHandle error after write, sys err [%d]", errno);
408 return -E_INVALID_PATH;
409 }
410 targetHandle.close();
411 return E_OK;
412 }
413
CopyFilePermissions(const string & sourceFile,const string & targetFile)414 static int CopyFilePermissions(const string &sourceFile, const string &targetFile)
415 {
416 uint32_t permissions;
417 int errCode = OS::GetFilePermissions(sourceFile, permissions);
418 if (errCode != E_OK) {
419 LOGE("Get file permissions failed.");
420 return errCode;
421 }
422 errCode = OS::SetFilePermissions(targetFile, permissions);
423 if (errCode != E_OK) {
424 LOGE("Set file permissions failed.");
425 }
426 return errCode;
427 }
428
PackageFiles(const string & sourcePath,const string & targetFile,const FileInfo & fileInfo)429 int PackageFile::PackageFiles(const string &sourcePath, const string &targetFile,
430 const FileInfo &fileInfo)
431 {
432 int errCode = ExePackage(sourcePath, targetFile, fileInfo);
433 if (errno == EKEYREVOKED) {
434 errCode = -E_EKEYREVOKED;
435 LOGE("[PackageFile][PackageFiles] Forbid access files errCode [%d].", errCode);
436 }
437 return errCode;
438 }
439
GetPackageVersion(const std::string & sourceFile,uint32_t & version)440 int PackageFile::GetPackageVersion(const std::string &sourceFile, uint32_t &version)
441 {
442 int errCode = E_OK;
443 vector<uint8_t> fileHeader(FILE_HEADER_LEN, 0);
444 Parcel parcel(fileHeader.data(), FILE_HEADER_LEN);
445
446 ifstream sourceHandle(sourceFile, ios::in | ios::binary);
447 if (!sourceHandle.good()) {
448 LOGE("sourceHandle error, sys err [%d]", errno);
449 errCode = -E_INVALID_PATH;
450 goto END;
451 }
452
453 sourceHandle.read(reinterpret_cast<char *>(fileHeader.data()), FILE_HEADER_LEN);
454 if (!sourceHandle.good()) {
455 LOGE("GetPackageVersion read sourceFile handle error!");
456 errCode = -E_INVALID_PATH;
457 goto END;
458 }
459
460 errCode = CheckMagicHeader(parcel);
461 if (errCode != E_OK) {
462 errCode = -E_INVALID_PATH;
463 goto END;
464 }
465
466 (void)parcel.ReadUInt32(version);
467 END:
468 if (errno == EKEYREVOKED) {
469 errCode = -E_EKEYREVOKED;
470 LOGE("[PackageFile][PackageFiles] Forbid access files by secLabel, errCode [%d].", errCode);
471 }
472 return errCode;
473 }
474
ExePackage(const string & sourcePath,const string & targetFile,const FileInfo & fileInfo)475 int PackageFile::ExePackage(const string &sourcePath, const string &targetFile,
476 const FileInfo &fileInfo)
477 {
478 list<FileContext> fileContexts;
479 int errCode = GetFileContexts(sourcePath, fileContexts);
480 if (errCode != E_OK) {
481 return errCode;
482 }
483 if (fileContexts.empty()) {
484 return -E_EMPTY_PATH;
485 }
486 bool targetExists = OS::CheckPathExistence(targetFile);
487 ofstream targetHandle(targetFile, ios::out | ios::binary);
488 if (!targetHandle.good()) {
489 Clear(targetHandle, targetFile);
490 LOGE("[PackageFiles]targetHandle error, sys err [%d], [%zu]", errno, fileContexts.size());
491 return -E_INVALID_PATH;
492 }
493
494 if (!targetExists) {
495 errCode = CopyFilePermissions(sourcePath + FILE_SEPARATOR + string(fileContexts.front().fileName), targetFile);
496 if (errCode != E_OK) {
497 LOGE("Copy file fail when execute pack files! errCode = [%d]", errCode);
498 Clear(targetHandle, targetFile);
499 return errCode;
500 }
501 }
502
503 errCode = PackFileHeader(targetHandle, fileInfo, static_cast<uint32_t>(fileContexts.size()));
504 if (errCode != E_OK) {
505 Clear(targetHandle, targetFile);
506 LOGE("[PackageFiles]Pack file header err[%d]!!!", errCode);
507 return errCode;
508 }
509 // FILE_HEADER_LEN is 92, FILE_CONTEXT_LEN is 280, fileContexts.size() < UINT_MAX, the offset will never overflow.
510 uint64_t offset = FILE_HEADER_LEN + FILE_CONTEXT_LEN * static_cast<uint64_t>(fileContexts.size());
511 for (auto &file : fileContexts) {
512 file.offset = offset;
513 errCode = PackFileContext(targetHandle, file);
514 if (errCode != E_OK) {
515 Clear(targetHandle, targetFile);
516 LOGE("[PackageFiles]Pack file context err[%d]!!!", errCode);
517 return errCode;
518 }
519 offset += file.fileLen;
520 }
521 for (const auto &file : fileContexts) {
522 // If file type is path no need pack content in PackFileContent
523 errCode = PackFileContent(targetHandle, sourcePath, file);
524 if (errCode != E_OK) {
525 Clear(targetHandle, targetFile);
526 return errCode;
527 }
528 }
529 targetHandle.close();
530 return WriteChecksum(targetFile);
531 }
532
UnpackFile(const string & sourceFile,const string & targetPath,FileInfo & fileInfo)533 int PackageFile::UnpackFile(const string &sourceFile, const string &targetPath, FileInfo &fileInfo)
534 {
535 ifstream sourceHandle(sourceFile, ios::in | ios::binary);
536 if (!sourceHandle.good()) {
537 LOGE("sourceHandle error, sys err [%d]", errno);
538 return -E_INVALID_PATH;
539 }
540 uint32_t fileNum;
541 int errCode = UnpackFileHeader(sourceHandle, sourceFile, fileInfo, fileNum);
542 if (errCode != E_OK) {
543 return errCode;
544 }
545 FileContext fileContext;
546 list<FileContext> fileContexts;
547 sourceHandle.seekg(static_cast<int64_t>(FILE_HEADER_LEN), ios_base::beg);
548 if (!sourceHandle.good()) {
549 return -E_INVALID_PATH;
550 }
551 for (uint32_t fileCount = 0; fileCount < fileNum; fileCount++) {
552 errCode = UnpackFileContext(sourceHandle, fileContext);
553 if (errCode != E_OK) {
554 return errCode;
555 }
556 fileContexts.push_back(fileContext);
557 }
558
559 for (const auto &file : fileContexts) {
560 if (file.fileType == OS::PATH) {
561 std::string dirPath = targetPath + "/" + std::string(file.fileName);
562 if (!OS::CheckPathExistence(dirPath) && OS::MakeDBDirectory(dirPath) != E_OK) {
563 return -E_SYSTEM_API_FAIL;
564 }
565 continue;
566 }
567 errCode = UnpackFileContent(sourceHandle, targetPath, file);
568 if (errCode != E_OK) {
569 return errCode;
570 }
571 }
572 return E_OK;
573 }
574 }
575