Add security patch level to update manifest
When installing a full OTA, the target build might have a newer
timestamp but older SPL. In these caess, update_engine will fail to
recognize the SPL downgrade and skip data wipe, causing /data decryption
to fail on next reboot. To fix this issue, add a SPL field to update
manifest. update_engine will check this field on OTA install and
schedule data wipe as needed.
Test: install OTA with newer timestamp but older SPL, make sure data wipe is scheduled
Bug: 242812845
Change-Id: I9d1dd73b46323939bbf990e29da5cc0ba79f86e2
diff --git a/aosp/update_attempter_android.cc b/aosp/update_attempter_android.cc
index b95da94..4faae08 100644
--- a/aosp/update_attempter_android.cc
+++ b/aosp/update_attempter_android.cc
@@ -47,6 +47,7 @@
#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/partition_writer.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_consumer/payload_metadata.h"
#include "update_engine/payload_consumer/payload_verifier.h"
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index fc8858f..47eb353 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -28,10 +28,12 @@
#include <utility>
#include <vector>
+#include <android-base/properties.h>
#include <base/files/file_util.h>
#include <base/format_macros.h>
#include <base/metrics/histogram_macros.h>
#include <base/strings/string_number_conversions.h>
+#include <base/strings/stringprintf.h>
#include <base/time/time.h>
#include <brillo/data_encoding.h>
#include <bsdiff/bspatch.h>
@@ -44,24 +46,15 @@
#include "update_engine/common/error_code_utils.h"
#include "update_engine/common/hardware_interface.h"
#include "update_engine/common/prefs_interface.h"
-#include "update_engine/common/subprocess.h"
#include "update_engine/common/terminator.h"
#include "update_engine/common/utils.h"
-#include "update_engine/payload_consumer/bzip_extent_writer.h"
-#include "update_engine/payload_consumer/cached_file_descriptor.h"
-#include "update_engine/payload_consumer/certificate_parser_interface.h"
-#include "update_engine/payload_consumer/extent_reader.h"
-#include "update_engine/payload_consumer/extent_writer.h"
#include "update_engine/payload_consumer/partition_update_generator_interface.h"
#include "update_engine/payload_consumer/partition_writer.h"
#if USE_FEC
#include "update_engine/payload_consumer/fec_file_descriptor.h"
#endif // USE_FEC
-#include "update_engine/payload_consumer/file_descriptor_utils.h"
-#include "update_engine/payload_consumer/mount_history.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_consumer/payload_verifier.h"
-#include "update_engine/payload_consumer/xz_extent_writer.h"
using google::protobuf::RepeatedPtrField;
using std::min;
@@ -398,6 +391,23 @@
base::TimeDelta::FromMinutes(5), \
20);
+void DeltaPerformer::CheckSPLDowngrade() {
+ const auto new_spl = manifest_.security_patch_level();
+ const auto current_spl =
+ android::base::GetProperty("ro.build.version.security_patch", "");
+ if (current_spl.empty()) {
+ LOG(ERROR) << "Failed to get ro.build.version.security_patch, unable to "
+ "determine if this OTA is a SPL downgrade.";
+ return;
+ }
+ if (new_spl < current_spl) {
+ install_plan_->powerwash_required = true;
+ LOG(INFO) << "Target build SPL " << new_spl
+ << " is older than current build's SPL " << current_spl
+ << ", this OTA is an SPL downgrade. Data wipe will be required";
+ }
+}
+
// Wrapper around write. Returns true if all requested bytes
// were written, or false on any error, regardless of progress
// and stores an action exit code in |error|.
@@ -444,6 +454,8 @@
block_size_ = manifest_.block_size();
+ CheckSPLDowngrade();
+
// This populates |partitions_| and the |install_plan.partitions| with the
// list of partitions from the manifest.
if (!ParseManifestPartitions(error))
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index dd71467..633c533 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -32,10 +32,9 @@
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/platform_constants.h"
-#include "update_engine/payload_consumer/file_descriptor.h"
#include "update_engine/payload_consumer/file_writer.h"
#include "update_engine/payload_consumer/install_plan.h"
-#include "update_engine/payload_consumer/partition_writer.h"
+#include "update_engine/payload_consumer/partition_writer_interface.h"
#include "update_engine/payload_consumer/payload_metadata.h"
#include "update_engine/payload_consumer/payload_verifier.h"
#include "update_engine/update_metadata.pb.h"
@@ -88,7 +87,7 @@
// FileWriter's Write implementation where caller doesn't care about
// error codes.
bool Write(const void* bytes, size_t count) override {
- ErrorCode error;
+ ErrorCode error{};
return Write(bytes, count, &error);
}
@@ -315,6 +314,8 @@
// Check if partition `part_name` is a dynamic partition.
bool IsDynamicPartition(const std::string& part_name, uint32_t slot);
+ void CheckSPLDowngrade();
+
// Update Engine preference store.
PrefsInterface* prefs_;
diff --git a/payload_consumer/partition_writer_unittest.cc b/payload_consumer/partition_writer_unittest.cc
index 331a061..4910594 100644
--- a/payload_consumer/partition_writer_unittest.cc
+++ b/payload_consumer/partition_writer_unittest.cc
@@ -26,16 +26,15 @@
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
-#include "update_engine/payload_consumer/delta_performer.h"
-#include "update_engine/payload_consumer/extent_reader.h"
#include "update_engine/payload_consumer/extent_writer.h"
#include "update_engine/payload_consumer/fake_file_descriptor.h"
#include "update_engine/payload_consumer/file_descriptor.h"
#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/partition_writer.h"
+#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_generator/annotated_operation.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
#include "update_engine/payload_generator/extent_ranges.h"
-#include "update_engine/payload_generator/payload_file.h"
#include "update_engine/payload_generator/payload_generation_config.h"
#include "update_engine/update_metadata.pb.h"
diff --git a/payload_generator/delta_diff_utils.h b/payload_generator/delta_diff_utils.h
index dcb6867..bfbcdf7 100644
--- a/payload_generator/delta_diff_utils.h
+++ b/payload_generator/delta_diff_utils.h
@@ -25,8 +25,9 @@
#include <brillo/secure_blob.h>
#include <puffin/puffdiff.h>
-#include "payload_generator/deflate_utils.h"
+#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_generator/annotated_operation.h"
+#include "update_engine/payload_generator/deflate_utils.h"
#include "update_engine/payload_generator/extent_ranges.h"
#include "update_engine/payload_generator/payload_generation_config.h"
#include "update_engine/update_metadata.pb.h"
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index 49c1e9c..96883a8 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -394,6 +394,11 @@
"The maximum timestamp of the OS allowed to apply this "
"payload.");
DEFINE_string(
+ security_patch_level,
+ "",
+ "The security patch level of this OTA. Devices with a newer SPL "
+ "will not be allowed to apply this payload");
+ DEFINE_string(
partition_timestamps,
"",
"The per-partition maximum timestamps which the OS allowed to apply this "
@@ -719,6 +724,9 @@
}
payload_config.max_timestamp = FLAGS_max_timestamp;
+
+ payload_config.security_patch_level = FLAGS_security_patch_level;
+
if (!FLAGS_partition_timestamps.empty()) {
CHECK(ParsePerPartitionTimestamps(FLAGS_partition_timestamps,
&payload_config));
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index 129377a..0ef747a 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -26,7 +26,6 @@
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/utils.h"
-#include "update_engine/payload_consumer/delta_performer.h"
#include "update_engine/payload_consumer/file_writer.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_generator/annotated_operation.h"
@@ -67,6 +66,7 @@
manifest_.set_minor_version(config.version.minor);
manifest_.set_block_size(config.block_size);
manifest_.set_max_timestamp(config.max_timestamp);
+ manifest_.set_security_patch_level(config.security_patch_level);
if (config.target.dynamic_partition_metadata != nullptr)
*(manifest_.mutable_dynamic_partition_metadata()) =
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index 1e8794b..fc56f56 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -27,7 +27,6 @@
#include <brillo/secure_blob.h>
#include "bsdiff/constants.h"
-#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_generator/filesystem_interface.h"
#include "update_engine/update_metadata.pb.h"
@@ -262,6 +261,8 @@
// Whether to enable zucchini ops
bool enable_zucchini = true;
+ std::string security_patch_level;
+
std::vector<bsdiff::CompressorType> compressors{
bsdiff::CompressorType::kBZ2, bsdiff::CompressorType::kBrotli};
diff --git a/payload_generator/payload_properties_unittest.cc b/payload_generator/payload_properties_unittest.cc
index 0ff364f..0d62681 100644
--- a/payload_generator/payload_properties_unittest.cc
+++ b/payload_generator/payload_properties_unittest.cc
@@ -104,9 +104,9 @@
"{"
R"("is_delta":true,)"
R"("metadata_signature":"",)"
- R"("metadata_size":165,)"
- R"("sha256_hex":"cV7kfZBH3K0B6QJHxxykDh6b6x0WgVOmc63whPLOy7U=",)"
- R"("size":211,)"
+ R"("metadata_size":168,)"
+ R"("sha256_hex":"6rXHDjFO8k8mNtIbLhimWOifecVI1Ts230Ia1DyNuPY=",)"
+ R"("size":214,)"
R"("version":2)"
"}";
string json;
@@ -118,10 +118,10 @@
// Validate the hash of file and metadata are within the output.
TEST_F(PayloadPropertiesTest, GetPropertiesAsKeyValueTestHash) {
constexpr char kKeyValueProperties[] =
- "FILE_HASH=cV7kfZBH3K0B6QJHxxykDh6b6x0WgVOmc63whPLOy7U=\n"
- "FILE_SIZE=211\n"
- "METADATA_HASH=aEKYyzJt2E8Gz8fzB+gmekN5mriotZCSq6R+kDfdeV4=\n"
- "METADATA_SIZE=165\n";
+ "FILE_HASH=6rXHDjFO8k8mNtIbLhimWOifecVI1Ts230Ia1DyNuPY=\n"
+ "FILE_SIZE=214\n"
+ "METADATA_HASH=wq2nRZ7o/aqEeVWcc2Z+bebLYEI8quPEnXHlyLtdW9Y=\n"
+ "METADATA_SIZE=168\n";
string key_value;
EXPECT_TRUE(PayloadProperties{payload_file_.path()}.GetPropertiesAsKeyValue(
&key_value));
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index b2d6080..6652b38 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -220,6 +220,8 @@
"Required if --enabled_lz4diff true is passed. Path to liblz4.so. delta_generator will use this copy of liblz4.so for compression. It is important that this copy of liblz4.so is the same as the one on source build."
DEFINE_string erofs_compression_param "" \
"Compression parameter passed to mkfs.erofs's -z option."
+ DEFINE_string security_patch_level "" \
+ "Optional: security patch level of this OTA"
fi
if [[ "${COMMAND}" == "hash" || "${COMMAND}" == "sign" ]]; then
DEFINE_string unsigned_payload "" "Path to the input unsigned payload."
@@ -776,6 +778,10 @@
GENERATOR_ARGS+=( --max_timestamp="${FLAGS_max_timestamp}" )
fi
+ if [[ -n "${FLAGS_security_patch_level}" ]]; then
+ GENERATOR_ARGS+=( --security_patch_level="${FLAGS_security_patch_level}" )
+ fi
+
if [[ -n "${FLAGS_partition_timestamps}" ]]; then
GENERATOR_ARGS+=( --partition_timestamps="${FLAGS_partition_timestamps}" )
fi
diff --git a/update_metadata.proto b/update_metadata.proto
index 3f454ad..84b991b 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -423,4 +423,8 @@
// Information on compressed APEX to figure out how much space is required for
// their decompression
repeated ApexInfo apex_info = 17;
+
+ // Security patch level of the device, usually in the format of
+ // yyyy-mm-dd
+ optional string security_patch_level = 18;
}