1 /*
2  * Copyright (c) 2024-2024 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 <cinttypes>
17 
18 #include "securec.h"
19 #include "signature_info.h"
20 #include "signature_tools_log.h"
21 #include "digest_common.h"
22 //#include "verify_hap_openssl_utils.h"
23 #include "random_access_file.h"
24 
25 namespace OHOS {
26 namespace SignatureTools {
27 int32_t RandomAccessFile::memoryPageSize = sysconf(_SC_PAGESIZE);
28 
RandomAccessFile()29 RandomAccessFile::RandomAccessFile()
30     : fd(-1), fileLength(0)
31 {
32 }
33 
~RandomAccessFile()34 RandomAccessFile::~RandomAccessFile()
35 {
36     if (fd != -1) {
37         close(fd);
38     }
39 }
40 
Init(const std::string& filePath)41 bool RandomAccessFile::Init(const std::string& filePath)
42 {
43     fd = open(filePath.c_str(), O_RDWR);
44     if (fd == -1) {
45         PrintErrorNumberMsg("IO_ERROR", IO_ERROR, "open file: " + filePath + " failed");
46         return false;
47     }
48 
49     if (memoryPageSize <= 0) {
50         PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
51                             "getting pagesize failed. memoryPageSize: " + std::to_string(memoryPageSize));
52         return false;
53     }
54 
55     struct stat file_stat;
56     if (fstat(fd, &file_stat) == -1) {
57         PrintErrorNumberMsg("IO_ERROR", IO_ERROR,
58                             filePath + "get status failed");
59         return false;
60     }
61     fileLength = file_stat.st_size;
62 
63     return true;
64 }
65 
GetLength() const66 int64_t RandomAccessFile::GetLength() const
67 {
68     return fileLength;
69 }
70 
CheckLittleEndian()71 bool RandomAccessFile::CheckLittleEndian()
72 {
73     union LittleEndian {
74         int32_t number;
75         char ch;
76     } t;
77     t.number = 1;
78     return (t.ch == 1);
79 }
80 
DoMMap(int32_t bufCapacity, int64_t offset, MmapInfo& mmapInfo)81 int32_t RandomAccessFile::DoMMap(int32_t bufCapacity, int64_t offset, MmapInfo& mmapInfo)
82 {
83     if (!CheckLittleEndian()) {
84         SIGNATURE_TOOLS_LOGE("CheckLittleEndian: failed");
85         return MMAP_FAILED;
86     }
87 
88     // Starting address for memory mapping
89     mmapInfo.mapAddr = reinterpret_cast<char*>(MAP_FAILED);
90     if (fd == -1) {
91         SIGNATURE_TOOLS_LOGE("random access file's fd is -1, the file is closed");
92         return FILE_IS_CLOSE;
93     }
94     if (offset < 0 || offset > fileLength - bufCapacity) {
95         SIGNATURE_TOOLS_LOGE("offset is less than 0 OR read offset is out of range. offset: %" PRId64
96                              ", range: %" PRId64, offset, fileLength - bufCapacity);
97         return READ_OFFSET_OUT_OF_RANGE;
98     }
99     // Memory mapped file offset, 0 OR an integer multiple of 4K
100     mmapInfo.mmapPosition = (offset / memoryPageSize) * memoryPageSize;
101     // How many more bytes can be read from the current mapped memory page to find
102     mmapInfo.readMoreLen = static_cast<int>(offset - mmapInfo.mmapPosition);
103     mmapInfo.mmapSize = bufCapacity + mmapInfo.readMoreLen;
104     mmapInfo.mapAddr = reinterpret_cast<char*>(mmap(nullptr, mmapInfo.mmapSize, PROT_READ | PROT_WRITE,
105                                                     MAP_SHARED | MAP_POPULATE, fd, mmapInfo.mmapPosition));
106     if (mmapInfo.mapAddr == MAP_FAILED) {
107         SIGNATURE_TOOLS_LOGE("mmap failed");
108         return MMAP_FAILED;
109     }
110     return 0;
111 }
112 
ReadFileFullyFromOffset(char buf[], int64_t offset, int64_t bufCapacity)113 int32_t RandomAccessFile::ReadFileFullyFromOffset(char buf[], int64_t offset, int64_t bufCapacity)
114 {
115     if (buf == nullptr) {
116         SIGNATURE_TOOLS_LOGE("The dest buffer is null");
117         return DEST_BUFFER_IS_NULL;
118     }
119 
120     MmapInfo mmapInfo;
121     int32_t ret = DoMMap(bufCapacity, offset, mmapInfo);
122     if (ret < 0) {
123         return ret;
124     }
125 
126     if (memcpy_s(buf, bufCapacity, mmapInfo.mapAddr + mmapInfo.readMoreLen,
127                  mmapInfo.mmapSize - mmapInfo.readMoreLen) != EOK) {
128         munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
129         SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR);
130         return MMAP_COPY_FAILED;
131     }
132     munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
133     return bufCapacity;
134 }
135 
ReadFileFullyFromOffset(ByteBuffer& buffer, int64_t offset)136 int32_t RandomAccessFile::ReadFileFullyFromOffset(ByteBuffer& buffer, int64_t offset)
137 {
138     if (!buffer.HasRemaining()) {
139         SIGNATURE_TOOLS_LOGE("The dest buffer has not remaining");
140         return DEST_BUFFER_IS_NULL;
141     }
142 
143     MmapInfo mmapInfo;
144     int32_t bufCapacity = buffer.GetCapacity();
145     int64_t ret = DoMMap(bufCapacity, offset, mmapInfo);
146     if (ret < 0) {
147         return ret;
148     }
149 
150     buffer.PutData(0, mmapInfo.mapAddr + mmapInfo.readMoreLen, bufCapacity);
151     munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
152     return bufCapacity;
153 }
154 
WriteToFile(ByteBuffer& buffer, int64_t position, int64_t length)155 int32_t RandomAccessFile::WriteToFile(ByteBuffer& buffer, int64_t position, int64_t length)
156 {
157     // write file, file length may change
158     int64_t remainLength = fileLength - position;
159     fileLength = (length <= remainLength) ? fileLength : (fileLength + (length - remainLength));
160     // update file length
161     if (ftruncate(fd, fileLength) == -1) {
162         SIGNATURE_TOOLS_LOGE("RandomAccessFile ftruncate error: %s", strerror(errno));
163         return IO_ERROR;
164     }
165 
166     int32_t bufCapacity = buffer.GetCapacity();
167     if (bufCapacity == 0) {
168         SIGNATURE_TOOLS_LOGE("The dest buffer capacity is 0");
169         return DEST_BUFFER_IS_NULL;
170     }
171 
172     MmapInfo mmapInfo;
173 
174     int32_t ret = DoMMap(bufCapacity, position, mmapInfo);
175     if (ret < 0) {
176         SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret);
177         return ret;
178     }
179 
180     if (memcpy_s(mmapInfo.mapAddr + mmapInfo.readMoreLen,
181                  mmapInfo.mmapSize - mmapInfo.readMoreLen,
182         buffer.GetBufferPtr(), bufCapacity) != RET_OK) {
183         SIGNATURE_TOOLS_LOGE("memcpy_s error, errno: %d", IO_ERROR);
184         return MMAP_COPY_FAILED;
185     }
186     munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
187     return bufCapacity;
188 }
189 
ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam, int32_t chunkSize, int64_t offset)190 bool RandomAccessFile::ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam,
191                                                          int32_t chunkSize, int64_t offset)
192 {
193     MmapInfo mmapInfo;
194     int32_t ret = DoMMap(chunkSize, offset, mmapInfo);
195     if (ret < 0) {
196         SIGNATURE_TOOLS_LOGE("DoMMap failed: %d", ret);
197         return false;
198     }
199     unsigned char* content = reinterpret_cast<unsigned char*>(mmapInfo.mapAddr + mmapInfo.readMoreLen);
200     bool res = DigestCommon::DigestUpdate(digestParam, content, chunkSize);
201     munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
202     return res;
203 }
204 }
205 }