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