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 "applypatch/block_set.h"
17 #include <linux/fs.h>
18 #include <sys/ioctl.h>
19 #include <openssl/sha.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include "applypatch/command.h"
24 #include "applypatch/store.h"
25 #include "applypatch/transfer_manager.h"
26 #include "log/log.h"
27 #include "patch/update_patch.h"
28 #include "securec.h"
29 #include "utils.h"
30
31 using namespace updater;
32 using namespace updater::utils;
33
34 namespace updater {
BlockSet(std::vector<BlockPair> && pairs)35 BlockSet::BlockSet(std::vector<BlockPair> &&pairs)
36 {
37 blockSize_ = 0;
38 UPDATER_ERROR_CHECK(!pairs.empty(), "Invalid block.", return);
39
40 for (const auto &pair : pairs) {
41 UPDATER_CHECK_ONLY_RETURN(CheckReliablePair(pair), return);
42 PushBack(pair);
43 }
44 }
45
CheckReliablePair(BlockPair pair)46 bool BlockSet::CheckReliablePair(BlockPair pair)
47 {
48 UPDATER_ERROR_CHECK(pair.first < pair.second, "Invalid number of block size", return false);
49 size_t size = pair.second - pair.first;
50 UPDATER_ERROR_CHECK(blockSize_ < (SIZE_MAX - size), "Block size overflow", return false);
51 return true;
52 }
53
PushBack(BlockPair blockPair)54 void BlockSet::PushBack(BlockPair blockPair)
55 {
56 blocks_.push_back(std::move(blockPair));
57 blockSize_ += (blockPair.second - blockPair.first);
58 }
59
ClearBlocks()60 void BlockSet::ClearBlocks()
61 {
62 blockSize_ = 0;
63 blocks_.clear();
64 }
65
ParserAndInsert(const std::string & blockStr)66 bool BlockSet::ParserAndInsert(const std::string &blockStr)
67 {
68 UPDATER_ERROR_CHECK(blockStr != "", "Invalid argument, this argument is empty", return false);
69 std::vector<std::string> pairs = SplitString(blockStr, ",");
70 return ParserAndInsert(pairs);
71 }
72
ParserAndInsert(const std::vector<std::string> & blockToken)73 bool BlockSet::ParserAndInsert(const std::vector<std::string> &blockToken)
74 {
75 ClearBlocks();
76 UPDATER_ERROR_CHECK(!blockToken.empty(), "Invalid block token argument", return false);
77 UPDATER_ERROR_CHECK(blockToken.size() >= 3, "Too small blocks_ in argument", return false);
78 // Get number of blockToken
79 unsigned long long int blockPairSize;
80 std::vector<std::string> bt = blockToken;
81 std::vector<std::string>::iterator bp = bt.begin();
82 blockPairSize = String2Int<unsigned long long int>(*bp, N_DEC);
83 UPDATER_ERROR_CHECK(blockPairSize != 0 && blockPairSize % 2 == 0 &&
84 blockPairSize == bt.size() - 1, "Invalid number in block token", return false);
85
86 while (++bp != bt.end()) {
87 size_t first = String2Int<size_t>(*bp++, N_DEC);
88 size_t second = String2Int<size_t>(*bp, N_DEC);
89 blocks_.push_back(BlockPair {
90 first, second
91 });
92 blockSize_ += (second - first);
93 }
94 return true;
95 }
96
Begin()97 std::vector<BlockPair>::iterator BlockSet::Begin()
98 {
99 return blocks_.begin();
100 }
101
End()102 std::vector<BlockPair>::iterator BlockSet::End()
103 {
104 return blocks_.end();
105 }
106
CBegin() const107 std::vector<BlockPair>::const_iterator BlockSet::CBegin() const
108 {
109 return blocks_.cbegin();
110 }
111
CEnd() const112 std::vector<BlockPair>::const_iterator BlockSet::CEnd() const
113 {
114 return blocks_.cend();
115 }
116
CrBegin() const117 std::vector<BlockPair>::const_reverse_iterator BlockSet::CrBegin() const
118 {
119 return blocks_.crbegin();
120 }
121
CrEnd() const122 std::vector<BlockPair>::const_reverse_iterator BlockSet::CrEnd() const
123 {
124 return blocks_.crend();
125 }
126
ReadDataFromBlock(int fd,std::vector<uint8_t> & buffer)127 size_t BlockSet::ReadDataFromBlock(int fd, std::vector<uint8_t> &buffer)
128 {
129 size_t pos = 0;
130 std::vector<BlockPair>::iterator it = blocks_.begin();
131 int ret;
132 for (; it != blocks_.end(); ++it) {
133 ret = lseek64(fd, static_cast<off64_t>(it->first * H_BLOCK_SIZE), SEEK_SET);
134 UPDATER_ERROR_CHECK(ret != -1, "Fail to seek", return -1);
135 size_t size = (it->second - it->first) * H_BLOCK_SIZE;
136 UPDATER_ERROR_CHECK(utils::ReadFully(fd, buffer.data() + pos, size), "Fail to read", return -1);
137 pos += size;
138 }
139 return pos;
140 }
141
WriteDataToBlock(int fd,std::vector<uint8_t> & buffer)142 size_t BlockSet::WriteDataToBlock(int fd, std::vector<uint8_t> &buffer)
143 {
144 size_t pos = 0;
145 std::vector<BlockPair>::iterator it = blocks_.begin();
146 int ret = 0;
147 for (; it != blocks_.end(); ++it) {
148 off64_t offset = static_cast<off64_t>(it->first * H_BLOCK_SIZE);
149 size_t writeSize = (it->second - it->first) * H_BLOCK_SIZE;
150 #ifndef UPDATER_UT
151 uint64_t arguments[] = {static_cast<uint64_t>(offset), writeSize};
152 ret = ioctl(fd, BLKDISCARD, &arguments);
153 UPDATER_ERROR_CHECK(ret != -1 || errno == EOPNOTSUPP, "Error to write block set to memory", return -1);
154 #endif
155 ret = lseek64(fd, offset, SEEK_SET);
156 UPDATER_ERROR_CHECK(ret != -1, "BlockSet::WriteDataToBlock Fail to seek", return -1);
157 if (utils::WriteFully(fd, buffer.data() + pos, writeSize) == false) {
158 LOG(ERROR) << "Write data to block error, errno : " << errno;
159 return -1;
160 }
161 pos += writeSize;
162 }
163 UPDATER_ERROR_CHECK(fsync(fd) != -1, "Failed to fsync", return -1);
164 return pos;
165 }
166
CountOfRanges() const167 size_t BlockSet::CountOfRanges() const
168 {
169 return blocks_.size();
170 }
171
TotalBlockSize() const172 size_t BlockSet::TotalBlockSize() const
173 {
174 return blockSize_;
175 }
176
VerifySha256(const std::vector<uint8_t> & buffer,const size_t size,const std::string & expected)177 int32_t BlockSet::VerifySha256(const std::vector<uint8_t> &buffer, const size_t size, const std::string &expected)
178 {
179 uint8_t digest[SHA256_DIGEST_LENGTH];
180 SHA256(buffer.data(), size * H_BLOCK_SIZE, digest);
181 std::string hexdigest = utils::ConvertSha256Hex(digest, SHA256_DIGEST_LENGTH);
182 UPDATER_CHECK_ONLY_RETURN(hexdigest != expected, return 0);
183 return -1;
184 }
185
IsTwoBlocksOverlap(const BlockSet & source,BlockSet & target)186 bool BlockSet::IsTwoBlocksOverlap(const BlockSet &source, BlockSet &target)
187 {
188 auto firstIter = source.CBegin();
189 for (; firstIter != source.CEnd(); ++firstIter) {
190 std::vector<BlockPair>::iterator secondIter = target.Begin();
191 for (; secondIter != target.End(); ++secondIter) {
192 if (!(secondIter->first >= firstIter->second ||
193 firstIter->first >= secondIter->second)) {
194 return true;
195 }
196 }
197 }
198 return false;
199 }
200
MoveBlock(std::vector<uint8_t> & target,const BlockSet & locations,const std::vector<uint8_t> & source)201 void BlockSet::MoveBlock(std::vector<uint8_t> &target, const BlockSet& locations,
202 const std::vector<uint8_t>& source)
203 {
204 const uint8_t *sd = source.data();
205 uint8_t *td = target.data();
206 size_t start = locations.TotalBlockSize();
207 for (auto it = locations.CrBegin(); it != locations.CrEnd(); it++) {
208 size_t blocks = it->second - it->first;
209 start -= blocks;
210 UPDATER_ERROR_CHECK(!memmove_s(td + (it->first * H_BLOCK_SIZE), blocks * H_BLOCK_SIZE, sd + (start *
211 H_BLOCK_SIZE), blocks * H_BLOCK_SIZE), "MoveBlock memmove_s failed!", return);
212 }
213 }
214
LoadSourceBuffer(const Command & cmd,size_t & pos,std::vector<uint8_t> & sourceBuffer,bool & isOverlap,size_t & srcBlockSize)215 int32_t BlockSet::LoadSourceBuffer(const Command &cmd, size_t &pos, std::vector<uint8_t> &sourceBuffer,
216 bool &isOverlap, size_t &srcBlockSize)
217 {
218 std::string blockLen = cmd.GetArgumentByPos(pos++);
219 srcBlockSize = String2Int<size_t>(blockLen, N_DEC);
220 sourceBuffer.resize(srcBlockSize * H_BLOCK_SIZE);
221 std::string targetCmd = cmd.GetArgumentByPos(pos++);
222 std::string storeBase = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeBase;
223 if (targetCmd != "-") {
224 BlockSet srcBlk;
225 srcBlk.ParserAndInsert(targetCmd);
226 isOverlap = IsTwoBlocksOverlap(srcBlk, *this);
227 // read source data
228 LOG(INFO) << "new start to read source block ...";
229 UPDATER_CHECK_ONLY_RETURN(srcBlk.ReadDataFromBlock(cmd.GetFileDescriptor(), sourceBuffer) > 0, return -1);
230 std::string nextArgv = cmd.GetArgumentByPos(pos++);
231 UPDATER_CHECK_ONLY_RETURN(nextArgv != "", return 1);
232 BlockSet locations;
233 locations.ParserAndInsert(nextArgv);
234 MoveBlock(sourceBuffer, locations, sourceBuffer);
235 }
236
237 std::string lastArg = cmd.GetArgumentByPos(pos++);
238 while (lastArg != "") {
239 std::vector<std::string> tokens = SplitString(lastArg, ":");
240 UPDATER_ERROR_CHECK(tokens.size() == H_CMD_ARGS_LIMIT, "invalid parameter", return -1);
241 std::vector<uint8_t> stash;
242 auto ret = Store::LoadDataFromStore(storeBase, tokens[H_ZERO_NUMBER], stash);
243 UPDATER_ERROR_CHECK(ret != -1, "Failed to load tokens", return -1);
244 BlockSet locations;
245 locations.ParserAndInsert(tokens[1]);
246 MoveBlock(sourceBuffer, locations, stash);
247
248 lastArg = cmd.GetArgumentByPos(pos++);
249 }
250 return 1;
251 }
252
LoadTargetBuffer(const Command & cmd,std::vector<uint8_t> & buffer,size_t & blockSize,size_t pos,std::string & srcHash)253 int32_t BlockSet::LoadTargetBuffer(const Command &cmd, std::vector<uint8_t> &buffer, size_t &blockSize,
254 size_t pos, std::string &srcHash)
255 {
256 bool isOverlap = false;
257 auto ret = LoadSourceBuffer(cmd, pos, buffer, isOverlap, blockSize);
258 UPDATER_CHECK_ONLY_RETURN(ret == 1,
259 return ret);
260 std::string storeBase = TransferManager::GetTransferManagerInstance()->GetGlobalParams()->storeBase;
261 std::string storePath = storeBase + "/" + srcHash;
262 struct stat storeStat {};
263 int res = stat(storePath.c_str(), &storeStat);
264 if (VerifySha256(buffer, blockSize, srcHash) == 0) {
265 if (isOverlap && res != 0) {
266 ret = Store::WriteDataToStore(storeBase, srcHash, buffer, blockSize * H_BLOCK_SIZE);
267 UPDATER_ERROR_CHECK(ret == 0, "failed to stash overlapping source blocks", return -1);
268 }
269 return 0;
270 }
271 UPDATER_CHECK_ONLY_RETURN(Store::LoadDataFromStore(storeBase, srcHash, buffer) != 0, return 0);
272 return -1;
273 }
274
WriteZeroToBlock(int fd,bool isErase)275 int32_t BlockSet::WriteZeroToBlock(int fd, bool isErase)
276 {
277 std::vector<uint8_t> buffer;
278 buffer.resize(H_BLOCK_SIZE);
279 UPDATER_ERROR_CHECK(!memset_s(buffer.data(), H_BLOCK_SIZE, 0, H_BLOCK_SIZE), "memset_s failed", return -1);
280
281 auto iter = blocks_.begin();
282 while (iter != blocks_.end()) {
283 off64_t offset = static_cast<off64_t>(iter->first * H_BLOCK_SIZE);
284 int ret = 0;
285 #ifndef UPDATER_UT
286 size_t writeSize = (iter->second - iter->first) * H_BLOCK_SIZE;
287 uint64_t arguments[2] = {static_cast<uint64_t>(offset), writeSize};
288 ret = ioctl(fd, BLKDISCARD, &arguments);
289 UPDATER_ERROR_CHECK(ret != -1 || errno == EOPNOTSUPP, "Error to write block set to memory", return -1);
290 #endif
291 if (!isErase) {
292 ret = lseek64(fd, offset, SEEK_SET);
293 UPDATER_ERROR_CHECK(ret != -1, "BlockSet::WriteZeroToBlock Fail to seek", return -1);
294 for (size_t pos = iter->first; pos < iter->second; pos++) {
295 if (utils::WriteFully(fd, buffer.data(), H_BLOCK_SIZE) == false) {
296 UPDATER_CHECK_ONLY_RETURN(errno != EIO, return 1);
297 LOG(ERROR) << "BlockSet::WriteZeroToBlock Write 0 to block error, errno : " << errno;
298 return -1;
299 }
300 }
301 }
302 iter++;
303 }
304 return 0;
305 }
306
WriteDiffToBlock(const Command & cmd,std::vector<uint8_t> & srcBuffer,const size_t srcBlockSize,bool isImgDiff)307 int32_t BlockSet::WriteDiffToBlock(const Command &cmd, std::vector<uint8_t> &srcBuffer,
308 const size_t srcBlockSize, bool isImgDiff)
309 {
310 size_t pos = H_MOVE_CMD_ARGS_START;
311 size_t offset = utils::String2Int<size_t>(cmd.GetArgumentByPos(pos++), utils::N_DEC);
312 size_t length = utils::String2Int<size_t>(cmd.GetArgumentByPos(pos++), utils::N_DEC);
313 LOG(INFO) << "Get patch data offset: " << offset << ", length: " << length;
314 // Get patch buffer
315 auto globalParams = TransferManager::GetTransferManagerInstance()->GetGlobalParams();
316 auto patchBuff = globalParams->patchDataBuffer + offset;
317 size_t srcBuffSize = srcBlockSize * H_BLOCK_SIZE;
318 if (isImgDiff) {
319 std::vector<uint8_t> empty;
320 updatepatch::PatchParam patchParam = {
321 reinterpret_cast<u_char*>(srcBuffer.data()), srcBuffSize, reinterpret_cast<u_char*>(patchBuff), length
322 };
323 std::unique_ptr<BlockWriter> writer = std::make_unique<BlockWriter>(cmd.GetFileDescriptor(), *this);
324 UPDATER_ERROR_CHECK(writer.get() != nullptr, "Cannot create block writer, pkgdiff patch abort!", return -1);
325 int32_t ret = updatepatch::UpdatePatch::ApplyImagePatch(patchParam, empty,
326 [&](size_t start, const updatepatch::BlockBuffer &data, size_t size) -> int {
327 bool ret = writer->Write(data.buffer, size, WRITE_BLOCK, "");
328 return ret ? 0 : -1;
329 }, cmd.GetArgumentByPos(pos + 1));
330 writer.reset();
331 UPDATER_ERROR_CHECK(ret == 0, "Fail to ApplyImagePatch", return -1);
332 } else {
333 LOG(DEBUG) << "Run bsdiff patch.";
334 updatepatch::PatchBuffer patchInfo = {patchBuff, 0, length};
335 std::unique_ptr<BlockWriter> writer = std::make_unique<BlockWriter>(cmd.GetFileDescriptor(), *this);
336 UPDATER_ERROR_CHECK(writer.get() != nullptr, "Cannot create block writer, pkgdiff patch abort!", return -1);
337 auto ret = updatepatch::UpdatePatch::ApplyBlockPatch(patchInfo, {srcBuffer.data(), srcBuffSize},
338 [&](size_t start, const updatepatch::BlockBuffer &data, size_t size) -> int {
339 bool ret = writer->Write(data.buffer, size, WRITE_BLOCK, "");
340 return ret ? 0 : -1;
341 }, cmd.GetArgumentByPos(pos + 1));
342 writer.reset();
343 UPDATER_ERROR_CHECK(ret == 0, "Fail to ApplyBlockPatch", return -1);
344 }
345 return 0;
346 }
347 } // namespace updater
348