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 "common/random_access_file.h"
17
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <parameters.h>
21 #include <string>
22 #include <sys/mman.h>
23 #include <unistd.h>
24
25 #include "common/hap_verify_log.h"
26 #include "securec.h"
27 #include "util/hap_verify_openssl_utils.h"
28
29 namespace OHOS {
30 namespace Security {
31 namespace Verify {
32 const int32_t RandomAccessFile::FILE_OPEN_FAIL_ERROR_NUM = -1;
33 int32_t RandomAccessFile::memoryPageSize = sysconf(_SC_PAGESIZE);
34
RandomAccessFile()35 RandomAccessFile::RandomAccessFile()
36 : fd(FILE_OPEN_FAIL_ERROR_NUM), fileLength(0)
37 {
38 }
39
~RandomAccessFile()40 RandomAccessFile::~RandomAccessFile()
41 {
42 if (fd != FILE_OPEN_FAIL_ERROR_NUM) {
43 close(fd);
44 }
45 }
46
Init(const std::string & filePath,bool readFile)47 bool RandomAccessFile::Init(const std::string& filePath, bool readFile)
48 {
49 fd = open(filePath.c_str(), O_RDONLY);
50 if (fd == FILE_OPEN_FAIL_ERROR_NUM) {
51 return false;
52 }
53
54 if (memoryPageSize <= 0) {
55 HAPVERIFY_LOG_ERROR("getting pagesize failed: %{public}d", memoryPageSize);
56 return false;
57 }
58
59 fileLength = lseek(fd, 0, SEEK_END);
60 if (fileLength < 0) {
61 HAPVERIFY_LOG_ERROR("getting fileLength failed: %{public}lld", fileLength);
62 return false;
63 }
64 readFile_ = readFile;
65 return true;
66 }
67
InitWithFd(const int32_t fileFd)68 bool RandomAccessFile::InitWithFd(const int32_t fileFd)
69 {
70 if (fileFd <= FILE_OPEN_FAIL_ERROR_NUM) {
71 HAPVERIFY_LOG_ERROR("invalid fd");
72 return false;
73 }
74 fd = dup(fileFd);
75 if (fd <= FILE_OPEN_FAIL_ERROR_NUM) {
76 HAPVERIFY_LOG_ERROR("dup failed: %{public}d", errno);
77 return false;
78 }
79
80 if (memoryPageSize <= 0) {
81 HAPVERIFY_LOG_ERROR("getting pagesize failed: %{public}d", memoryPageSize);
82 return false;
83 }
84
85 fileLength = lseek(fd, 0, SEEK_END);
86 if (fileLength < 0) {
87 HAPVERIFY_LOG_ERROR("getting fileLength failed: %{public}lld", fileLength);
88 return false;
89 }
90 readFile_ = true;
91 return true;
92 }
93
GetLength() const94 long long RandomAccessFile::GetLength() const
95 {
96 return fileLength;
97 }
98
CheckLittleEndian()99 bool RandomAccessFile::CheckLittleEndian()
100 {
101 union LittleEndian {
102 int32_t num;
103 char ch;
104 } t;
105 t.num = 1;
106 return (t.ch == 1);
107 }
108
DoMMap(int32_t bufCapacity,long long offset,MmapInfo & mmapInfo)109 long long RandomAccessFile::DoMMap(int32_t bufCapacity, long long offset, MmapInfo& mmapInfo)
110 {
111 if (!CheckLittleEndian()) {
112 HAPVERIFY_LOG_ERROR("CheckLittleEndian: failed");
113 return MMAP_FAILED;
114 }
115 mmapInfo.mapAddr = reinterpret_cast<char*>(MAP_FAILED);
116 if (fd == FILE_OPEN_FAIL_ERROR_NUM) {
117 return FILE_IS_CLOSE;
118 }
119 if (offset < 0 || offset > fileLength - bufCapacity) {
120 return READ_OFFSET_OUT_OF_RANGE;
121 }
122 mmapInfo.mmapPosition = (offset / memoryPageSize) * memoryPageSize;
123 mmapInfo.readMoreLen = static_cast<int>(offset - mmapInfo.mmapPosition);
124 mmapInfo.mmapSize = bufCapacity + mmapInfo.readMoreLen;
125 mmapInfo.mapAddr = reinterpret_cast<char*>(mmap(nullptr, mmapInfo.mmapSize, PROT_READ,
126 MAP_SHARED | MAP_POPULATE, fd, mmapInfo.mmapPosition));
127 if (mmapInfo.mapAddr == MAP_FAILED) {
128 HAPVERIFY_LOG_ERROR("MAP_FAILED: %{public}d", errno);
129 return MMAP_FAILED;
130 }
131 return 0;
132 }
133
ReadFileFullyFromOffset(char buf[],long long offset,int32_t bufCapacity)134 long long RandomAccessFile::ReadFileFullyFromOffset(char buf[], long long offset, int32_t bufCapacity)
135 {
136 if (readFile_) {
137 return ReadFileFullyFromOffsetV2(buf, offset, bufCapacity);
138 }
139 if (buf == nullptr) {
140 return DEST_BUFFER_IS_NULL;
141 }
142
143 MmapInfo mmapInfo;
144 long long ret = DoMMap(bufCapacity, offset, mmapInfo);
145 if (ret < 0) {
146 return ret;
147 }
148
149 if (memcpy_s(buf, bufCapacity, mmapInfo.mapAddr + mmapInfo.readMoreLen,
150 mmapInfo.mmapSize - mmapInfo.readMoreLen) != EOK) {
151 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
152 return MMAP_COPY_FAILED;
153 }
154 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
155 return bufCapacity;
156 }
157
ReadFileFullyFromOffset(HapByteBuffer & buffer,long long offset)158 long long RandomAccessFile::ReadFileFullyFromOffset(HapByteBuffer& buffer, long long offset)
159 {
160 if (readFile_) {
161 return ReadFileFullyFromOffsetV2(buffer, offset);
162 }
163 if (!buffer.HasRemaining()) {
164 return DEST_BUFFER_IS_NULL;
165 }
166
167 MmapInfo mmapInfo;
168 int32_t bufCapacity = buffer.GetCapacity();
169 long long ret = DoMMap(bufCapacity, offset, mmapInfo);
170 if (ret < 0) {
171 return ret;
172 }
173
174 buffer.PutData(0, mmapInfo.mapAddr + mmapInfo.readMoreLen, bufCapacity);
175 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
176 return bufCapacity;
177 }
178
ReadFileFromOffsetAndDigestUpdate(const DigestParameter & digestParam,int32_t chunkSize,long long offset)179 bool RandomAccessFile::ReadFileFromOffsetAndDigestUpdate(const DigestParameter& digestParam,
180 int32_t chunkSize, long long offset)
181 {
182 if (readFile_ || HapVerifyParallelizationSupported()) {
183 return ReadFileFromOffsetAndDigestUpdateV2(digestParam, chunkSize, offset);
184 }
185 MmapInfo mmapInfo;
186 long long ret = DoMMap(chunkSize, offset, mmapInfo);
187 if (ret < 0) {
188 HAPVERIFY_LOG_ERROR("DoMMap failed: %{public}lld", ret);
189 return false;
190 }
191
192 unsigned char* content = reinterpret_cast<unsigned char*>(mmapInfo.mapAddr + mmapInfo.readMoreLen);
193 bool res = HapVerifyOpensslUtils::DigestUpdate(digestParam, content, chunkSize);
194 munmap(mmapInfo.mapAddr, mmapInfo.mmapSize);
195 return res;
196 }
197
ReadFileFullyFromOffsetV2(char buf[],long long offset,int32_t bufCapacity)198 long long RandomAccessFile::ReadFileFullyFromOffsetV2(char buf[], long long offset, int32_t bufCapacity)
199 {
200 if (buf == nullptr) {
201 HAPVERIFY_LOG_ERROR("buf is null");
202 return DEST_BUFFER_IS_NULL;
203 }
204
205 long long bytesRead = pread(fd, buf, bufCapacity, offset);
206 if (bytesRead < 0) {
207 HAPVERIFY_LOG_ERROR("pread failed: %{public}d", errno);
208 return bytesRead;
209 }
210
211 return bytesRead;
212 }
213
ReadFileFullyFromOffsetV2(HapByteBuffer & buffer,long long offset)214 long long RandomAccessFile::ReadFileFullyFromOffsetV2(HapByteBuffer& buffer, long long offset)
215 {
216 if (!buffer.HasRemaining()) {
217 HAPVERIFY_LOG_ERROR("buffer has no remaining space");
218 return DEST_BUFFER_IS_NULL;
219 }
220
221 int32_t bufCapacity = buffer.GetCapacity();
222 if (bufCapacity <= 0) {
223 HAPVERIFY_LOG_ERROR("Invalid buffer capacity");
224 return DEST_BUFFER_IS_NULL;
225 }
226 char* buf = new (std::nothrow) char[bufCapacity];
227 if (buf == nullptr) {
228 HAPVERIFY_LOG_ERROR("Failed to allocate memory for buffer");
229 return DEST_BUFFER_IS_NULL;
230 }
231
232 long long bytesRead = pread(fd, buf, bufCapacity, offset);
233 if (bytesRead < 0) {
234 HAPVERIFY_LOG_ERROR("pread failed: %{public}lld", bytesRead);
235 delete[] buf;
236 return bytesRead;
237 }
238
239 buffer.PutData(0, buf, bytesRead);
240 delete[] buf;
241 return bytesRead;
242 }
243
ReadFileFromOffsetAndDigestUpdateV2(const DigestParameter & digestParam,int32_t chunkSize,long long offset)244 bool RandomAccessFile::ReadFileFromOffsetAndDigestUpdateV2(const DigestParameter& digestParam,
245 int32_t chunkSize, long long offset)
246 {
247 if (chunkSize <= 0) {
248 HAPVERIFY_LOG_ERROR("Invalid chunkSize");
249 return false;
250 }
251 unsigned char* buffer = new (std::nothrow) unsigned char[chunkSize];
252 if (buffer == nullptr) {
253 HAPVERIFY_LOG_ERROR("Failed to allocate memory for buffer");
254 return false;
255 }
256
257 long long bytesRead = pread(fd, buffer, chunkSize, offset);
258 if (bytesRead < 0) {
259 HAPVERIFY_LOG_ERROR("pread failed: %{public}lld", bytesRead);
260 delete[] buffer;
261 return false;
262 }
263
264 bool res = HapVerifyOpensslUtils::DigestUpdate(digestParam, buffer, bytesRead);
265 delete[] buffer;
266 return res;
267 }
268
HapVerifyParallelizationSupported()269 bool RandomAccessFile::HapVerifyParallelizationSupported()
270 {
271 return OHOS::system::GetBoolParameter("const.appverify.hap_verify_parallel", false);
272 }
273 } // namespace Verify
274 } // namespace Security
275 } // namespace OHOS
276