• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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