• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "ptable.h"
17 
18 #include <map>
19 #include <sys/stat.h>
20 
21 #include "applypatch/data_writer.h"
22 #include "log/log.h"
23 #include "securec.h"
24 
25 namespace Updater {
26 constexpr const char *PTABLE_CONFIG_PATH = "/etc/ptable_data.json";
27 constexpr const char *PTABLE_DATA_LABEL = "ptableData";
28 constexpr const char *EMMC_GPT_DATA_LEN_LABEL = "emmcGptDataLen";
29 constexpr const char *LBA_LEN_LABEL = "lbaLen";
30 constexpr const char *GPT_HEADER_LEN_LABEL = "gptHeaderLen";
31 constexpr const char *BLOCK_SIZE_LABEL = "blockSize";
32 constexpr const char *IMG_LUN_SIZE_LABEL = "imgLuSize";
33 constexpr const char *START_LUN_NUM_LABEL = "startLunNumber";
34 constexpr const char *WRITE_DEVICE_LUN_SIZE_LABEL = "writeDeviceLunSize";
35 constexpr const char *DEFAULT_LUN_NUM_LABEL = "defaultLunNum";
36 
GetPtablePartitionInfo() const37 std::vector<Ptable::PtnInfo> Ptable::GetPtablePartitionInfo() const
38 {
39     return partitionInfo_;
40 }
41 
GetPtablePartitionNum() const42 uint32_t Ptable::GetPtablePartitionNum() const
43 {
44     return partitionInfo_.size();
45 }
46 
InitPtable()47 bool Ptable::InitPtable()
48 {
49     if (!partitionInfo_.empty()) {
50         std::vector<PtnInfo>().swap(partitionInfo_);
51     }
52     if (!ParsePtableData()) {
53         LOG(ERROR) << "parse PtableData from json file error";
54         return false;
55     }
56     return true;
57 }
58 
ParsePtableDataNode(const JsonNode & ptableDataNode)59 bool Ptable::ParsePtableDataNode(const JsonNode &ptableDataNode)
60 {
61     std::map<std::string, uint32_t*> ptableDataVars = {
62         {EMMC_GPT_DATA_LEN_LABEL, &ptableData_.emmcGptDataLen},
63         {LBA_LEN_LABEL, &ptableData_.lbaLen},
64         {GPT_HEADER_LEN_LABEL, &ptableData_.gptHeaderLen},
65         {BLOCK_SIZE_LABEL, &ptableData_.blockSize},
66         {IMG_LUN_SIZE_LABEL, &ptableData_.imgLuSize},
67         {START_LUN_NUM_LABEL, &ptableData_.startLunNumber},
68         {WRITE_DEVICE_LUN_SIZE_LABEL, &ptableData_.writeDeviceLunSize},
69         {DEFAULT_LUN_NUM_LABEL, &ptableData_.defaultLunNum},
70     };
71 
72     for (auto dataVar : ptableDataVars) {
73         auto dataValue = ptableDataNode[dataVar.first.c_str()].As<uint32_t>();
74         if (!dataValue) {
75             LOG(ERROR) << "parse json failed! " << dataVar.first << " is nullptr!";
76             return false;
77         }
78         *(dataVar.second) = *dataValue;
79         LOG(INFO) << "set " << dataVar.first << " : " << *dataValue;
80     }
81     return true;
82 }
83 
ParsePtableData()84 bool Ptable::ParsePtableData()
85 {
86     (void)memset_s(&ptableData_, sizeof(ptableData_), 0, sizeof(ptableData_));
87     std::ifstream ifs(std::string {PTABLE_CONFIG_PATH});
88     if (!ifs.is_open()) {
89         LOG(ERROR) << PTABLE_CONFIG_PATH << " not exist";
90         return false;
91     }
92 
93     // get root node
94     std::string content {std::istreambuf_iterator<char> {ifs}, {}};
95     cJSONPtr root(cJSON_Parse(content.c_str()), cJSON_Delete);
96     if (root == nullptr) {
97         LOG(ERROR) << PTABLE_CONFIG_PATH << " contained json invalid";
98         return false;
99     }
100 
101     JsonNode node(root.get(), false);
102     const JsonNode &ptableDataNode = node[PTABLE_DATA_LABEL];
103     bool ret = ParsePtableDataNode(ptableDataNode);
104     ptableData_.dataValid = ret;
105     return ret;
106 }
107 
GetDefaultImageSize() const108 uint32_t Ptable::GetDefaultImageSize() const
109 {
110     return ptableData_.emmcGptDataLen + ptableData_.defaultLunNum * ptableData_.imgLuSize;
111 }
112 
CheckFileExist(const std::string & fileName)113 bool Ptable::CheckFileExist(const std::string &fileName)
114 {
115     struct stat buffers;
116     if (memset_s(&buffers, sizeof(buffers), 0, sizeof(buffers)) != EOK) {
117         LOG(WARNING) << "memset_s fail";
118     }
119     if (stat(fileName.c_str(), &buffers) == 0) {
120         LOG(INFO) << fileName << " is exist";
121         return true;
122     }
123     LOG(INFO) << fileName << " is not exist";
124     return false;
125 }
126 
MemReadWithOffset(const std::string & filePath,const uint64_t offset,uint8_t * outData,const uint32_t dataSize)127 bool Ptable::MemReadWithOffset(const std::string &filePath, const uint64_t offset,
128     uint8_t *outData, const uint32_t dataSize)
129 {
130     if (filePath.length() == 0 || outData == nullptr || dataSize == 0) {
131         LOG(ERROR) << "invaild input";
132         return false;
133     }
134 
135     std::ifstream fin(filePath, std::ios::in);
136     if (fin.fail()) {
137         LOG(ERROR) << "open " << filePath << " fail";
138         return false;
139     }
140 
141     fin.seekg(offset, std::ios::beg);
142     if (fin.tellg() != static_cast<long long>(offset)) {
143         LOG(ERROR) << "seekp 0x" << std::hex << offset << " bytes in " << filePath <<
144             " failed. Now is in 0x" << std::hex << fin.tellg() << std::dec;
145         fin.close();
146         return false;
147     }
148 
149     if (!fin.read(reinterpret_cast<char *>(outData), dataSize)) {
150         LOG(ERROR) << "read 0x" << std::hex << dataSize << " bytes in " << filePath <<
151             " failed. only read 0x" << std::hex << fin.gcount() << std::dec;
152         fin.close();
153         return false;
154     }
155     fin.close();
156     return true;
157 }
158 
Reflect(uint32_t data,const uint32_t len)159 uint32_t Ptable::Reflect(uint32_t data, const uint32_t len)
160 {
161     uint32_t ref = 0;
162     for (uint32_t i = 0; i < len; i++) {
163         if (data & 0x1) {
164             ref |= (1 << ((len - 1) - i));
165         }
166         data = (data >> 1);
167     }
168     return ref;
169 }
170 
CalculateCrc32(const uint8_t * buffer,const uint32_t len)171 uint32_t Ptable::CalculateCrc32(const uint8_t *buffer, const uint32_t len)
172 {
173     if (buffer == nullptr || len == 0) {
174         LOG(INFO) << "invaild input";
175         return 0;
176     }
177     const uint32_t byteLen = 8; // 8:length of unit (i.e. byte)
178     uint32_t msb;
179     const uint64_t polynomial = 0x104C11DB7LL; // IEEE 32bit polynomial
180     uint32_t regs = 0xFFFFFFFF; // init to all ones
181     const uint32_t regsMask = 0xFFFFFFFF; // ensure only 32 bit answer
182     uint32_t regsMsb;
183     for (uint32_t i = 0; i < len; i++) {
184         uint32_t dataByte = buffer[i];
185         dataByte = Reflect(dataByte, 8); // 8:length of unit (i.e. byte)
186         for (uint32_t j = 0; j < byteLen; j++) {
187             msb = dataByte >> (byteLen - 1); // get MSB
188             msb &= 1; // ensure just 1 bit
189             regsMsb = (regs >> 31) & 1; // 31:32-1, MSB of regs
190             regs = regs << 1; // shift regs for CRC-CCITT
191             if (regsMsb ^ msb) { // MSB is a 1
192                 regs = regs ^ polynomial; // XOR with generator poly
193             }
194             regs = regs & regsMask; // Mask off excess upper bits
195             dataByte <<= 1; // get to next bit
196         }
197     }
198     regs = regs & regsMask;
199     uint32_t ret = Reflect(regs, 32) ^ 0xFFFFFFFF; // 32:32bit
200     return ret;
201 }
202 
VerifyMbrMagicNum(const uint8_t * buffer,const uint32_t size)203 bool Ptable::VerifyMbrMagicNum(const uint8_t *buffer, const uint32_t size)
204 {
205     // avoid checking past end of buffer
206     if (size < (MBR_MAGIC_NUM_POS + 1)) {
207         LOG(ERROR) << "size < (TABLE_SIGNATURE + 1)";
208         return false;
209     }
210     // check to see if magic number(0x55AA) exists at pos 0x1FE
211     if ((buffer[MBR_MAGIC_NUM_POS] != MBR_MAGIC_NUM_0) ||
212         (buffer[MBR_MAGIC_NUM_POS + 1] != MBR_MAGIC_NUM_1)) {
213         LOG(ERROR) << "MBR magic number does not match, magic buffer is " << *(buffer + MBR_MAGIC_NUM_POS);
214         return false;
215     }
216     return true;
217 }
218 
CheckProtectiveMbr(const uint8_t * gptImage,const uint32_t imgLen)219 bool Ptable::CheckProtectiveMbr(const uint8_t *gptImage, const uint32_t imgLen)
220 {
221     if (!VerifyMbrMagicNum(gptImage, imgLen)) {
222         LOG(ERROR) << "MBR magic number verify failed!";
223         return false;
224     }
225 
226     // process each of the four partitions in the MBR, find a Protective MBR(0xEE)
227     uint32_t type;
228     for (uint32_t i = 0; i < MBR_GPT_MAX_NUM; i++) {
229         // type 0xEE indicates the protective MBR and GPT partitions exist
230         if (MBR_GPT_ENTRY + i * MBR_GPT_ENTRY_SIZE + GPT_TYPE_SIGN_OFFSET >= imgLen) {
231             LOG(INFO) << "not find Protective MBR(type: 0xEE) in this partition";
232             return false;
233         }
234         type = gptImage[MBR_GPT_ENTRY + i * MBR_GPT_ENTRY_SIZE + GPT_TYPE_SIGN_OFFSET];
235         if (type == MBR_PROTECTIVE_GPT_TYPE) {
236             LOG(INFO) << "type is MBR_PROTECTIVE_GPT_TYPE(0xEE), GPT partitions exist";
237             return true;
238         }
239         LOG(INFO) << "the " << i << " main GPT's type=0x" << std::hex << type << std::dec;
240     }
241     LOG(INFO) << "not find Protective MBR(type: 0xEE) in this partition";
242     return false;
243 }
244 
CheckIfValidGpt(const uint8_t * gptImage,const uint32_t gptImageLen)245 bool Ptable::CheckIfValidGpt(const uint8_t *gptImage, const uint32_t gptImageLen)
246 {
247     // 8 is the length of EFI_MAGIC_NUMBER
248     if (gptImageLen < 8) {
249         LOG(ERROR) << "gptImageLen is less than 8.";
250         return false;
251     }
252     // get magic number
253     uint64_t gptMagic = GET_LLWORD_FROM_BYTE(gptImage);
254     if (gptMagic != EFI_MAGIC_NUMBER) {
255         LOG(ERROR) << "invaild partiton with gptMagic:0x" << std::hex << gptMagic << std::dec;
256         return false;
257     }
258     return true;
259 }
260 
GetCapacity(const std::string & filePath,uint64_t & lunCapacity)261 bool Ptable::GetCapacity(const std::string &filePath, uint64_t &lunCapacity)
262 {
263     if (filePath.empty()) {
264         LOG(ERROR) << "filePath is empty or lunCapacity is nullptr";
265         return false;
266     }
267     std::ifstream fin(filePath, std::ios::in);
268     if (!fin.is_open()) {
269         LOG(ERROR) << "open " << filePath << " fail";
270         return false;
271     }
272 
273     uint64_t sector = 0;
274     fin >> sector;
275     if (sector == 0) {
276         LOG(ERROR) << "read data from " << filePath << " fail";
277         fin.close();
278         return false;
279     }
280 
281     uint64_t capacity = sector * SECTOR_SIZE;
282     LOG(INFO) << "lun capacity = 0x" << std::hex << capacity << std::dec;
283     lunCapacity = capacity;
284     fin.close();
285     return true;
286 }
287 
GetPartitionGptHeaderInfo(const uint8_t * buffer,const uint32_t bufferLen,GPTHeaderInfo & gptHeaderInfo)288 bool Ptable::GetPartitionGptHeaderInfo(const uint8_t *buffer, const uint32_t bufferLen, GPTHeaderInfo& gptHeaderInfo)
289 {
290     if (buffer == nullptr || bufferLen < LBA_LENGTH) {
291         LOG(ERROR) << "input invalid";
292         return false;
293     }
294 
295     // Check GPT Signature
296     if (!CheckIfValidGpt(buffer, bufferLen)) {
297         LOG(ERROR) << "invaild partiton with gptMagic";
298         return false;
299     }
300     gptHeaderInfo.headerSize = GET_LWORD_FROM_BYTE(buffer + HEADER_SIZE_OFFSET);
301     gptHeaderInfo.firstUsableLba = GET_LLWORD_FROM_BYTE(buffer + FIRST_USABLE_LBA_OFFSET);
302     gptHeaderInfo.maxPartitionCount = GET_LWORD_FROM_BYTE(buffer + PARTITION_COUNT_OFFSET);
303     gptHeaderInfo.partitionEntrySize = GET_LWORD_FROM_BYTE(buffer + PENTRY_SIZE_OFFSET);
304     if (gptHeaderInfo.maxPartitionCount == 0 || gptHeaderInfo.partitionEntrySize == 0) {
305         LOG(ERROR) << "invalid gpt header info";
306         return false;
307     }
308     return true;
309 }
310 
CheckGptHeader(uint8_t * buffer,const uint32_t bufferLen,const uint64_t lbaNum,const GPTHeaderInfo & gptHeaderInfo)311 bool Ptable::CheckGptHeader(uint8_t *buffer, const uint32_t bufferLen, const uint64_t lbaNum,
312     const GPTHeaderInfo& gptHeaderInfo)
313 {
314     if (bufferLen < LBA_LENGTH || lbaNum == 0) {
315         LOG(ERROR) << "bufferLen < LBA_LENGTH || lbaNum == 0";
316         return false;
317     }
318 
319     if (gptHeaderInfo.headerSize < GPT_HEADER_SIZE || gptHeaderInfo.headerSize > bufferLen) {
320         LOG(ERROR) << "GPT Header size is invaild";
321         return false;
322     }
323     uint32_t orgCrcVal = GET_LWORD_FROM_BYTE(buffer + HEADER_CRC_OFFSET);
324     // Write CRC field to 0 before calculating the crc of the whole rest of GPT header
325     PUT_LONG(buffer + HEADER_CRC_OFFSET, 0);
326     uint32_t crcVal = CalculateCrc32(buffer, gptHeaderInfo.headerSize);
327     if (crcVal != orgCrcVal) {
328         LOG(ERROR) << "Header crc mismatch crcVal = " << std::hex << crcVal << " with orgCrcVal = " <<
329             orgCrcVal << std::dec;
330         return false;
331     }
332     PUT_LONG(buffer + HEADER_CRC_OFFSET, crcVal);
333 
334     uint32_t currentLba = GET_LLWORD_FROM_BYTE(buffer + PRIMARY_HEADER_OFFSET);
335     uint32_t lastUsableLba = GET_LLWORD_FROM_BYTE(buffer + LAST_USABLE_LBA_OFFSET);
336     uint32_t partition0 = GET_LLWORD_FROM_BYTE(buffer + PARTITION_ENTRIES_OFFSET);
337 
338     // check for first and last lba range
339     if (gptHeaderInfo.firstUsableLba > lbaNum || lastUsableLba > lbaNum) {
340         LOG(ERROR) << "invalid usable lba " << gptHeaderInfo.firstUsableLba << ", last is " << lastUsableLba <<
341             " lbaNum is " << lbaNum;
342         return false;
343     }
344     // check for partition entry size
345     if (gptHeaderInfo.partitionEntrySize != PARTITION_ENTRY_SIZE ||
346         gptHeaderInfo.maxPartitionCount > (MIN_PARTITION_ARRAY_SIZE / PARTITION_ENTRY_SIZE)) {
347         LOG(ERROR) << "invalid parition entry size or max count";
348         return false;
349     }
350     // GPT header should always be the 0x1 LBA, partition entry should always the 0x2 LBA
351     if (currentLba != 0x1 || partition0 != 0x2) {
352         LOG(ERROR) << "starting LBA mismatch";
353         return false;
354     }
355     LOG(INFO) << "ufs gpt header check ok";
356     return true;
357 }
358 
PartitionCheckGptHeader(const uint8_t * gptImage,const uint32_t len,const uint64_t lbaNum,const uint32_t blockSize,const GPTHeaderInfo & gptHeaderInfo)359 bool Ptable::PartitionCheckGptHeader(const uint8_t *gptImage, const uint32_t len, const uint64_t lbaNum,
360     const uint32_t blockSize, const GPTHeaderInfo& gptHeaderInfo)
361 {
362     if (len < ptableData_.writeDeviceLunSize || lbaNum == 0) {
363         LOG(ERROR) << "len < ptableData_.writeDeviceLunSize || lbaNum == 0";
364         return false;
365     }
366 
367     uint8_t *buffer = new(std::nothrow) uint8_t[blockSize]();
368     if (buffer == nullptr) {
369         LOG(ERROR) << "new buffer failed!";
370         return false;
371     }
372     if (memcpy_s(buffer, blockSize, gptImage + blockSize, blockSize) != EOK) {
373         LOG(ERROR) << "copy gpt header fail";
374         delete [] buffer;
375         return false;
376     }
377 
378     if (!CheckGptHeader(buffer, blockSize, lbaNum, gptHeaderInfo)) {
379         LOG(ERROR) << "CheckGptHeader fail";
380         delete [] buffer;
381         return false;
382     }
383 
384     uint32_t partition0 = GET_LLWORD_FROM_BYTE(&buffer[PARTITION_ENTRIES_OFFSET]);
385     uint32_t orgCrcVal = GET_LWORD_FROM_BYTE(&buffer[PARTITION_CRC_OFFSET]);
386     delete [] buffer;
387 
388     uint32_t crcVal = CalculateCrc32(gptImage + partition0 * blockSize,
389         gptHeaderInfo.maxPartitionCount * gptHeaderInfo.partitionEntrySize);
390     if (crcVal != orgCrcVal) {
391         LOG(ERROR) << "partition entires crc mismatch crcVal =" << std::hex << crcVal << " with orgCrcVal =" <<
392             orgCrcVal << std::dec;
393         return false;
394     }
395     LOG(INFO) << "UfsPartitionCheckGptHeader ok";
396     return true;
397 }
398 
PrintPtableInfo() const399 void Ptable::PrintPtableInfo() const
400 {
401     if (partitionInfo_.empty()) {
402         LOG(ERROR) << "ptable vector is empty!";
403         return;
404     }
405 
406     LOG(INFO) << "ptnInfo : ===========================================";
407     LOG(INFO) << "partition count = " << std::dec << partitionInfo_.size();
408     for (size_t i = 0; i < partitionInfo_.size(); i++) {
409         LOG(INFO) << "ptable.entry[" << i << "].name=" << partitionInfo_[i].dispName.c_str() <<
410             ", startAddr=0x" << std::hex << partitionInfo_[i].startAddr << ", size=0x" <<
411             partitionInfo_[i].partitionSize << ", lun=" << std::dec << partitionInfo_[i].lun;
412     }
413     LOG(INFO) << "ptnInfo : ===========================================";
414 }
415 
PrintPtableInfo(const std::vector<PtnInfo> & ptnInfo) const416 void Ptable::PrintPtableInfo(const std::vector<PtnInfo> &ptnInfo) const
417 {
418     if (ptnInfo.empty()) {
419         LOG(ERROR) << "ptable vector is empty!";
420         return;
421     }
422 
423     LOG(INFO) << "ptnInfo : ===========================================";
424     LOG(INFO) << "partition count = " << std::dec << ptnInfo.size();
425     for (size_t i = 0; i < ptnInfo.size(); i++) {
426         LOG(INFO) << "ptable.entry[" << i << "].name=" << ptnInfo[i].dispName.c_str() << ", startAddr=0x" <<
427         std::hex << ptnInfo[i].startAddr << ", size=0x" << ptnInfo[i].partitionSize << ", lun=" <<
428         std::dec << ptnInfo[i].lun;
429     }
430     LOG(INFO) << "ptnInfo : ===========================================";
431 }
432 
ParsePartitionName(const uint8_t * data,const uint32_t dataLen,std::string & name,const uint32_t nameLen)433 void Ptable::ParsePartitionName(const uint8_t *data, const uint32_t dataLen,
434     std::string &name, const uint32_t nameLen)
435 {
436     if (data == nullptr || dataLen == 0 || nameLen == 0) {
437         LOG(ERROR) << "dataLen == 0 || nameLen == 0";
438         return;
439     }
440     char utf16Name[MAX_GPT_NAME_SIZE] = {0};
441     if (memcpy_s(utf16Name, sizeof(utf16Name), data, dataLen) != EOK) {
442         LOG(ERROR) << "memcpy name fail";
443         return;
444     }
445 
446     std::string outName;
447     // convert utf8 to utf16, 2 bytes for 1 charactor of partition name
448     for (uint32_t n = 0; n < nameLen && n < (MAX_GPT_NAME_SIZE / 2) && utf16Name[n * 2] != '\0'; n++) {
449         outName = outName + utf16Name[n * 2];
450     }
451     for (uint32_t i = 0; i < outName.size(); i++) {
452         outName[i] = static_cast<char>(toupper(outName[i]));
453     }
454     name = outName;
455     return;
456 }
457 
WriteBufferToPath(const std::string & path,const uint64_t offset,const uint8_t * buffer,const uint32_t size)458 bool Ptable::WriteBufferToPath(const std::string &path, const uint64_t offset,
459     const uint8_t *buffer, const uint32_t size)
460 {
461     std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_RAW, path, offset);
462     if (writer == nullptr) {
463         LOG(ERROR) << "create writer class failed!";
464         return false;
465     }
466     bool ret = writer->Write(buffer, size, nullptr);
467     if (!ret) {
468         LOG(ERROR) << "writer to " << path << " with offset " << offset << " failed ";
469         DataWriter::ReleaseDataWriter(writer);
470         return false;
471     }
472     DataWriter::ReleaseDataWriter(writer);
473     return true;
474 }
475 
GetPartionInfoByName(const std::string & partitionName,PtnInfo & ptnInfo,int32_t & index)476 bool Ptable::GetPartionInfoByName(const std::string &partitionName, PtnInfo &ptnInfo, int32_t &index)
477 {
478     if (partitionInfo_.empty()) {
479         LOG(ERROR) << "get partition failed! partitionInfo_ is empty";
480         return false;
481     }
482     for (int32_t i = 0; i < static_cast<int32_t>(partitionInfo_.size()); i++) {
483         if (partitionInfo_[i].dispName.size() == partitionName.size() &&
484             strcasecmp(partitionInfo_[i].dispName.c_str(), partitionName.c_str()) == 0) {
485             index = i;
486             ptnInfo = partitionInfo_[i];
487             return true;
488         }
489     }
490     LOG(ERROR) << "get partition info failed! Not found partition:" << partitionName;
491     return false;
492 }
493 } // namespace Updater