Don't log old PartitionInfo for full payload. am: 7b9a587d7c
am: 8afebd28e0
Change-Id: Iafed23c61c07e1faf6c3ea89410e0af7deddd380
diff --git a/common/error_code.h b/common/error_code.h
index adae391..0b08005 100644
--- a/common/error_code.h
+++ b/common/error_code.h
@@ -74,7 +74,7 @@
kUserCanceled = 48,
kNonCriticalUpdateInOOBE = 49,
// kOmahaUpdateIgnoredOverCellular = 50,
- // kPayloadTimestampError = 51,
+ kPayloadTimestampError = 51,
kUpdatedButNotActive = 52,
// VERY IMPORTANT! When adding new error codes:
diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
index 983d004..313a15f 100644
--- a/common/error_code_utils.cc
+++ b/common/error_code_utils.cc
@@ -144,6 +144,8 @@
return "ErrorCode::kUserCanceled";
case ErrorCode::kNonCriticalUpdateInOOBE:
return "ErrorCode::kNonCriticalUpdateInOOBE";
+ case ErrorCode::kPayloadTimestampError:
+ return "ErrorCode::kPayloadTimestampError";
case ErrorCode::kUpdatedButNotActive:
return "ErrorCode::kUpdatedButNotActive";
// Don't add a default case to let the compiler warn about newly added
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 01d23d0..f2b2c9d 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -81,6 +81,8 @@
return false;
}
+ int64_t GetBuildTimestamp() const override { return build_timestamp_; }
+
bool GetFirstActiveOmahaPingSent() const override {
return first_active_omaha_ping_sent_;
}
@@ -133,6 +135,10 @@
powerwash_count_ = powerwash_count;
}
+ void SetBuildTimestamp(int64_t build_timestamp) {
+ build_timestamp_ = build_timestamp;
+ }
+
private:
bool is_official_build_{true};
bool is_normal_boot_mode_{true};
@@ -145,6 +151,7 @@
std::string ec_version_{"Fake EC v1.0a"};
int powerwash_count_{kPowerwashCountNotSet};
bool powerwash_scheduled_{false};
+ int64_t build_timestamp_{0};
bool first_active_omaha_ping_sent_{false};
DISALLOW_COPY_AND_ASSIGN(FakeHardware);
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index 541a68a..94442d1 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -17,6 +17,8 @@
#ifndef UPDATE_ENGINE_COMMON_HARDWARE_INTERFACE_H_
#define UPDATE_ENGINE_COMMON_HARDWARE_INTERFACE_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
@@ -90,6 +92,9 @@
// returns false.
virtual bool GetPowerwashSafeDirectory(base::FilePath* path) const = 0;
+ // Returns the timestamp of the current OS build.
+ virtual int64_t GetBuildTimestamp() const = 0;
+
// Returns whether the first active ping was sent to Omaha at some point, and
// that the value is persisted across recovery (and powerwash) once set with
// |SetFirstActiveOmahaPingSent()|.
diff --git a/hardware_android.cc b/hardware_android.cc
index 58c68b6..947b13a 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -35,6 +35,7 @@
#include "update_engine/utils_android.h"
using android::base::GetBoolProperty;
+using android::base::GetIntProperty;
using android::base::GetProperty;
using std::string;
@@ -56,6 +57,7 @@
const char kPropProductManufacturer[] = "ro.product.manufacturer";
const char kPropBootHardwareSKU[] = "ro.boot.hardware.sku";
const char kPropBootRevision[] = "ro.boot.revision";
+const char kPropBuildDateUTC[] = "ro.build.date.utc";
// Write a recovery command line |message| to the BCB. The arguments to recovery
// must be separated by '\n'. An empty string will erase the BCB.
@@ -194,6 +196,10 @@
return false;
}
+int64_t HardwareAndroid::GetBuildTimestamp() const {
+ return GetIntProperty<int64_t>(kPropBuildDateUTC, 0);
+}
+
bool HardwareAndroid::GetFirstActiveOmahaPingSent() const {
LOG(WARNING) << "STUB: Assuming first active omaha was never set.";
return false;
diff --git a/hardware_android.h b/hardware_android.h
index 37393ce..ca90b62 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -47,6 +47,7 @@
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
+ int64_t GetBuildTimestamp() const override;
bool GetFirstActiveOmahaPingSent() const override;
void SetFirstActiveOmahaPingSent() override;
diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
index 8c19aa7..f2bb28a 100644
--- a/hardware_chromeos.cc
+++ b/hardware_chromeos.cc
@@ -231,6 +231,11 @@
return true;
}
+int64_t HardwareChromeOS::GetBuildTimestamp() const {
+ // TODO(senj): implement this in Chrome OS.
+ return 0;
+}
+
void HardwareChromeOS::LoadConfig(const string& root_prefix, bool normal_mode) {
brillo::KeyValueStore store;
diff --git a/hardware_chromeos.h b/hardware_chromeos.h
index 3a0bba2..0cf1214 100644
--- a/hardware_chromeos.h
+++ b/hardware_chromeos.h
@@ -51,6 +51,7 @@
bool CancelPowerwash() override;
bool GetNonVolatileDirectory(base::FilePath* path) const override;
bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
+ int64_t GetBuildTimestamp() const override;
bool GetFirstActiveOmahaPingSent() const override;
void SetFirstActiveOmahaPingSent() override;
diff --git a/metrics_utils.cc b/metrics_utils.cc
index 7e6b20f..46530f0 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -78,6 +78,7 @@
case ErrorCode::kDownloadPayloadVerificationError:
case ErrorCode::kSignedDeltaPayloadExpectedError:
case ErrorCode::kDownloadPayloadPubKeyVerificationError:
+ case ErrorCode::kPayloadTimestampError:
return metrics::AttemptResult::kPayloadVerificationFailed;
case ErrorCode::kNewRootfsVerificationError:
@@ -213,6 +214,7 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ case ErrorCode::kPayloadTimestampError:
case ErrorCode::kUpdatedButNotActive:
break;
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 0fb0a77..e5b9259 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -1645,6 +1645,14 @@
}
}
+ if (manifest_.max_timestamp() < hardware_->GetBuildTimestamp()) {
+ LOG(ERROR) << "The current OS build timestamp ("
+ << hardware_->GetBuildTimestamp()
+ << ") is newer than the maximum timestamp in the manifest ("
+ << manifest_.max_timestamp() << ")";
+ return ErrorCode::kPayloadTimestampError;
+ }
+
// TODO(garnold) we should be adding more and more manifest checks, such as
// partition boundaries etc (see chromium-os:37661).
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index 092327b..420efd2 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -721,6 +721,20 @@
ErrorCode::kUnsupportedMinorPayloadVersion);
}
+TEST_F(DeltaPerformerTest, ValidateManifestDowngrade) {
+ // The Manifest we are validating.
+ DeltaArchiveManifest manifest;
+
+ manifest.set_minor_version(kFullPayloadMinorVersion);
+ manifest.set_max_timestamp(1);
+ fake_hardware_.SetBuildTimestamp(2);
+
+ RunManifestValidation(manifest,
+ DeltaPerformer::kSupportedMajorPayloadVersion,
+ InstallPayloadType::kFull,
+ ErrorCode::kPayloadTimestampError);
+}
+
TEST_F(DeltaPerformerTest, BrilloMetadataSignatureSizeTest) {
EXPECT_TRUE(performer_.Write(kDeltaMagic, sizeof(kDeltaMagic)));
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index a20a567..2729bc4 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -335,6 +335,10 @@
DEFINE_string(properties_file, "",
"If passed, dumps the payload properties of the payload passed "
"in --in_file and exits.");
+ DEFINE_int64(max_timestamp,
+ 0,
+ "The maximum timestamp of the OS allowed to apply this "
+ "payload.");
DEFINE_string(old_channel, "",
"The channel for the old image. 'dev-channel', 'npo-channel', "
@@ -576,6 +580,8 @@
LOG(INFO) << "Using provided minor_version=" << FLAGS_minor_version;
}
+ payload_config.max_timestamp = FLAGS_max_timestamp;
+
LOG(INFO) << "Generating " << (payload_config.is_delta ? "delta" : "full")
<< " update";
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index 941b640..f48d2a2 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -73,6 +73,7 @@
*(manifest_.mutable_new_image_info()) = config.target.image_info;
manifest_.set_block_size(config.block_size);
+ manifest_.set_max_timestamp(config.max_timestamp);
return true;
}
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index ca6fb04..c553d29 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -186,6 +186,9 @@
// The block size used for all the operations in the manifest.
size_t block_size = 4096;
+
+ // The maximum timestamp of the OS allowed to apply this payload.
+ int64_t max_timestamp = 0;
};
} // namespace chromeos_update_engine
diff --git a/payload_state.cc b/payload_state.cc
index cff02b1..4992606 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -305,6 +305,7 @@
case ErrorCode::kPayloadMismatchedType:
case ErrorCode::kUnsupportedMajorPayloadVersion:
case ErrorCode::kUnsupportedMinorPayloadVersion:
+ case ErrorCode::kPayloadTimestampError:
IncrementUrlIndex();
break;
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index 61ecadf..65c63f5 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -167,6 +167,10 @@
"Optional: Path to a source image. If specified, this makes a delta update."
DEFINE_string metadata_size_file "" \
"Optional: Path to output metadata size."
+ DEFINE_string max_timestamp "" \
+ "Optional: The maximum unix timestamp of the OS allowed to apply this \
+payload, should be set to a number higher than the build timestamp of the \
+system running on the device, 0 if not specified."
fi
if [[ "${COMMAND}" == "hash" || "${COMMAND}" == "sign" ]]; then
DEFINE_string unsigned_payload "" "Path to the input unsigned payload."
@@ -567,6 +571,10 @@
GENERATOR_ARGS+=( --out_metadata_size_file="${FLAGS_metadata_size_file}" )
fi
+ if [[ -n "${FLAGS_max_timestamp}" ]]; then
+ GENERATOR_ARGS+=( --max_timestamp="${FLAGS_max_timestamp}" )
+ fi
+
if [[ -n "${POSTINSTALL_CONFIG_FILE}" ]]; then
GENERATOR_ARGS+=(
--new_postinstall_config_file="${POSTINSTALL_CONFIG_FILE}"
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 5ee0584..aacb06b 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -29,6 +29,7 @@
#include <brillo/data_encoding.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/strings/string_utils.h>
+#include <log/log_safetynet.h>
#include "update_engine/common/constants.h"
#include "update_engine/common/file_fetcher.h"
@@ -350,6 +351,11 @@
LOG(INFO) << "Resetting update progress.";
break;
+ case ErrorCode::kPayloadTimestampError:
+ // SafetyNet logging, b/36232423
+ android_errorWriteLog(0x534e4554, "36232423");
+ break;
+
default:
// Ignore all other error codes.
break;
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
index 12f417c..b32b626 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -79,6 +79,7 @@
case ErrorCode::kPayloadMismatchedType:
case ErrorCode::kUnsupportedMajorPayloadVersion:
case ErrorCode::kUnsupportedMinorPayloadVersion:
+ case ErrorCode::kPayloadTimestampError:
LOG(INFO) << "Advancing download URL due to error "
<< chromeos_update_engine::utils::ErrorCodeToString(err_code)
<< " (" << static_cast<int>(err_code) << ")";
diff --git a/update_metadata.proto b/update_metadata.proto
index ad377c7..b5d6c59 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -288,4 +288,8 @@
// array can have more than two partitions if needed, and they are identified
// by the partition name.
repeated PartitionUpdate partitions = 13;
+
+ // The maximum timestamp of the OS allowed to apply this payload.
+ // Can be used to prevent downgrading the OS.
+ optional int64 max_timestamp = 14;
}