Implement VerifyPayloadApplicable.
Parse the payload metadata and validate the source hash of all operations.
Return false if any error occur or hash mismatch.
Bug: 65283633
Test: mma
Change-Id: I6f5ae3cb69f4de973cecd0e3d7b733a48b2462f1
(cherry picked from commit 8371c1c852eae461043d8a3d911394a0ec0db909)
diff --git a/binder_service_android.cc b/binder_service_android.cc
index ccae3bf..1702ead 100644
--- a/binder_service_android.cc
+++ b/binder_service_android.cc
@@ -145,9 +145,11 @@
android::String8{metadata_filename}.string()};
LOG(INFO) << "Received a request of verifying payload metadata in "
<< payload_metadata << ".";
-
- // FIXME: Do the actual verification work.
- *return_value = true;
+ brillo::ErrorPtr error;
+ *return_value =
+ service_delegate_->VerifyPayloadApplicable(payload_metadata, &error);
+ if (error != nullptr)
+ return ErrorPtrToStatus(error);
return Status::ok();
}
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 5303e03..2445c6d 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -1031,15 +1031,10 @@
return true;
}
-namespace {
-
-// Compare |calculated_hash| with source hash in |operation|, return false and
-// dump hash and set |error| if don't match.
-// |source_fd| is the file descriptor of the source partition.
-bool ValidateSourceHash(const brillo::Blob& calculated_hash,
- const InstallOperation& operation,
- const FileDescriptorPtr source_fd,
- ErrorCode* error) {
+bool DeltaPerformer::ValidateSourceHash(const brillo::Blob& calculated_hash,
+ const InstallOperation& operation,
+ const FileDescriptorPtr source_fd,
+ ErrorCode* error) {
brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
operation.src_sha256_hash().end());
if (calculated_hash != expected_source_hash) {
@@ -1074,8 +1069,6 @@
return true;
}
-} // namespace
-
bool DeltaPerformer::PerformSourceCopyOperation(
const InstallOperation& operation, ErrorCode* error) {
if (operation.has_src_length())
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index 55a19d8..b156e2f 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -165,6 +165,14 @@
// it returns that value, otherwise it returns the default value.
uint32_t GetMinorVersion() const;
+ // Compare |calculated_hash| with source hash in |operation|, return false and
+ // dump hash and set |error| if don't match.
+ // |source_fd| is the file descriptor of the source partition.
+ static bool ValidateSourceHash(const brillo::Blob& calculated_hash,
+ const InstallOperation& operation,
+ const FileDescriptorPtr source_fd,
+ ErrorCode* error);
+
private:
friend class DeltaPerformerTest;
friend class DeltaPerformerIntegrationTest;
diff --git a/service_delegate_android_interface.h b/service_delegate_android_interface.h
index 7dae40f..5267bb0 100644
--- a/service_delegate_android_interface.h
+++ b/service_delegate_android_interface.h
@@ -70,6 +70,12 @@
// of error, returns false and sets |error| accordingly.
virtual bool ResetStatus(brillo::ErrorPtr* error) = 0;
+ // Verifies whether a payload (delegated by the payload metadata) can be
+ // applied to the current device. Returns whether the payload is applicable.
+ // In case of error, returns false and sets |error| accordingly.
+ virtual bool VerifyPayloadApplicable(const std::string& metadata_filename,
+ brillo::ErrorPtr* error) = 0;
+
protected:
ServiceDelegateAndroidInterface() = default;
};
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 4ec58d0..7df093d 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -31,14 +31,20 @@
#include <brillo/strings/string_utils.h>
#include "update_engine/common/constants.h"
+#include "update_engine/common/error_code_utils.h"
#include "update_engine/common/file_fetcher.h"
#include "update_engine/common/utils.h"
#include "update_engine/daemon_state_interface.h"
#include "update_engine/metrics_reporter_interface.h"
#include "update_engine/metrics_utils.h"
#include "update_engine/network_selector.h"
+#include "update_engine/payload_consumer/delta_performer.h"
#include "update_engine/payload_consumer/download_action.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/file_descriptor_utils.h"
#include "update_engine/payload_consumer/filesystem_verifier_action.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_consumer/payload_metadata.h"
#include "update_engine/payload_consumer/postinstall_runner_action.h"
#include "update_engine/update_status_utils.h"
@@ -326,6 +332,96 @@
}
}
+bool UpdateAttempterAndroid::VerifyPayloadApplicable(
+ const std::string& metadata_filename, brillo::ErrorPtr* error) {
+ FileDescriptorPtr fd(new EintrSafeFileDescriptor);
+ if (!fd->Open(metadata_filename.c_str(), O_RDONLY)) {
+ return LogAndSetError(
+ error, FROM_HERE, "Failed to open " + metadata_filename);
+ }
+ brillo::Blob metadata(kMaxPayloadHeaderSize);
+ if (!fd->Read(metadata.data(), metadata.size())) {
+ return LogAndSetError(
+ error,
+ FROM_HERE,
+ "Failed to read payload header from " + metadata_filename);
+ }
+ ErrorCode errorcode;
+ PayloadMetadata payload_metadata;
+ if (payload_metadata.ParsePayloadHeader(
+ metadata, kBrilloMajorPayloadVersion, &errorcode) !=
+ MetadataParseResult::kSuccess) {
+ return LogAndSetError(error,
+ FROM_HERE,
+ "Failed to parse payload header: " +
+ utils::ErrorCodeToString(errorcode));
+ }
+ metadata.resize(payload_metadata.GetMetadataSize() +
+ payload_metadata.GetMetadataSignatureSize());
+ if (metadata.size() < kMaxPayloadHeaderSize) {
+ return LogAndSetError(
+ error,
+ FROM_HERE,
+ "Metadata size too small: " + std::to_string(metadata.size()));
+ }
+ if (!fd->Read(metadata.data() + kMaxPayloadHeaderSize,
+ metadata.size() - kMaxPayloadHeaderSize)) {
+ return LogAndSetError(
+ error,
+ FROM_HERE,
+ "Failed to read metadata and signature from " + metadata_filename);
+ }
+ fd->Close();
+ errorcode = payload_metadata.ValidateMetadataSignature(
+ metadata, "", base::FilePath(constants::kUpdatePayloadPublicKeyPath));
+ if (errorcode != ErrorCode::kSuccess) {
+ return LogAndSetError(error,
+ FROM_HERE,
+ "Failed to validate metadata signature: " +
+ utils::ErrorCodeToString(errorcode));
+ }
+ DeltaArchiveManifest manifest;
+ if (!payload_metadata.GetManifest(metadata, &manifest)) {
+ return LogAndSetError(error, FROM_HERE, "Failed to parse manifest.");
+ }
+
+ BootControlInterface::Slot current_slot = boot_control_->GetCurrentSlot();
+ for (const PartitionUpdate& partition : manifest.partitions()) {
+ if (!partition.has_old_partition_info())
+ continue;
+ string partition_path;
+ if (!boot_control_->GetPartitionDevice(
+ partition.partition_name(), current_slot, &partition_path)) {
+ return LogAndSetError(
+ error,
+ FROM_HERE,
+ "Failed to get partition device for " + partition.partition_name());
+ }
+ if (!fd->Open(partition_path.c_str(), O_RDONLY)) {
+ return LogAndSetError(
+ error, FROM_HERE, "Failed to open " + partition_path);
+ }
+ for (const InstallOperation& operation : partition.operations()) {
+ if (!operation.has_src_sha256_hash())
+ continue;
+ brillo::Blob source_hash;
+ if (!fd_utils::ReadAndHashExtents(fd,
+ operation.src_extents(),
+ manifest.block_size(),
+ &source_hash)) {
+ return LogAndSetError(
+ error, FROM_HERE, "Failed to hash " + partition_path);
+ }
+ if (!DeltaPerformer::ValidateSourceHash(
+ source_hash, operation, fd, &errorcode)) {
+ return false;
+ }
+ }
+ fd->Close();
+ }
+ return true;
+}
+
void UpdateAttempterAndroid::ProcessingDone(const ActionProcessor* processor,
ErrorCode code) {
LOG(INFO) << "Processing Done.";
diff --git a/update_attempter_android.h b/update_attempter_android.h
index 28bf90a..f00692e 100644
--- a/update_attempter_android.h
+++ b/update_attempter_android.h
@@ -69,6 +69,8 @@
bool ResumeUpdate(brillo::ErrorPtr* error) override;
bool CancelUpdate(brillo::ErrorPtr* error) override;
bool ResetStatus(brillo::ErrorPtr* error) override;
+ bool VerifyPayloadApplicable(const std::string& metadata_filename,
+ brillo::ErrorPtr* error) override;
// ActionProcessorDelegate methods:
void ProcessingDone(const ActionProcessor* processor,