• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &current_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