1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include <sys/types.h>
18 #include <unistd.h>
19
20 #include <limits>
21 #include <optional>
22 #include <vector>
23
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <libsnapshot/cow_reader.h>
27 #include <zlib.h>
28
29 #include "cow_decompress.h"
30
31 namespace android {
32 namespace snapshot {
33
CowReader()34 CowReader::CowReader() : fd_(-1), header_(), fd_size_(0) {}
35
SHA256(const void *,size_t,uint8_t[])36 static void SHA256(const void*, size_t, uint8_t[]) {
37 #if 0
38 SHA256_CTX c;
39 SHA256_Init(&c);
40 SHA256_Update(&c, data, length);
41 SHA256_Final(out, &c);
42 #endif
43 }
44
InitForMerge(android::base::unique_fd && fd)45 bool CowReader::InitForMerge(android::base::unique_fd&& fd) {
46 owned_fd_ = std::move(fd);
47 fd_ = owned_fd_.get();
48
49 auto pos = lseek(fd_.get(), 0, SEEK_END);
50 if (pos < 0) {
51 PLOG(ERROR) << "lseek end failed";
52 return false;
53 }
54 fd_size_ = pos;
55
56 if (lseek(fd_.get(), 0, SEEK_SET) < 0) {
57 PLOG(ERROR) << "lseek header failed";
58 return false;
59 }
60 if (!android::base::ReadFully(fd_, &header_, sizeof(header_))) {
61 PLOG(ERROR) << "read header failed";
62 return false;
63 }
64
65 return true;
66 }
67
Parse(android::base::unique_fd && fd,std::optional<uint64_t> label)68 bool CowReader::Parse(android::base::unique_fd&& fd, std::optional<uint64_t> label) {
69 owned_fd_ = std::move(fd);
70 return Parse(android::base::borrowed_fd{owned_fd_}, label);
71 }
72
Parse(android::base::borrowed_fd fd,std::optional<uint64_t> label)73 bool CowReader::Parse(android::base::borrowed_fd fd, std::optional<uint64_t> label) {
74 fd_ = fd;
75
76 auto pos = lseek(fd_.get(), 0, SEEK_END);
77 if (pos < 0) {
78 PLOG(ERROR) << "lseek end failed";
79 return false;
80 }
81 fd_size_ = pos;
82
83 if (lseek(fd_.get(), 0, SEEK_SET) < 0) {
84 PLOG(ERROR) << "lseek header failed";
85 return false;
86 }
87 if (!android::base::ReadFully(fd_, &header_, sizeof(header_))) {
88 PLOG(ERROR) << "read header failed";
89 return false;
90 }
91
92 if (header_.magic != kCowMagicNumber) {
93 LOG(ERROR) << "Header Magic corrupted. Magic: " << header_.magic
94 << "Expected: " << kCowMagicNumber;
95 return false;
96 }
97 if (header_.footer_size != sizeof(CowFooter)) {
98 LOG(ERROR) << "Footer size unknown, read " << header_.footer_size << ", expected "
99 << sizeof(CowFooter);
100 return false;
101 }
102 if (header_.op_size != sizeof(CowOperation)) {
103 LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected "
104 << sizeof(CowOperation);
105 return false;
106 }
107 if (header_.cluster_ops == 1) {
108 LOG(ERROR) << "Clusters must contain at least two operations to function.";
109 return false;
110 }
111 if (header_.op_size != sizeof(CowOperation)) {
112 LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected "
113 << sizeof(CowOperation);
114 return false;
115 }
116 if (header_.cluster_ops == 1) {
117 LOG(ERROR) << "Clusters must contain at least two operations to function.";
118 return false;
119 }
120
121 if ((header_.major_version > kCowVersionMajor) || (header_.minor_version != kCowVersionMinor)) {
122 LOG(ERROR) << "Header version mismatch";
123 LOG(ERROR) << "Major version: " << header_.major_version
124 << "Expected: " << kCowVersionMajor;
125 LOG(ERROR) << "Minor version: " << header_.minor_version
126 << "Expected: " << kCowVersionMinor;
127 return false;
128 }
129
130 return ParseOps(label);
131 }
132
ParseOps(std::optional<uint64_t> label)133 bool CowReader::ParseOps(std::optional<uint64_t> label) {
134 uint64_t pos;
135
136 // Skip the scratch space
137 if (header_.major_version >= 2 && (header_.buffer_size > 0)) {
138 LOG(DEBUG) << " Scratch space found of size: " << header_.buffer_size;
139 size_t init_offset = header_.header_size + header_.buffer_size;
140 pos = lseek(fd_.get(), init_offset, SEEK_SET);
141 if (pos != init_offset) {
142 PLOG(ERROR) << "lseek ops failed";
143 return false;
144 }
145 } else {
146 pos = lseek(fd_.get(), header_.header_size, SEEK_SET);
147 if (pos != header_.header_size) {
148 PLOG(ERROR) << "lseek ops failed";
149 return false;
150 }
151 // Reading a v1 version of COW which doesn't have buffer_size.
152 header_.buffer_size = 0;
153 }
154
155 auto ops_buffer = std::make_shared<std::vector<CowOperation>>();
156 uint64_t current_op_num = 0;
157 uint64_t cluster_ops = header_.cluster_ops ?: 1;
158 bool done = false;
159
160 // Alternating op clusters and data
161 while (!done) {
162 uint64_t to_add = std::min(cluster_ops, (fd_size_ - pos) / sizeof(CowOperation));
163 if (to_add == 0) break;
164 ops_buffer->resize(current_op_num + to_add);
165 if (!android::base::ReadFully(fd_, &ops_buffer->data()[current_op_num],
166 to_add * sizeof(CowOperation))) {
167 PLOG(ERROR) << "read op failed";
168 return false;
169 }
170 // Parse current cluster to find start of next cluster
171 while (current_op_num < ops_buffer->size()) {
172 auto& current_op = ops_buffer->data()[current_op_num];
173 current_op_num++;
174 pos += sizeof(CowOperation) + GetNextOpOffset(current_op, header_.cluster_ops);
175
176 if (current_op.type == kCowClusterOp) {
177 break;
178 } else if (current_op.type == kCowLabelOp) {
179 last_label_ = {current_op.source};
180
181 // If we reach the requested label, stop reading.
182 if (label && label.value() == current_op.source) {
183 done = true;
184 break;
185 }
186 } else if (current_op.type == kCowFooterOp) {
187 footer_.emplace();
188 CowFooter* footer = &footer_.value();
189 memcpy(&footer_->op, ¤t_op, sizeof(footer->op));
190 off_t offs = lseek(fd_.get(), pos, SEEK_SET);
191 if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
192 PLOG(ERROR) << "lseek next op failed";
193 return false;
194 }
195 if (!android::base::ReadFully(fd_, &footer->data, sizeof(footer->data))) {
196 LOG(ERROR) << "Could not read COW footer";
197 return false;
198 }
199
200 // Drop the footer from the op stream.
201 current_op_num--;
202 done = true;
203 break;
204 }
205 }
206
207 // Position for next cluster read
208 off_t offs = lseek(fd_.get(), pos, SEEK_SET);
209 if (offs < 0 || pos != static_cast<uint64_t>(offs)) {
210 PLOG(ERROR) << "lseek next op failed";
211 return false;
212 }
213 ops_buffer->resize(current_op_num);
214 }
215
216 LOG(DEBUG) << "COW file read complete. Total ops: " << ops_buffer->size();
217 // To successfully parse a COW file, we need either:
218 // (1) a label to read up to, and for that label to be found, or
219 // (2) a valid footer.
220 if (label) {
221 if (!last_label_) {
222 LOG(ERROR) << "Did not find label " << label.value()
223 << " while reading COW (no labels found)";
224 return false;
225 }
226 if (last_label_.value() != label.value()) {
227 LOG(ERROR) << "Did not find label " << label.value()
228 << ", last label=" << last_label_.value();
229 return false;
230 }
231 } else if (!footer_) {
232 LOG(ERROR) << "No COW footer found";
233 return false;
234 }
235
236 uint8_t csum[32];
237 memset(csum, 0, sizeof(uint8_t) * 32);
238
239 if (footer_) {
240 if (ops_buffer->size() != footer_->op.num_ops) {
241 LOG(ERROR) << "num ops does not match, expected " << footer_->op.num_ops << ", found "
242 << ops_buffer->size();
243 return false;
244 }
245 if (ops_buffer->size() * sizeof(CowOperation) != footer_->op.ops_size) {
246 LOG(ERROR) << "ops size does not match ";
247 return false;
248 }
249 SHA256(&footer_->op, sizeof(footer_->op), footer_->data.footer_checksum);
250 if (memcmp(csum, footer_->data.ops_checksum, sizeof(csum)) != 0) {
251 LOG(ERROR) << "ops checksum does not match";
252 return false;
253 }
254 SHA256(ops_buffer.get()->data(), footer_->op.ops_size, csum);
255 if (memcmp(csum, footer_->data.ops_checksum, sizeof(csum)) != 0) {
256 LOG(ERROR) << "ops checksum does not match";
257 return false;
258 }
259 }
260
261 ops_ = ops_buffer;
262 ops_->shrink_to_fit();
263
264 return true;
265 }
266
InitializeMerge()267 void CowReader::InitializeMerge() {
268 uint64_t num_copy_ops = 0;
269
270 // Remove all the metadata operations
271 ops_->erase(std::remove_if(ops_.get()->begin(), ops_.get()->end(),
272 [](CowOperation& op) { return IsMetadataOp(op); }),
273 ops_.get()->end());
274
275 set_total_data_ops(ops_->size());
276 // We will re-arrange the vector in such a way that
277 // kernel can batch merge. Ex:
278 //
279 // Existing COW format; All the copy operations
280 // are at the beginning.
281 // =======================================
282 // Copy-op-1 - cow_op->new_block = 1
283 // Copy-op-2 - cow_op->new_block = 2
284 // Copy-op-3 - cow_op->new_block = 3
285 // Replace-op-4 - cow_op->new_block = 6
286 // Replace-op-5 - cow_op->new_block = 4
287 // Replace-op-6 - cow_op->new_block = 8
288 // Replace-op-7 - cow_op->new_block = 9
289 // Zero-op-8 - cow_op->new_block = 7
290 // Zero-op-9 - cow_op->new_block = 5
291 // =======================================
292 //
293 // First find the operation which isn't a copy-op
294 // and then sort all the operations in descending order
295 // with the key being cow_op->new_block (source block)
296 //
297 // The data-structure will look like:
298 //
299 // =======================================
300 // Copy-op-1 - cow_op->new_block = 1
301 // Copy-op-2 - cow_op->new_block = 2
302 // Copy-op-3 - cow_op->new_block = 3
303 // Replace-op-7 - cow_op->new_block = 9
304 // Replace-op-6 - cow_op->new_block = 8
305 // Zero-op-8 - cow_op->new_block = 7
306 // Replace-op-4 - cow_op->new_block = 6
307 // Zero-op-9 - cow_op->new_block = 5
308 // Replace-op-5 - cow_op->new_block = 4
309 // =======================================
310 //
311 // Daemon will read the above data-structure in reverse-order
312 // when reading metadata. Thus, kernel will get the metadata
313 // in the following order:
314 //
315 // ========================================
316 // Replace-op-5 - cow_op->new_block = 4
317 // Zero-op-9 - cow_op->new_block = 5
318 // Replace-op-4 - cow_op->new_block = 6
319 // Zero-op-8 - cow_op->new_block = 7
320 // Replace-op-6 - cow_op->new_block = 8
321 // Replace-op-7 - cow_op->new_block = 9
322 // Copy-op-3 - cow_op->new_block = 3
323 // Copy-op-2 - cow_op->new_block = 2
324 // Copy-op-1 - cow_op->new_block = 1
325 // ===========================================
326 //
327 // When merging begins, kernel will start from the last
328 // metadata which was read: In the above format, Copy-op-1
329 // will be the first merge operation.
330 //
331 // Now, batching of the merge operations happens only when
332 // 1: origin block numbers in the base device are contiguous
333 // (cow_op->new_block) and,
334 // 2: cow block numbers which are assigned by daemon in ReadMetadata()
335 // are contiguous. These are monotonically increasing numbers.
336 //
337 // When both (1) and (2) are true, kernel will batch merge the operations.
338 // In the above case, we have to ensure that the copy operations
339 // are merged first before replace operations are done. Hence,
340 // we will not change the order of copy operations. Since,
341 // cow_op->new_block numbers are contiguous, we will ensure that the
342 // cow block numbers assigned in ReadMetadata() for these respective copy
343 // operations are not contiguous forcing kernel to issue merge for each
344 // copy operations without batch merging.
345 //
346 // For all the other operations viz. Replace and Zero op, the cow block
347 // numbers assigned by daemon will be contiguous allowing kernel to batch
348 // merge.
349 //
350 // The final format after assiging COW block numbers by the daemon will
351 // look something like:
352 //
353 // =========================================================
354 // Replace-op-5 - cow_op->new_block = 4 cow-block-num = 2
355 // Zero-op-9 - cow_op->new_block = 5 cow-block-num = 3
356 // Replace-op-4 - cow_op->new_block = 6 cow-block-num = 4
357 // Zero-op-8 - cow_op->new_block = 7 cow-block-num = 5
358 // Replace-op-6 - cow_op->new_block = 8 cow-block-num = 6
359 // Replace-op-7 - cow_op->new_block = 9 cow-block-num = 7
360 // Copy-op-3 - cow_op->new_block = 3 cow-block-num = 9
361 // Copy-op-2 - cow_op->new_block = 2 cow-block-num = 11
362 // Copy-op-1 - cow_op->new_block = 1 cow-block-num = 13
363 // ==========================================================
364 //
365 // Merge sequence will look like:
366 //
367 // Merge-1 - Batch-merge { Copy-op-1, Copy-op-2, Copy-op-3 }
368 // Merge-2 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
369 // Replace-op-4, Zero-op-9, Replace-op-5 }
370 //==============================================================
371
372 num_copy_ops = FindNumCopyops();
373
374 std::sort(ops_.get()->begin() + num_copy_ops, ops_.get()->end(),
375 [](CowOperation& op1, CowOperation& op2) -> bool {
376 return op1.new_block > op2.new_block;
377 });
378
379 if (header_.num_merge_ops > 0) {
380 ops_->erase(ops_.get()->begin(), ops_.get()->begin() + header_.num_merge_ops);
381 }
382
383 num_copy_ops = FindNumCopyops();
384 set_copy_ops(num_copy_ops);
385 }
386
FindNumCopyops()387 uint64_t CowReader::FindNumCopyops() {
388 uint64_t num_copy_ops = 0;
389
390 for (uint64_t i = 0; i < ops_->size(); i++) {
391 auto& current_op = ops_->data()[i];
392 if (current_op.type != kCowCopyOp) {
393 break;
394 }
395 num_copy_ops += 1;
396 }
397
398 return num_copy_ops;
399 }
400
GetHeader(CowHeader * header)401 bool CowReader::GetHeader(CowHeader* header) {
402 *header = header_;
403 return true;
404 }
405
GetFooter(CowFooter * footer)406 bool CowReader::GetFooter(CowFooter* footer) {
407 if (!footer_) return false;
408 *footer = footer_.value();
409 return true;
410 }
411
GetLastLabel(uint64_t * label)412 bool CowReader::GetLastLabel(uint64_t* label) {
413 if (!last_label_) return false;
414 *label = last_label_.value();
415 return true;
416 }
417
418 class CowOpIter final : public ICowOpIter {
419 public:
420 CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops);
421
422 bool Done() override;
423 const CowOperation& Get() override;
424 void Next() override;
425
426 private:
427 std::shared_ptr<std::vector<CowOperation>> ops_;
428 std::vector<CowOperation>::iterator op_iter_;
429 };
430
CowOpIter(std::shared_ptr<std::vector<CowOperation>> & ops)431 CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops) {
432 ops_ = ops;
433 op_iter_ = ops_.get()->begin();
434 }
435
Done()436 bool CowOpIter::Done() {
437 return op_iter_ == ops_.get()->end();
438 }
439
Next()440 void CowOpIter::Next() {
441 CHECK(!Done());
442 op_iter_++;
443 }
444
Get()445 const CowOperation& CowOpIter::Get() {
446 CHECK(!Done());
447 return (*op_iter_);
448 }
449
450 class CowOpReverseIter final : public ICowOpReverseIter {
451 public:
452 explicit CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops);
453
454 bool Done() override;
455 const CowOperation& Get() override;
456 void Next() override;
457
458 private:
459 std::shared_ptr<std::vector<CowOperation>> ops_;
460 std::vector<CowOperation>::reverse_iterator op_riter_;
461 };
462
CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops)463 CowOpReverseIter::CowOpReverseIter(std::shared_ptr<std::vector<CowOperation>> ops) {
464 ops_ = ops;
465 op_riter_ = ops_.get()->rbegin();
466 }
467
Done()468 bool CowOpReverseIter::Done() {
469 return op_riter_ == ops_.get()->rend();
470 }
471
Next()472 void CowOpReverseIter::Next() {
473 CHECK(!Done());
474 op_riter_++;
475 }
476
Get()477 const CowOperation& CowOpReverseIter::Get() {
478 CHECK(!Done());
479 return (*op_riter_);
480 }
481
GetOpIter()482 std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
483 return std::make_unique<CowOpIter>(ops_);
484 }
485
GetRevOpIter()486 std::unique_ptr<ICowOpReverseIter> CowReader::GetRevOpIter() {
487 return std::make_unique<CowOpReverseIter>(ops_);
488 }
489
GetRawBytes(uint64_t offset,void * buffer,size_t len,size_t * read)490 bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
491 // Validate the offset, taking care to acknowledge possible overflow of offset+len.
492 if (offset < header_.header_size || offset >= fd_size_ - sizeof(CowFooter) || len >= fd_size_ ||
493 offset + len > fd_size_ - sizeof(CowFooter)) {
494 LOG(ERROR) << "invalid data offset: " << offset << ", " << len << " bytes";
495 return false;
496 }
497 if (lseek(fd_.get(), offset, SEEK_SET) < 0) {
498 PLOG(ERROR) << "lseek to read raw bytes failed";
499 return false;
500 }
501 ssize_t rv = TEMP_FAILURE_RETRY(::read(fd_.get(), buffer, len));
502 if (rv < 0) {
503 PLOG(ERROR) << "read failed";
504 return false;
505 }
506 *read = rv;
507 return true;
508 }
509
510 class CowDataStream final : public IByteStream {
511 public:
CowDataStream(CowReader * reader,uint64_t offset,size_t data_length)512 CowDataStream(CowReader* reader, uint64_t offset, size_t data_length)
513 : reader_(reader), offset_(offset), data_length_(data_length) {
514 remaining_ = data_length_;
515 }
516
Read(void * buffer,size_t length,size_t * read)517 bool Read(void* buffer, size_t length, size_t* read) override {
518 size_t to_read = std::min(length, remaining_);
519 if (!to_read) {
520 *read = 0;
521 return true;
522 }
523 if (!reader_->GetRawBytes(offset_, buffer, to_read, read)) {
524 return false;
525 }
526 offset_ += *read;
527 remaining_ -= *read;
528 return true;
529 }
530
Size() const531 size_t Size() const override { return data_length_; }
532
533 private:
534 CowReader* reader_;
535 uint64_t offset_;
536 size_t data_length_;
537 size_t remaining_;
538 };
539
ReadData(const CowOperation & op,IByteSink * sink)540 bool CowReader::ReadData(const CowOperation& op, IByteSink* sink) {
541 std::unique_ptr<IDecompressor> decompressor;
542 switch (op.compression) {
543 case kCowCompressNone:
544 decompressor = IDecompressor::Uncompressed();
545 break;
546 case kCowCompressGz:
547 decompressor = IDecompressor::Gz();
548 break;
549 case kCowCompressBrotli:
550 decompressor = IDecompressor::Brotli();
551 break;
552 default:
553 LOG(ERROR) << "Unknown compression type: " << op.compression;
554 return false;
555 }
556
557 CowDataStream stream(this, op.source, op.data_length);
558 decompressor->set_stream(&stream);
559 decompressor->set_sink(sink);
560 return decompressor->Decompress(header_.block_size);
561 }
562
563 } // namespace snapshot
564 } // namespace android
565