• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2012 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 "update_engine/payload_consumer/delta_performer.h"
18 
19 #include <errno.h>
20 #include <linux/fs.h>
21 
22 #include <algorithm>
23 #include <cstring>
24 #include <map>
25 #include <memory>
26 #include <set>
27 #include <string>
28 #include <utility>
29 #include <vector>
30 
31 #include <base/files/file_util.h>
32 #include <base/format_macros.h>
33 #include <base/metrics/histogram_macros.h>
34 #include <base/strings/string_number_conversions.h>
35 #include <base/time/time.h>
36 #include <brillo/data_encoding.h>
37 #include <bsdiff/bspatch.h>
38 #include <google/protobuf/repeated_field.h>
39 #include <puffin/puffpatch.h>
40 
41 #include "update_engine/common/constants.h"
42 #include "update_engine/common/download_action.h"
43 #include "update_engine/common/error_code.h"
44 #include "update_engine/common/error_code_utils.h"
45 #include "update_engine/common/hardware_interface.h"
46 #include "update_engine/common/prefs_interface.h"
47 #include "update_engine/common/subprocess.h"
48 #include "update_engine/common/terminator.h"
49 #include "update_engine/common/utils.h"
50 #include "update_engine/payload_consumer/bzip_extent_writer.h"
51 #include "update_engine/payload_consumer/cached_file_descriptor.h"
52 #include "update_engine/payload_consumer/certificate_parser_interface.h"
53 #include "update_engine/payload_consumer/extent_reader.h"
54 #include "update_engine/payload_consumer/extent_writer.h"
55 #include "update_engine/payload_consumer/partition_update_generator_interface.h"
56 #include "update_engine/payload_consumer/partition_writer.h"
57 #if USE_FEC
58 #include "update_engine/payload_consumer/fec_file_descriptor.h"
59 #endif  // USE_FEC
60 #include "update_engine/payload_consumer/file_descriptor_utils.h"
61 #include "update_engine/payload_consumer/mount_history.h"
62 #include "update_engine/payload_consumer/payload_constants.h"
63 #include "update_engine/payload_consumer/payload_verifier.h"
64 #include "update_engine/payload_consumer/xz_extent_writer.h"
65 
66 using google::protobuf::RepeatedPtrField;
67 using std::min;
68 using std::string;
69 using std::vector;
70 
71 namespace chromeos_update_engine {
72 const unsigned DeltaPerformer::kProgressLogMaxChunks = 10;
73 const unsigned DeltaPerformer::kProgressLogTimeoutSeconds = 30;
74 const unsigned DeltaPerformer::kProgressDownloadWeight = 50;
75 const unsigned DeltaPerformer::kProgressOperationsWeight = 50;
76 const uint64_t DeltaPerformer::kCheckpointFrequencySeconds = 1;
77 
78 namespace {
79 const int kUpdateStateOperationInvalid = -1;
80 const int kMaxResumedUpdateFailures = 10;
81 
82 }  // namespace
83 
84 // Computes the ratio of |part| and |total|, scaled to |norm|, using integer
85 // arithmetic.
IntRatio(uint64_t part,uint64_t total,uint64_t norm)86 static uint64_t IntRatio(uint64_t part, uint64_t total, uint64_t norm) {
87   return part * norm / total;
88 }
89 
LogProgress(const char * message_prefix)90 void DeltaPerformer::LogProgress(const char* message_prefix) {
91   // Format operations total count and percentage.
92   string total_operations_str("?");
93   string completed_percentage_str("");
94   if (num_total_operations_) {
95     total_operations_str = std::to_string(num_total_operations_);
96     // Upcasting to 64-bit to avoid overflow, back to size_t for formatting.
97     completed_percentage_str = base::StringPrintf(
98         " (%" PRIu64 "%%)",
99         IntRatio(next_operation_num_, num_total_operations_, 100));
100   }
101 
102   // Format download total count and percentage.
103   size_t payload_size = payload_->size;
104   string payload_size_str("?");
105   string downloaded_percentage_str("");
106   if (payload_size) {
107     payload_size_str = std::to_string(payload_size);
108     // Upcasting to 64-bit to avoid overflow, back to size_t for formatting.
109     downloaded_percentage_str = base::StringPrintf(
110         " (%" PRIu64 "%%)", IntRatio(total_bytes_received_, payload_size, 100));
111   }
112 
113   LOG(INFO) << (message_prefix ? message_prefix : "") << next_operation_num_
114             << "/" << total_operations_str << " operations"
115             << completed_percentage_str << ", " << total_bytes_received_ << "/"
116             << payload_size_str << " bytes downloaded"
117             << downloaded_percentage_str << ", overall progress "
118             << overall_progress_ << "%";
119 }
120 
UpdateOverallProgress(bool force_log,const char * message_prefix)121 void DeltaPerformer::UpdateOverallProgress(bool force_log,
122                                            const char* message_prefix) {
123   // Compute our download and overall progress.
124   unsigned new_overall_progress = 0;
125   static_assert(kProgressDownloadWeight + kProgressOperationsWeight == 100,
126                 "Progress weights don't add up");
127   // Only consider download progress if its total size is known; otherwise
128   // adjust the operations weight to compensate for the absence of download
129   // progress. Also, make sure to cap the download portion at
130   // kProgressDownloadWeight, in case we end up downloading more than we
131   // initially expected (this indicates a problem, but could generally happen).
132   // TODO(garnold) the correction of operations weight when we do not have the
133   // total payload size, as well as the conditional guard below, should both be
134   // eliminated once we ensure that the payload_size in the install plan is
135   // always given and is non-zero. This currently isn't the case during unit
136   // tests (see chromium-os:37969).
137   size_t payload_size = payload_->size;
138   unsigned actual_operations_weight = kProgressOperationsWeight;
139   if (payload_size)
140     new_overall_progress +=
141         min(static_cast<unsigned>(IntRatio(
142                 total_bytes_received_, payload_size, kProgressDownloadWeight)),
143             kProgressDownloadWeight);
144   else
145     actual_operations_weight += kProgressDownloadWeight;
146 
147   // Only add completed operations if their total number is known; we definitely
148   // expect an update to have at least one operation, so the expectation is that
149   // this will eventually reach |actual_operations_weight|.
150   if (num_total_operations_)
151     new_overall_progress += IntRatio(
152         next_operation_num_, num_total_operations_, actual_operations_weight);
153 
154   // Progress ratio cannot recede, unless our assumptions about the total
155   // payload size, total number of operations, or the monotonicity of progress
156   // is breached.
157   if (new_overall_progress < overall_progress_) {
158     LOG(WARNING) << "progress counter receded from " << overall_progress_
159                  << "% down to " << new_overall_progress << "%; this is a bug";
160     force_log = true;
161   }
162   overall_progress_ = new_overall_progress;
163 
164   // Update chunk index, log as needed: if forced by called, or we completed a
165   // progress chunk, or a timeout has expired.
166   base::TimeTicks curr_time = base::TimeTicks::Now();
167   unsigned curr_progress_chunk =
168       overall_progress_ * kProgressLogMaxChunks / 100;
169   if (force_log || curr_progress_chunk > last_progress_chunk_ ||
170       curr_time > forced_progress_log_time_) {
171     forced_progress_log_time_ = curr_time + forced_progress_log_wait_;
172     LogProgress(message_prefix);
173   }
174   last_progress_chunk_ = curr_progress_chunk;
175 }
176 
CopyDataToBuffer(const char ** bytes_p,size_t * count_p,size_t max)177 size_t DeltaPerformer::CopyDataToBuffer(const char** bytes_p,
178                                         size_t* count_p,
179                                         size_t max) {
180   const size_t count = *count_p;
181   if (!count)
182     return 0;  // Special case shortcut.
183   size_t read_len = min(count, max - buffer_.size());
184   const char* bytes_start = *bytes_p;
185   const char* bytes_end = bytes_start + read_len;
186   buffer_.reserve(max);
187   buffer_.insert(buffer_.end(), bytes_start, bytes_end);
188   *bytes_p = bytes_end;
189   *count_p = count - read_len;
190   return read_len;
191 }
192 
HandleOpResult(bool op_result,const char * op_type_name,ErrorCode * error)193 bool DeltaPerformer::HandleOpResult(bool op_result,
194                                     const char* op_type_name,
195                                     ErrorCode* error) {
196   if (op_result)
197     return true;
198 
199   LOG(ERROR) << "Failed to perform " << op_type_name << " operation "
200              << next_operation_num_ << ", which is the operation "
201              << GetPartitionOperationNum() << " in partition \""
202              << partitions_[current_partition_].partition_name() << "\"";
203   if (*error == ErrorCode::kSuccess)
204     *error = ErrorCode::kDownloadOperationExecutionError;
205   return false;
206 }
207 
Close()208 int DeltaPerformer::Close() {
209   int err = -CloseCurrentPartition();
210   LOG_IF(ERROR,
211          !payload_hash_calculator_.Finalize() ||
212              !signed_hash_calculator_.Finalize())
213       << "Unable to finalize the hash.";
214   if (!buffer_.empty()) {
215     LOG(INFO) << "Discarding " << buffer_.size() << " unused downloaded bytes";
216     if (err >= 0)
217       err = 1;
218   }
219   return -err;
220 }
221 
CloseCurrentPartition()222 int DeltaPerformer::CloseCurrentPartition() {
223   if (!partition_writer_) {
224     return 0;
225   }
226   int err = partition_writer_->Close();
227   partition_writer_ = nullptr;
228   return err;
229 }
230 
OpenCurrentPartition()231 bool DeltaPerformer::OpenCurrentPartition() {
232   if (current_partition_ >= partitions_.size())
233     return false;
234 
235   const PartitionUpdate& partition = partitions_[current_partition_];
236   size_t num_previous_partitions =
237       install_plan_->partitions.size() - partitions_.size();
238   const InstallPlan::Partition& install_part =
239       install_plan_->partitions[num_previous_partitions + current_partition_];
240   auto dynamic_control = boot_control_->GetDynamicPartitionControl();
241   partition_writer_ = CreatePartitionWriter(
242       partition,
243       install_part,
244       dynamic_control,
245       block_size_,
246       interactive_,
247       IsDynamicPartition(install_part.name, install_plan_->target_slot));
248   // Open source fds if we have a delta payload, or for partitions in the
249   // partial update.
250   const bool source_may_exist = manifest_.partial_update() ||
251                                 payload_->type == InstallPayloadType::kDelta;
252   const size_t partition_operation_num = GetPartitionOperationNum();
253 
254   TEST_AND_RETURN_FALSE(partition_writer_->Init(
255       install_plan_, source_may_exist, partition_operation_num));
256   CheckpointUpdateProgress(true);
257   return true;
258 }
259 
GetPartitionOperationNum()260 size_t DeltaPerformer::GetPartitionOperationNum() {
261   return next_operation_num_ -
262          (current_partition_ ? acc_num_operations_[current_partition_ - 1] : 0);
263 }
264 
265 namespace {
266 
LogPartitionInfoHash(const PartitionInfo & info,const string & tag)267 void LogPartitionInfoHash(const PartitionInfo& info, const string& tag) {
268   string sha256 = HexEncode(info.hash());
269   LOG(INFO) << "PartitionInfo " << tag << " sha256: " << sha256
270             << " size: " << info.size();
271 }
272 
LogPartitionInfo(const vector<PartitionUpdate> & partitions)273 void LogPartitionInfo(const vector<PartitionUpdate>& partitions) {
274   for (const PartitionUpdate& partition : partitions) {
275     if (partition.has_old_partition_info()) {
276       LogPartitionInfoHash(partition.old_partition_info(),
277                            "old " + partition.partition_name());
278     }
279     LogPartitionInfoHash(partition.new_partition_info(),
280                          "new " + partition.partition_name());
281   }
282 }
283 
284 }  // namespace
285 
IsHeaderParsed() const286 bool DeltaPerformer::IsHeaderParsed() const {
287   return metadata_size_ != 0;
288 }
289 
ParsePayloadMetadata(const brillo::Blob & payload,ErrorCode * error)290 MetadataParseResult DeltaPerformer::ParsePayloadMetadata(
291     const brillo::Blob& payload, ErrorCode* error) {
292   *error = ErrorCode::kSuccess;
293 
294   if (!IsHeaderParsed()) {
295     MetadataParseResult result =
296         payload_metadata_.ParsePayloadHeader(payload, error);
297     if (result != MetadataParseResult::kSuccess)
298       return result;
299 
300     metadata_size_ = payload_metadata_.GetMetadataSize();
301     metadata_signature_size_ = payload_metadata_.GetMetadataSignatureSize();
302     major_payload_version_ = payload_metadata_.GetMajorVersion();
303 
304     // If the metadata size is present in install plan, check for it immediately
305     // even before waiting for that many number of bytes to be downloaded in the
306     // payload. This will prevent any attack which relies on us downloading data
307     // beyond the expected metadata size.
308     if (install_plan_->hash_checks_mandatory) {
309       if (payload_->metadata_size != metadata_size_) {
310         LOG(ERROR) << "Mandatory metadata size in Omaha response ("
311                    << payload_->metadata_size
312                    << ") is missing/incorrect, actual = " << metadata_size_;
313         *error = ErrorCode::kDownloadInvalidMetadataSize;
314         return MetadataParseResult::kError;
315       }
316     }
317 
318     // Check that the |metadata signature size_| and |metadata_size_| are not
319     // very big numbers. This is necessary since |update_engine| needs to write
320     // these values into the buffer before being able to use them, and if an
321     // attacker sets these values to a very big number, the buffer will overflow
322     // and |update_engine| will crash. A simple way of solving this is to check
323     // that the size of both values is smaller than the payload itself.
324     if (metadata_size_ + metadata_signature_size_ > payload_->size) {
325       LOG(ERROR) << "The size of the metadata_size(" << metadata_size_ << ")"
326                  << " or metadata signature(" << metadata_signature_size_ << ")"
327                  << " is greater than the size of the payload"
328                  << "(" << payload_->size << ")";
329       *error = ErrorCode::kDownloadInvalidMetadataSize;
330       return MetadataParseResult::kError;
331     }
332   }
333 
334   // Now that we have validated the metadata size, we should wait for the full
335   // metadata and its signature (if exist) to be read in before we can parse it.
336   if (payload.size() < metadata_size_ + metadata_signature_size_)
337     return MetadataParseResult::kInsufficientData;
338 
339   // Log whether we validated the size or simply trusting what's in the payload
340   // here. This is logged here (after we received the full metadata data) so
341   // that we just log once (instead of logging n times) if it takes n
342   // DeltaPerformer::Write calls to download the full manifest.
343   if (payload_->metadata_size == metadata_size_) {
344     LOG(INFO) << "Manifest size in payload matches expected value from Omaha";
345   } else {
346     // For mandatory-cases, we'd have already returned a kMetadataParseError
347     // above. We'll be here only for non-mandatory cases. Just send a UMA stat.
348     LOG(WARNING) << "Ignoring missing/incorrect metadata size ("
349                  << payload_->metadata_size
350                  << ") in Omaha response as validation is not mandatory. "
351                  << "Trusting metadata size in payload = " << metadata_size_;
352   }
353 
354   // NOLINTNEXTLINE(whitespace/braces)
355   auto [payload_verifier, perform_verification] = CreatePayloadVerifier();
356   if (!payload_verifier) {
357     LOG(ERROR) << "Failed to create payload verifier.";
358     *error = ErrorCode::kDownloadMetadataSignatureVerificationError;
359     if (perform_verification) {
360       return MetadataParseResult::kError;
361     }
362   } else {
363     // We have the full metadata in |payload|. Verify its integrity
364     // and authenticity based on the information we have in Omaha response.
365     *error = payload_metadata_.ValidateMetadataSignature(
366         payload, payload_->metadata_signature, *payload_verifier);
367   }
368   if (*error != ErrorCode::kSuccess) {
369     if (install_plan_->hash_checks_mandatory) {
370       // The autoupdate_CatchBadSignatures test checks for this string
371       // in log-files. Keep in sync.
372       LOG(ERROR) << "Mandatory metadata signature validation failed";
373       return MetadataParseResult::kError;
374     }
375 
376     // For non-mandatory cases, just send a UMA stat.
377     LOG(WARNING) << "Ignoring metadata signature validation failures";
378     *error = ErrorCode::kSuccess;
379   }
380 
381   // The payload metadata is deemed valid, it's safe to parse the protobuf.
382   if (!payload_metadata_.GetManifest(payload, &manifest_)) {
383     LOG(ERROR) << "Unable to parse manifest in update file.";
384     *error = ErrorCode::kDownloadManifestParseError;
385     return MetadataParseResult::kError;
386   }
387 
388   manifest_parsed_ = true;
389   return MetadataParseResult::kSuccess;
390 }
391 
392 #define OP_DURATION_HISTOGRAM(_op_name, _start_time)                        \
393   LOCAL_HISTOGRAM_CUSTOM_TIMES(                                             \
394       "UpdateEngine.DownloadAction.InstallOperation::" + string(_op_name) + \
395           ".Duration",                                                      \
396       (base::TimeTicks::Now() - _start_time),                               \
397       base::TimeDelta::FromMilliseconds(10),                                \
398       base::TimeDelta::FromMinutes(5),                                      \
399       20);
400 
401 // Wrapper around write. Returns true if all requested bytes
402 // were written, or false on any error, regardless of progress
403 // and stores an action exit code in |error|.
Write(const void * bytes,size_t count,ErrorCode * error)404 bool DeltaPerformer::Write(const void* bytes, size_t count, ErrorCode* error) {
405   *error = ErrorCode::kSuccess;
406   const char* c_bytes = reinterpret_cast<const char*>(bytes);
407 
408   // Update the total byte downloaded count and the progress logs.
409   total_bytes_received_ += count;
410   UpdateOverallProgress(false, "Completed ");
411 
412   while (!manifest_valid_) {
413     // Read data up to the needed limit; this is either maximium payload header
414     // size, or the full metadata size (once it becomes known).
415     const bool do_read_header = !IsHeaderParsed();
416     CopyDataToBuffer(
417         &c_bytes,
418         &count,
419         (do_read_header ? kMaxPayloadHeaderSize
420                         : metadata_size_ + metadata_signature_size_));
421 
422     MetadataParseResult result = ParsePayloadMetadata(buffer_, error);
423     if (result == MetadataParseResult::kError)
424       return false;
425     if (result == MetadataParseResult::kInsufficientData) {
426       // If we just processed the header, make an attempt on the manifest.
427       if (do_read_header && IsHeaderParsed())
428         continue;
429 
430       return true;
431     }
432 
433     // Checks the integrity of the payload manifest.
434     if ((*error = ValidateManifest()) != ErrorCode::kSuccess)
435       return false;
436     manifest_valid_ = true;
437     if (!install_plan_->is_resume) {
438       auto begin = reinterpret_cast<const char*>(buffer_.data());
439       prefs_->SetString(kPrefsManifestBytes, {begin, buffer_.size()});
440     }
441 
442     // Clear the download buffer.
443     DiscardBuffer(false, metadata_size_);
444 
445     block_size_ = manifest_.block_size();
446 
447     // This populates |partitions_| and the |install_plan.partitions| with the
448     // list of partitions from the manifest.
449     if (!ParseManifestPartitions(error))
450       return false;
451 
452     // |install_plan.partitions| was filled in, nothing need to be done here if
453     // the payload was already applied, returns false to terminate http fetcher,
454     // but keep |error| as ErrorCode::kSuccess.
455     if (payload_->already_applied)
456       return false;
457 
458     num_total_operations_ = 0;
459     for (const auto& partition : partitions_) {
460       num_total_operations_ += partition.operations_size();
461       acc_num_operations_.push_back(num_total_operations_);
462     }
463 
464     LOG_IF(WARNING,
465            !prefs_->SetInt64(kPrefsManifestMetadataSize, metadata_size_))
466         << "Unable to save the manifest metadata size.";
467     LOG_IF(WARNING,
468            !prefs_->SetInt64(kPrefsManifestSignatureSize,
469                              metadata_signature_size_))
470         << "Unable to save the manifest signature size.";
471 
472     if (!PrimeUpdateState()) {
473       *error = ErrorCode::kDownloadStateInitializationError;
474       LOG(ERROR) << "Unable to prime the update state.";
475       return false;
476     }
477 
478     if (next_operation_num_ < acc_num_operations_[current_partition_]) {
479       if (!OpenCurrentPartition()) {
480         *error = ErrorCode::kInstallDeviceOpenError;
481         return false;
482       }
483     }
484 
485     if (next_operation_num_ > 0)
486       UpdateOverallProgress(true, "Resuming after ");
487     LOG(INFO) << "Starting to apply update payload operations";
488   }
489 
490   while (next_operation_num_ < num_total_operations_) {
491     // Check if we should cancel the current attempt for any reason.
492     // In this case, *error will have already been populated with the reason
493     // why we're canceling.
494     if (download_delegate_ && download_delegate_->ShouldCancel(error))
495       return false;
496 
497     // We know there are more operations to perform because we didn't reach the
498     // |num_total_operations_| limit yet.
499     if (next_operation_num_ >= acc_num_operations_[current_partition_]) {
500       if (partition_writer_) {
501         if (!partition_writer_->FinishedInstallOps()) {
502           *error = ErrorCode::kDownloadWriteError;
503           return false;
504         }
505       }
506       CloseCurrentPartition();
507       // Skip until there are operations for current_partition_.
508       while (next_operation_num_ >= acc_num_operations_[current_partition_]) {
509         current_partition_++;
510       }
511       if (!OpenCurrentPartition()) {
512         *error = ErrorCode::kInstallDeviceOpenError;
513         return false;
514       }
515     }
516 
517     const InstallOperation& op =
518         partitions_[current_partition_].operations(GetPartitionOperationNum());
519 
520     CopyDataToBuffer(&c_bytes, &count, op.data_length());
521 
522     // Check whether we received all of the next operation's data payload.
523     if (!CanPerformInstallOperation(op))
524       return true;
525 
526     // Validate the operation unconditionally. This helps prevent the
527     // exploitation of vulnerabilities in the patching libraries, e.g. bspatch.
528     // The hash of the patch data for a given operation is embedded in the
529     // payload metadata; and thus has been verified against the public key on
530     // device.
531     // Note: Validate must be called only if CanPerformInstallOperation is
532     // called. Otherwise, we might be failing operations before even if there
533     // isn't sufficient data to compute the proper hash.
534     *error = ValidateOperationHash(op);
535     if (*error != ErrorCode::kSuccess) {
536       if (install_plan_->hash_checks_mandatory) {
537         LOG(ERROR) << "Mandatory operation hash check failed";
538         return false;
539       }
540 
541       // For non-mandatory cases, just send a UMA stat.
542       LOG(WARNING) << "Ignoring operation validation errors";
543       *error = ErrorCode::kSuccess;
544     }
545 
546     // Makes sure we unblock exit when this operation completes.
547     ScopedTerminatorExitUnblocker exit_unblocker =
548         ScopedTerminatorExitUnblocker();  // Avoids a compiler unused var bug.
549 
550     base::TimeTicks op_start_time = base::TimeTicks::Now();
551 
552     bool op_result;
553     const string op_name = InstallOperationTypeName(op.type());
554     switch (op.type()) {
555       case InstallOperation::REPLACE:
556       case InstallOperation::REPLACE_BZ:
557       case InstallOperation::REPLACE_XZ:
558         op_result = PerformReplaceOperation(op);
559         OP_DURATION_HISTOGRAM("REPLACE", op_start_time);
560         break;
561       case InstallOperation::ZERO:
562       case InstallOperation::DISCARD:
563         op_result = PerformZeroOrDiscardOperation(op);
564         OP_DURATION_HISTOGRAM("ZERO_OR_DISCARD", op_start_time);
565         break;
566       case InstallOperation::SOURCE_COPY:
567         op_result = PerformSourceCopyOperation(op, error);
568         OP_DURATION_HISTOGRAM("SOURCE_COPY", op_start_time);
569         break;
570       case InstallOperation::SOURCE_BSDIFF:
571       case InstallOperation::BROTLI_BSDIFF:
572       case InstallOperation::PUFFDIFF:
573       case InstallOperation::ZUCCHINI:
574       case InstallOperation::LZ4DIFF_PUFFDIFF:
575       case InstallOperation::LZ4DIFF_BSDIFF:
576         op_result = PerformDiffOperation(op, error);
577         OP_DURATION_HISTOGRAM(op_name, op_start_time);
578         break;
579       default:
580         op_result = false;
581     }
582     if (!HandleOpResult(op_result, op_name.c_str(), error))
583       return false;
584 
585     next_operation_num_++;
586     UpdateOverallProgress(false, "Completed ");
587     CheckpointUpdateProgress(false);
588   }
589 
590   if (partition_writer_) {
591     TEST_AND_RETURN_FALSE(partition_writer_->FinishedInstallOps());
592   }
593   CloseCurrentPartition();
594 
595   // In major version 2, we don't add unused operation to the payload.
596   // If we already extracted the signature we should skip this step.
597   if (manifest_.has_signatures_offset() && manifest_.has_signatures_size() &&
598       signatures_message_data_.empty()) {
599     if (manifest_.signatures_offset() != buffer_offset_) {
600       LOG(ERROR) << "Payload signatures offset points to blob offset "
601                  << manifest_.signatures_offset()
602                  << " but signatures are expected at offset " << buffer_offset_;
603       *error = ErrorCode::kDownloadPayloadVerificationError;
604       return false;
605     }
606     CopyDataToBuffer(&c_bytes, &count, manifest_.signatures_size());
607     // Needs more data to cover entire signature.
608     if (buffer_.size() < manifest_.signatures_size())
609       return true;
610     if (!ExtractSignatureMessage()) {
611       LOG(ERROR) << "Extract payload signature failed.";
612       *error = ErrorCode::kDownloadPayloadVerificationError;
613       return false;
614     }
615     DiscardBuffer(true, 0);
616     // Since we extracted the SignatureMessage we need to advance the
617     // checkpoint, otherwise we would reload the signature and try to extract
618     // it again.
619     // This is the last checkpoint for an update, force this checkpoint to be
620     // saved.
621     CheckpointUpdateProgress(true);
622   }
623 
624   return true;
625 }
626 
IsManifestValid()627 bool DeltaPerformer::IsManifestValid() {
628   return manifest_valid_;
629 }
630 
ParseManifestPartitions(ErrorCode * error)631 bool DeltaPerformer::ParseManifestPartitions(ErrorCode* error) {
632   partitions_.assign(manifest_.partitions().begin(),
633                      manifest_.partitions().end());
634 
635   // For VAB and partial updates, the partition preparation will copy the
636   // dynamic partitions metadata to the target metadata slot, and rename the
637   // slot suffix of the partitions in the metadata.
638   if (install_plan_->target_slot != BootControlInterface::kInvalidSlot) {
639     uint64_t required_size = 0;
640     if (!PreparePartitionsForUpdate(&required_size)) {
641       if (required_size > 0) {
642         *error = ErrorCode::kNotEnoughSpace;
643       } else {
644         *error = ErrorCode::kInstallDeviceOpenError;
645       }
646       return false;
647     }
648   }
649 
650   // Partitions in manifest are no longer needed after preparing partitions.
651   manifest_.clear_partitions();
652   // TODO(xunchang) TBD: allow partial update only on devices with dynamic
653   // partition.
654   if (manifest_.partial_update()) {
655     std::set<std::string> touched_partitions;
656     for (const auto& partition_update : partitions_) {
657       touched_partitions.insert(partition_update.partition_name());
658     }
659 
660     auto generator = partition_update_generator::Create(boot_control_,
661                                                         manifest_.block_size());
662     std::vector<PartitionUpdate> untouched_static_partitions;
663     TEST_AND_RETURN_FALSE(
664         generator->GenerateOperationsForPartitionsNotInPayload(
665             install_plan_->source_slot,
666             install_plan_->target_slot,
667             touched_partitions,
668             &untouched_static_partitions));
669     partitions_.insert(partitions_.end(),
670                        untouched_static_partitions.begin(),
671                        untouched_static_partitions.end());
672 
673     // Save the untouched dynamic partitions in install plan.
674     std::vector<std::string> dynamic_partitions;
675     if (!boot_control_->GetDynamicPartitionControl()
676              ->ListDynamicPartitionsForSlot(install_plan_->source_slot,
677                                             boot_control_->GetCurrentSlot(),
678                                             &dynamic_partitions)) {
679       LOG(ERROR) << "Failed to load dynamic partitions from slot "
680                  << install_plan_->source_slot;
681       return false;
682     }
683     install_plan_->untouched_dynamic_partitions.clear();
684     for (const auto& name : dynamic_partitions) {
685       if (touched_partitions.find(name) == touched_partitions.end()) {
686         install_plan_->untouched_dynamic_partitions.push_back(name);
687       }
688     }
689   }
690 
691   if (!install_plan_->ParsePartitions(
692           partitions_, boot_control_, block_size_, error)) {
693     return false;
694   }
695 
696   LogPartitionInfo(partitions_);
697   return true;
698 }
699 
PreparePartitionsForUpdate(uint64_t * required_size)700 bool DeltaPerformer::PreparePartitionsForUpdate(uint64_t* required_size) {
701   // Call static PreparePartitionsForUpdate with hash from
702   // kPrefsUpdateCheckResponseHash to ensure hash of payload that space is
703   // preallocated for is the same as the hash of payload being applied.
704   string update_check_response_hash;
705   ignore_result(prefs_->GetString(kPrefsUpdateCheckResponseHash,
706                                   &update_check_response_hash));
707   return PreparePartitionsForUpdate(prefs_,
708                                     boot_control_,
709                                     install_plan_->target_slot,
710                                     manifest_,
711                                     update_check_response_hash,
712                                     required_size);
713 }
714 
PreparePartitionsForUpdate(PrefsInterface * prefs,BootControlInterface * boot_control,BootControlInterface::Slot target_slot,const DeltaArchiveManifest & manifest,const std::string & update_check_response_hash,uint64_t * required_size)715 bool DeltaPerformer::PreparePartitionsForUpdate(
716     PrefsInterface* prefs,
717     BootControlInterface* boot_control,
718     BootControlInterface::Slot target_slot,
719     const DeltaArchiveManifest& manifest,
720     const std::string& update_check_response_hash,
721     uint64_t* required_size) {
722   string last_hash;
723   ignore_result(
724       prefs->GetString(kPrefsDynamicPartitionMetadataUpdated, &last_hash));
725 
726   bool is_resume = !update_check_response_hash.empty() &&
727                    last_hash == update_check_response_hash;
728 
729   if (is_resume) {
730     LOG(INFO) << "Using previously prepared partitions for update. hash = "
731               << last_hash;
732   } else {
733     LOG(INFO) << "Preparing partitions for new update. last hash = "
734               << last_hash << ", new hash = " << update_check_response_hash;
735     ResetUpdateProgress(prefs, false);
736   }
737 
738   if (!boot_control->GetDynamicPartitionControl()->PreparePartitionsForUpdate(
739           boot_control->GetCurrentSlot(),
740           target_slot,
741           manifest,
742           !is_resume /* should update */,
743           required_size)) {
744     LOG(ERROR) << "Unable to initialize partition metadata for slot "
745                << BootControlInterface::SlotName(target_slot);
746     return false;
747   }
748 
749   TEST_AND_RETURN_FALSE(prefs->SetString(kPrefsDynamicPartitionMetadataUpdated,
750                                          update_check_response_hash));
751   LOG(INFO) << "PreparePartitionsForUpdate done.";
752 
753   return true;
754 }
755 
CanPerformInstallOperation(const chromeos_update_engine::InstallOperation & operation)756 bool DeltaPerformer::CanPerformInstallOperation(
757     const chromeos_update_engine::InstallOperation& operation) {
758   // If we don't have a data blob we can apply it right away.
759   if (!operation.has_data_offset() && !operation.has_data_length())
760     return true;
761 
762   // See if we have the entire data blob in the buffer
763   if (operation.data_offset() < buffer_offset_) {
764     LOG(ERROR) << "we threw away data it seems?";
765     return false;
766   }
767 
768   return (operation.data_offset() + operation.data_length() <=
769           buffer_offset_ + buffer_.size());
770 }
771 
PerformReplaceOperation(const InstallOperation & operation)772 bool DeltaPerformer::PerformReplaceOperation(
773     const InstallOperation& operation) {
774   CHECK(operation.type() == InstallOperation::REPLACE ||
775         operation.type() == InstallOperation::REPLACE_BZ ||
776         operation.type() == InstallOperation::REPLACE_XZ);
777 
778   // Since we delete data off the beginning of the buffer as we use it,
779   // the data we need should be exactly at the beginning of the buffer.
780   TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length());
781 
782   TEST_AND_RETURN_FALSE(partition_writer_->PerformReplaceOperation(
783       operation, buffer_.data(), buffer_.size()));
784   // Update buffer
785   DiscardBuffer(true, buffer_.size());
786   return true;
787 }
788 
PerformZeroOrDiscardOperation(const InstallOperation & operation)789 bool DeltaPerformer::PerformZeroOrDiscardOperation(
790     const InstallOperation& operation) {
791   CHECK(operation.type() == InstallOperation::DISCARD ||
792         operation.type() == InstallOperation::ZERO);
793 
794   // These operations have no blob.
795   TEST_AND_RETURN_FALSE(!operation.has_data_offset());
796   TEST_AND_RETURN_FALSE(!operation.has_data_length());
797 
798   return partition_writer_->PerformZeroOrDiscardOperation(operation);
799 }
800 
PerformSourceCopyOperation(const InstallOperation & operation,ErrorCode * error)801 bool DeltaPerformer::PerformSourceCopyOperation(
802     const InstallOperation& operation, ErrorCode* error) {
803   if (operation.has_src_length())
804     TEST_AND_RETURN_FALSE(operation.src_length() % block_size_ == 0);
805   if (operation.has_dst_length())
806     TEST_AND_RETURN_FALSE(operation.dst_length() % block_size_ == 0);
807   return partition_writer_->PerformSourceCopyOperation(operation, error);
808 }
809 
ExtentsToBsdiffPositionsString(const RepeatedPtrField<Extent> & extents,uint64_t block_size,uint64_t full_length,string * positions_string)810 bool DeltaPerformer::ExtentsToBsdiffPositionsString(
811     const RepeatedPtrField<Extent>& extents,
812     uint64_t block_size,
813     uint64_t full_length,
814     string* positions_string) {
815   string ret;
816   uint64_t length = 0;
817   for (const Extent& extent : extents) {
818     int64_t start = extent.start_block() * block_size;
819     uint64_t this_length =
820         min(full_length - length,
821             static_cast<uint64_t>(extent.num_blocks()) * block_size);
822     ret += base::StringPrintf("%" PRIi64 ":%" PRIu64 ",", start, this_length);
823     length += this_length;
824   }
825   TEST_AND_RETURN_FALSE(length == full_length);
826   if (!ret.empty())
827     ret.resize(ret.size() - 1);  // Strip trailing comma off
828   *positions_string = ret;
829   return true;
830 }
831 
PerformDiffOperation(const InstallOperation & operation,ErrorCode * error)832 bool DeltaPerformer::PerformDiffOperation(const InstallOperation& operation,
833                                           ErrorCode* error) {
834   // Since we delete data off the beginning of the buffer as we use it,
835   // the data we need should be exactly at the beginning of the buffer.
836   TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset());
837   TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length());
838   if (operation.has_src_length())
839     TEST_AND_RETURN_FALSE(operation.src_length() % block_size_ == 0);
840   if (operation.has_dst_length())
841     TEST_AND_RETURN_FALSE(operation.dst_length() % block_size_ == 0);
842 
843   TEST_AND_RETURN_FALSE(partition_writer_->PerformDiffOperation(
844       operation, error, buffer_.data(), buffer_.size()));
845   DiscardBuffer(true, buffer_.size());
846   return true;
847 }
848 
ExtractSignatureMessage()849 bool DeltaPerformer::ExtractSignatureMessage() {
850   TEST_AND_RETURN_FALSE(signatures_message_data_.empty());
851   TEST_AND_RETURN_FALSE(buffer_offset_ == manifest_.signatures_offset());
852   TEST_AND_RETURN_FALSE(buffer_.size() >= manifest_.signatures_size());
853   signatures_message_data_.assign(
854       buffer_.begin(), buffer_.begin() + manifest_.signatures_size());
855 
856   LOG(INFO) << "Extracted signature data of size "
857             << manifest_.signatures_size() << " at "
858             << manifest_.signatures_offset();
859   return true;
860 }
861 
GetPublicKey(string * out_public_key)862 bool DeltaPerformer::GetPublicKey(string* out_public_key) {
863   out_public_key->clear();
864 
865   if (utils::FileExists(public_key_path_.c_str())) {
866     LOG(INFO) << "Verifying using public key: " << public_key_path_;
867     return utils::ReadFile(public_key_path_, out_public_key);
868   }
869 
870   // If this is an official build then we are not allowed to use public key
871   // from Omaha response.
872   if (!hardware_->IsOfficialBuild() && !install_plan_->public_key_rsa.empty()) {
873     LOG(INFO) << "Verifying using public key from Omaha response.";
874     return brillo::data_encoding::Base64Decode(install_plan_->public_key_rsa,
875                                                out_public_key);
876   }
877   LOG(INFO) << "No public keys found for verification.";
878   return true;
879 }
880 
881 std::pair<std::unique_ptr<PayloadVerifier>, bool>
CreatePayloadVerifier()882 DeltaPerformer::CreatePayloadVerifier() {
883   if (utils::FileExists(update_certificates_path_.c_str())) {
884     LOG(INFO) << "Verifying using certificates: " << update_certificates_path_;
885     return {
886         PayloadVerifier::CreateInstanceFromZipPath(update_certificates_path_),
887         true};
888   }
889 
890   string public_key;
891   if (!GetPublicKey(&public_key)) {
892     LOG(ERROR) << "Failed to read public key";
893     return {nullptr, true};
894   }
895 
896   // Skips the verification if the public key is empty.
897   if (public_key.empty()) {
898     return {nullptr, false};
899   }
900   LOG(INFO) << "Verifing using public key: " << public_key;
901   return {PayloadVerifier::CreateInstance(public_key), true};
902 }
903 
ValidateManifest()904 ErrorCode DeltaPerformer::ValidateManifest() {
905   // Perform assorted checks to validation check the manifest, make sure it
906   // matches data from other sources, and that it is a supported version.
907   bool has_old_fields = std::any_of(manifest_.partitions().begin(),
908                                     manifest_.partitions().end(),
909                                     [](const PartitionUpdate& partition) {
910                                       return partition.has_old_partition_info();
911                                     });
912 
913   // The presence of an old partition hash is the sole indicator for a delta
914   // update. Also, always treat the partial update as delta so that we can
915   // perform the minor version check correctly.
916   InstallPayloadType actual_payload_type =
917       (has_old_fields || manifest_.partial_update())
918           ? InstallPayloadType::kDelta
919           : InstallPayloadType::kFull;
920 
921   if (payload_->type == InstallPayloadType::kUnknown) {
922     LOG(INFO) << "Detected a '"
923               << InstallPayloadTypeToString(actual_payload_type)
924               << "' payload.";
925     payload_->type = actual_payload_type;
926   } else if (payload_->type != actual_payload_type) {
927     LOG(ERROR) << "InstallPlan expected a '"
928                << InstallPayloadTypeToString(payload_->type)
929                << "' payload but the downloaded manifest contains a '"
930                << InstallPayloadTypeToString(actual_payload_type)
931                << "' payload.";
932     return ErrorCode::kPayloadMismatchedType;
933   }
934   // Check that the minor version is compatible.
935   // TODO(xunchang) increment minor version & add check for partial update
936   if (actual_payload_type == InstallPayloadType::kFull) {
937     if (manifest_.minor_version() != kFullPayloadMinorVersion) {
938       LOG(ERROR) << "Manifest contains minor version "
939                  << manifest_.minor_version()
940                  << ", but all full payloads should have version "
941                  << kFullPayloadMinorVersion << ".";
942       return ErrorCode::kUnsupportedMinorPayloadVersion;
943     }
944   } else {
945     if (manifest_.minor_version() < kMinSupportedMinorPayloadVersion ||
946         manifest_.minor_version() > kMaxSupportedMinorPayloadVersion) {
947       LOG(ERROR) << "Manifest contains minor version "
948                  << manifest_.minor_version()
949                  << " not in the range of supported minor versions ["
950                  << kMinSupportedMinorPayloadVersion << ", "
951                  << kMaxSupportedMinorPayloadVersion << "].";
952       return ErrorCode::kUnsupportedMinorPayloadVersion;
953     }
954   }
955 
956   ErrorCode error_code = CheckTimestampError();
957   if (error_code != ErrorCode::kSuccess) {
958     if (error_code == ErrorCode::kPayloadTimestampError) {
959       if (!hardware_->AllowDowngrade()) {
960         return ErrorCode::kPayloadTimestampError;
961       }
962       LOG(INFO) << "The current OS build allows downgrade, continuing to apply"
963                    " the payload with an older timestamp.";
964     } else {
965       LOG(ERROR) << "Timestamp check returned "
966                  << utils::ErrorCodeToString(error_code);
967       return error_code;
968     }
969   }
970 
971   // TODO(crbug.com/37661) we should be adding more and more manifest checks,
972   // such as partition boundaries, etc.
973 
974   return ErrorCode::kSuccess;
975 }
976 
CheckTimestampError() const977 ErrorCode DeltaPerformer::CheckTimestampError() const {
978   bool is_partial_update =
979       manifest_.has_partial_update() && manifest_.partial_update();
980   const auto& partitions = manifest_.partitions();
981 
982   // Check version field for a given PartitionUpdate object. If an error
983   // is encountered, set |error_code| accordingly. If downgrade is detected,
984   // |downgrade_detected| is set. Return true if the program should continue
985   // to check the next partition or not, or false if it should exit early due
986   // to errors.
987   auto&& timestamp_valid = [this](const PartitionUpdate& partition,
988                                   bool allow_empty_version,
989                                   bool* downgrade_detected) -> ErrorCode {
990     const auto& partition_name = partition.partition_name();
991     if (!partition.has_version()) {
992       if (hardware_->GetVersionForLogging(partition_name).empty()) {
993         LOG(INFO) << partition_name << " does't have version, skipping "
994                   << "downgrade check.";
995         return ErrorCode::kSuccess;
996       }
997 
998       if (allow_empty_version) {
999         return ErrorCode::kSuccess;
1000       }
1001       LOG(ERROR)
1002           << "PartitionUpdate " << partition_name
1003           << " doesn't have a version field. Not allowed in partial updates.";
1004       return ErrorCode::kDownloadManifestParseError;
1005     }
1006 
1007     auto error_code =
1008         hardware_->IsPartitionUpdateValid(partition_name, partition.version());
1009     switch (error_code) {
1010       case ErrorCode::kSuccess:
1011         break;
1012       case ErrorCode::kPayloadTimestampError:
1013         *downgrade_detected = true;
1014         LOG(WARNING) << "PartitionUpdate " << partition_name
1015                      << " has an older version than partition on device.";
1016         break;
1017       default:
1018         LOG(ERROR) << "IsPartitionUpdateValid(" << partition_name
1019                    << ") returned" << utils::ErrorCodeToString(error_code);
1020         break;
1021     }
1022     return error_code;
1023   };
1024 
1025   bool downgrade_detected = false;
1026 
1027   if (is_partial_update) {
1028     // for partial updates, all partition MUST have valid timestamps
1029     // But max_timestamp can be empty
1030     for (const auto& partition : partitions) {
1031       auto error_code = timestamp_valid(
1032           partition, false /* allow_empty_version */, &downgrade_detected);
1033       if (error_code != ErrorCode::kSuccess &&
1034           error_code != ErrorCode::kPayloadTimestampError) {
1035         return error_code;
1036       }
1037     }
1038     if (downgrade_detected) {
1039       return ErrorCode::kPayloadTimestampError;
1040     }
1041     return ErrorCode::kSuccess;
1042   }
1043 
1044   // For non-partial updates, check max_timestamp first.
1045   if (manifest_.max_timestamp() < hardware_->GetBuildTimestamp()) {
1046     LOG(ERROR) << "The current OS build timestamp ("
1047                << hardware_->GetBuildTimestamp()
1048                << ") is newer than the maximum timestamp in the manifest ("
1049                << manifest_.max_timestamp() << ")";
1050     return ErrorCode::kPayloadTimestampError;
1051   }
1052   // Otherwise... partitions can have empty timestamps.
1053   for (const auto& partition : partitions) {
1054     auto error_code = timestamp_valid(
1055         partition, true /* allow_empty_version */, &downgrade_detected);
1056     if (error_code != ErrorCode::kSuccess &&
1057         error_code != ErrorCode::kPayloadTimestampError) {
1058       return error_code;
1059     }
1060   }
1061   if (downgrade_detected) {
1062     return ErrorCode::kPayloadTimestampError;
1063   }
1064   return ErrorCode::kSuccess;
1065 }
1066 
ValidateOperationHash(const InstallOperation & operation)1067 ErrorCode DeltaPerformer::ValidateOperationHash(
1068     const InstallOperation& operation) {
1069   if (!operation.data_sha256_hash().size()) {
1070     if (!operation.data_length()) {
1071       // Operations that do not have any data blob won't have any operation
1072       // hash either. So, these operations are always considered validated
1073       // since the metadata that contains all the non-data-blob portions of
1074       // the operation has already been validated. This is true for both HTTP
1075       // and HTTPS cases.
1076       return ErrorCode::kSuccess;
1077     }
1078 
1079     // No hash is present for an operation that has data blobs. This shouldn't
1080     // happen normally for any client that has this code, because the
1081     // corresponding update should have been produced with the operation
1082     // hashes. So if it happens it means either we've turned operation hash
1083     // generation off in DeltaDiffGenerator or it's a regression of some sort.
1084     // One caveat though: The last operation is a unused signature operation
1085     // that doesn't have a hash at the time the manifest is created. So we
1086     // should not complaint about that operation. This operation can be
1087     // recognized by the fact that it's offset is mentioned in the manifest.
1088     if (manifest_.signatures_offset() &&
1089         manifest_.signatures_offset() == operation.data_offset()) {
1090       LOG(INFO) << "Skipping hash verification for signature operation "
1091                 << next_operation_num_ + 1;
1092     } else {
1093       if (install_plan_->hash_checks_mandatory) {
1094         LOG(ERROR) << "Missing mandatory operation hash for operation "
1095                    << next_operation_num_ + 1;
1096         return ErrorCode::kDownloadOperationHashMissingError;
1097       }
1098 
1099       LOG(WARNING) << "Cannot validate operation " << next_operation_num_ + 1
1100                    << " as there's no operation hash in manifest";
1101     }
1102     return ErrorCode::kSuccess;
1103   }
1104 
1105   brillo::Blob expected_op_hash;
1106   expected_op_hash.assign(operation.data_sha256_hash().data(),
1107                           (operation.data_sha256_hash().data() +
1108                            operation.data_sha256_hash().size()));
1109 
1110   brillo::Blob calculated_op_hash;
1111   if (!HashCalculator::RawHashOfBytes(
1112           buffer_.data(), operation.data_length(), &calculated_op_hash)) {
1113     LOG(ERROR) << "Unable to compute actual hash of operation "
1114                << next_operation_num_;
1115     return ErrorCode::kDownloadOperationHashVerificationError;
1116   }
1117 
1118   if (calculated_op_hash != expected_op_hash) {
1119     LOG(ERROR) << "Hash verification failed for operation "
1120                << next_operation_num_
1121                << ". Expected hash = " << HexEncode(expected_op_hash);
1122     LOG(ERROR) << "Calculated hash over " << operation.data_length()
1123                << " bytes at offset: " << operation.data_offset() << " = "
1124                << HexEncode(calculated_op_hash);
1125     return ErrorCode::kDownloadOperationHashMismatch;
1126   }
1127 
1128   return ErrorCode::kSuccess;
1129 }
1130 
1131 #define TEST_AND_RETURN_VAL(_retval, _condition)              \
1132   do {                                                        \
1133     if (!(_condition)) {                                      \
1134       LOG(ERROR) << "VerifyPayload failure: " << #_condition; \
1135       return _retval;                                         \
1136     }                                                         \
1137   } while (0);
1138 
VerifyPayload(const brillo::Blob & update_check_response_hash,const uint64_t update_check_response_size)1139 ErrorCode DeltaPerformer::VerifyPayload(
1140     const brillo::Blob& update_check_response_hash,
1141     const uint64_t update_check_response_size) {
1142   // Verifies the download size.
1143   if (update_check_response_size !=
1144       metadata_size_ + metadata_signature_size_ + buffer_offset_) {
1145     LOG(ERROR) << "update_check_response_size (" << update_check_response_size
1146                << ") doesn't match metadata_size (" << metadata_size_
1147                << ") + metadata_signature_size (" << metadata_signature_size_
1148                << ") + buffer_offset (" << buffer_offset_ << ").";
1149     return ErrorCode::kPayloadSizeMismatchError;
1150   }
1151 
1152   // Verifies the payload hash.
1153   TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadVerificationError,
1154                       !payload_hash_calculator_.raw_hash().empty());
1155   if (payload_hash_calculator_.raw_hash() != update_check_response_hash) {
1156     LOG(ERROR) << "Actual hash: "
1157                << HexEncode(payload_hash_calculator_.raw_hash())
1158                << ", expected hash: " << HexEncode(update_check_response_hash);
1159     return ErrorCode::kPayloadHashMismatchError;
1160   }
1161 
1162   // NOLINTNEXTLINE(whitespace/braces)
1163   auto [payload_verifier, perform_verification] = CreatePayloadVerifier();
1164   if (!perform_verification) {
1165     LOG(WARNING) << "Not verifying signed delta payload -- missing public key.";
1166     return ErrorCode::kSuccess;
1167   }
1168   if (!payload_verifier) {
1169     LOG(ERROR) << "Failed to create the payload verifier.";
1170     return ErrorCode::kDownloadPayloadPubKeyVerificationError;
1171   }
1172 
1173   TEST_AND_RETURN_VAL(ErrorCode::kSignedDeltaPayloadExpectedError,
1174                       !signatures_message_data_.empty());
1175   brillo::Blob hash_data = signed_hash_calculator_.raw_hash();
1176   TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
1177                       hash_data.size() == kSHA256Size);
1178 
1179   if (!payload_verifier->VerifySignature(signatures_message_data_, hash_data)) {
1180     // The autoupdate_CatchBadSignatures test checks for this string
1181     // in log-files. Keep in sync.
1182     LOG(ERROR) << "Public key verification failed, thus update failed.";
1183     return ErrorCode::kDownloadPayloadPubKeyVerificationError;
1184   }
1185 
1186   LOG(INFO) << "Payload hash matches value in payload.";
1187   return ErrorCode::kSuccess;
1188 }
1189 
DiscardBuffer(bool do_advance_offset,size_t signed_hash_buffer_size)1190 void DeltaPerformer::DiscardBuffer(bool do_advance_offset,
1191                                    size_t signed_hash_buffer_size) {
1192   // Update the buffer offset.
1193   if (do_advance_offset)
1194     buffer_offset_ += buffer_.size();
1195 
1196   // Hash the content.
1197   payload_hash_calculator_.Update(buffer_.data(), buffer_.size());
1198   signed_hash_calculator_.Update(buffer_.data(), signed_hash_buffer_size);
1199 
1200   // Swap content with an empty vector to ensure that all memory is released.
1201   brillo::Blob().swap(buffer_);
1202 }
1203 
CanResumeUpdate(PrefsInterface * prefs,const string & update_check_response_hash)1204 bool DeltaPerformer::CanResumeUpdate(PrefsInterface* prefs,
1205                                      const string& update_check_response_hash) {
1206   int64_t next_operation = kUpdateStateOperationInvalid;
1207   if (!(prefs->GetInt64(kPrefsUpdateStateNextOperation, &next_operation) &&
1208         next_operation != kUpdateStateOperationInvalid && next_operation > 0))
1209     return false;
1210 
1211   string interrupted_hash;
1212   if (!(prefs->GetString(kPrefsUpdateCheckResponseHash, &interrupted_hash) &&
1213         !interrupted_hash.empty() &&
1214         interrupted_hash == update_check_response_hash))
1215     return false;
1216 
1217   int64_t resumed_update_failures;
1218   // Note that storing this value is optional, but if it is there it should
1219   // not be more than the limit.
1220   if (prefs->GetInt64(kPrefsResumedUpdateFailures, &resumed_update_failures) &&
1221       resumed_update_failures > kMaxResumedUpdateFailures)
1222     return false;
1223 
1224   // Validation check the rest.
1225   int64_t next_data_offset = -1;
1226   if (!(prefs->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset) &&
1227         next_data_offset >= 0))
1228     return false;
1229 
1230   string sha256_context;
1231   if (!(prefs->GetString(kPrefsUpdateStateSHA256Context, &sha256_context) &&
1232         !sha256_context.empty()))
1233     return false;
1234 
1235   int64_t manifest_metadata_size = 0;
1236   if (!(prefs->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size) &&
1237         manifest_metadata_size > 0))
1238     return false;
1239 
1240   int64_t manifest_signature_size = 0;
1241   if (!(prefs->GetInt64(kPrefsManifestSignatureSize,
1242                         &manifest_signature_size) &&
1243         manifest_signature_size >= 0))
1244     return false;
1245 
1246   return true;
1247 }
1248 
ResetUpdateProgress(PrefsInterface * prefs,bool quick,bool skip_dynamic_partititon_metadata_updated)1249 bool DeltaPerformer::ResetUpdateProgress(
1250     PrefsInterface* prefs,
1251     bool quick,
1252     bool skip_dynamic_partititon_metadata_updated) {
1253   TEST_AND_RETURN_FALSE(prefs->SetInt64(kPrefsUpdateStateNextOperation,
1254                                         kUpdateStateOperationInvalid));
1255   if (!quick) {
1256     prefs->SetInt64(kPrefsUpdateStateNextDataOffset, -1);
1257     prefs->SetInt64(kPrefsUpdateStateNextDataLength, 0);
1258     prefs->SetString(kPrefsUpdateStateSHA256Context, "");
1259     prefs->SetString(kPrefsUpdateStateSignedSHA256Context, "");
1260     prefs->SetString(kPrefsUpdateStateSignatureBlob, "");
1261     prefs->SetInt64(kPrefsManifestMetadataSize, -1);
1262     prefs->SetInt64(kPrefsManifestSignatureSize, -1);
1263     prefs->SetInt64(kPrefsResumedUpdateFailures, 0);
1264     prefs->Delete(kPrefsPostInstallSucceeded);
1265     prefs->Delete(kPrefsVerityWritten);
1266 
1267     if (!skip_dynamic_partititon_metadata_updated) {
1268       LOG(INFO) << "Resetting recorded hash for prepared partitions.";
1269       prefs->Delete(kPrefsDynamicPartitionMetadataUpdated);
1270     }
1271   }
1272   return true;
1273 }
1274 
ShouldCheckpoint()1275 bool DeltaPerformer::ShouldCheckpoint() {
1276   base::TimeTicks curr_time = base::TimeTicks::Now();
1277   if (curr_time > update_checkpoint_time_) {
1278     update_checkpoint_time_ = curr_time + update_checkpoint_wait_;
1279     return true;
1280   }
1281   return false;
1282 }
1283 
CheckpointUpdateProgress(bool force)1284 bool DeltaPerformer::CheckpointUpdateProgress(bool force) {
1285   if (!force && !ShouldCheckpoint()) {
1286     return false;
1287   }
1288   Terminator::set_exit_blocked(true);
1289   if (last_updated_operation_num_ != next_operation_num_ || force) {
1290     // Resets the progress in case we die in the middle of the state update.
1291     ResetUpdateProgress(prefs_, true);
1292     if (!signatures_message_data_.empty()) {
1293       // Save the signature blob because if the update is interrupted after the
1294       // download phase we don't go through this path anymore. Some alternatives
1295       // to consider:
1296       //
1297       // 1. On resume, re-download the signature blob from the server and
1298       // re-verify it.
1299       //
1300       // 2. Verify the signature as soon as it's received and don't checkpoint
1301       // the blob and the signed sha-256 context.
1302       LOG_IF(WARNING,
1303              !prefs_->SetString(kPrefsUpdateStateSignatureBlob,
1304                                 signatures_message_data_))
1305           << "Unable to store the signature blob.";
1306     }
1307     TEST_AND_RETURN_FALSE(prefs_->SetString(
1308         kPrefsUpdateStateSHA256Context, payload_hash_calculator_.GetContext()));
1309     TEST_AND_RETURN_FALSE(
1310         prefs_->SetString(kPrefsUpdateStateSignedSHA256Context,
1311                           signed_hash_calculator_.GetContext()));
1312     TEST_AND_RETURN_FALSE(
1313         prefs_->SetInt64(kPrefsUpdateStateNextDataOffset, buffer_offset_));
1314     last_updated_operation_num_ = next_operation_num_;
1315 
1316     if (next_operation_num_ < num_total_operations_) {
1317       size_t partition_index = current_partition_;
1318       while (next_operation_num_ >= acc_num_operations_[partition_index]) {
1319         partition_index++;
1320       }
1321       const size_t partition_operation_num =
1322           next_operation_num_ -
1323           (partition_index ? acc_num_operations_[partition_index - 1] : 0);
1324       const InstallOperation& op =
1325           partitions_[partition_index].operations(partition_operation_num);
1326       TEST_AND_RETURN_FALSE(
1327           prefs_->SetInt64(kPrefsUpdateStateNextDataLength, op.data_length()));
1328     } else {
1329       TEST_AND_RETURN_FALSE(
1330           prefs_->SetInt64(kPrefsUpdateStateNextDataLength, 0));
1331     }
1332     if (partition_writer_) {
1333       partition_writer_->CheckpointUpdateProgress(GetPartitionOperationNum());
1334     } else {
1335       CHECK_EQ(next_operation_num_, num_total_operations_)
1336           << "Partition writer is null, we are expected to finish all "
1337              "operations: "
1338           << next_operation_num_ << "/" << num_total_operations_;
1339     }
1340   }
1341   TEST_AND_RETURN_FALSE(
1342       prefs_->SetInt64(kPrefsUpdateStateNextOperation, next_operation_num_));
1343   return true;
1344 }
1345 
PrimeUpdateState()1346 bool DeltaPerformer::PrimeUpdateState() {
1347   CHECK(manifest_valid_);
1348 
1349   int64_t next_operation = kUpdateStateOperationInvalid;
1350   if (!prefs_->GetInt64(kPrefsUpdateStateNextOperation, &next_operation) ||
1351       next_operation == kUpdateStateOperationInvalid || next_operation <= 0) {
1352     // Initiating a new update, no more state needs to be initialized.
1353     return true;
1354   }
1355   next_operation_num_ = next_operation;
1356 
1357   // Resuming an update -- load the rest of the update state.
1358   int64_t next_data_offset = -1;
1359   TEST_AND_RETURN_FALSE(
1360       prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset) &&
1361       next_data_offset >= 0);
1362   buffer_offset_ = next_data_offset;
1363 
1364   // The signed hash context and the signature blob may be empty if the
1365   // interrupted update didn't reach the signature.
1366   string signed_hash_context;
1367   if (prefs_->GetString(kPrefsUpdateStateSignedSHA256Context,
1368                         &signed_hash_context)) {
1369     TEST_AND_RETURN_FALSE(
1370         signed_hash_calculator_.SetContext(signed_hash_context));
1371   }
1372 
1373   prefs_->GetString(kPrefsUpdateStateSignatureBlob, &signatures_message_data_);
1374 
1375   string hash_context;
1376   TEST_AND_RETURN_FALSE(
1377       prefs_->GetString(kPrefsUpdateStateSHA256Context, &hash_context) &&
1378       payload_hash_calculator_.SetContext(hash_context));
1379 
1380   int64_t manifest_metadata_size = 0;
1381   TEST_AND_RETURN_FALSE(
1382       prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size) &&
1383       manifest_metadata_size > 0);
1384   metadata_size_ = manifest_metadata_size;
1385 
1386   int64_t manifest_signature_size = 0;
1387   TEST_AND_RETURN_FALSE(
1388       prefs_->GetInt64(kPrefsManifestSignatureSize, &manifest_signature_size) &&
1389       manifest_signature_size >= 0);
1390   metadata_signature_size_ = manifest_signature_size;
1391 
1392   // Advance the download progress to reflect what doesn't need to be
1393   // re-downloaded.
1394   total_bytes_received_ += buffer_offset_;
1395 
1396   // Speculatively count the resume as a failure.
1397   int64_t resumed_update_failures;
1398   if (prefs_->GetInt64(kPrefsResumedUpdateFailures, &resumed_update_failures)) {
1399     resumed_update_failures++;
1400   } else {
1401     resumed_update_failures = 1;
1402   }
1403   prefs_->SetInt64(kPrefsResumedUpdateFailures, resumed_update_failures);
1404   return true;
1405 }
1406 
IsDynamicPartition(const std::string & part_name,uint32_t slot)1407 bool DeltaPerformer::IsDynamicPartition(const std::string& part_name,
1408                                         uint32_t slot) {
1409   return boot_control_->GetDynamicPartitionControl()->IsDynamicPartition(
1410       part_name, slot);
1411 }
1412 
CreatePartitionWriter(const PartitionUpdate & partition_update,const InstallPlan::Partition & install_part,DynamicPartitionControlInterface * dynamic_control,size_t block_size,bool is_interactive,bool is_dynamic_partition)1413 std::unique_ptr<PartitionWriterInterface> DeltaPerformer::CreatePartitionWriter(
1414     const PartitionUpdate& partition_update,
1415     const InstallPlan::Partition& install_part,
1416     DynamicPartitionControlInterface* dynamic_control,
1417     size_t block_size,
1418     bool is_interactive,
1419     bool is_dynamic_partition) {
1420   return partition_writer::CreatePartitionWriter(
1421       partition_update,
1422       install_part,
1423       dynamic_control,
1424       block_size_,
1425       interactive_,
1426       IsDynamicPartition(install_part.name, install_plan_->target_slot));
1427 }
1428 
1429 }  // namespace chromeos_update_engine
1430