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 }