• 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 "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