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