AU: Split applied update verification into a separate step.
Use instances of FilesystemCopierAction to do applied update verification. This
speeds it up slightly because asynchronous reads happen in parallel with hash
calculation but, more importantly, makes update_engine be responsive to D-Bus
during that step.
BUG=9140
TEST=unit tests, tested on device
Change-Id: I3ec9445de5e8258a63433a61f1a476aef4434f6c
Review URL: http://codereview.chromium.org/5516009
diff --git a/action_processor.h b/action_processor.h
index 8bd890b..0cf6ff6 100644
--- a/action_processor.h
+++ b/action_processor.h
@@ -36,8 +36,10 @@
kActionCodeDownloadHashMismatchError = 10,
kActionCodeDownloadSizeMismatchError = 11,
kActionCodeDownloadPayloadVerificationError = 12,
- kActionCodeDownloadAppliedUpdateVerificationError = 13,
+ kActionCodeDownloadNewPartitionInfoError = 13,
kActionCodeDownloadWriteError = 14,
+ kActionCodeNewRootfsVerificationError = 15,
+ kActionCodeNewKernelVerificationError = 16,
kActionCodeOmahaRequestEmptyResponseError = 200,
kActionCodeOmahaRequestXMLParseError = 201,
kActionCodeOmahaRequestNoUpdateCheckNode = 202,
diff --git a/delta_performer.cc b/delta_performer.cc
index a5b7a72..6eb8aea 100644
--- a/delta_performer.cc
+++ b/delta_performer.cc
@@ -174,8 +174,8 @@
if (OmahaHashCalculator::Base64Encode(info.hash().data(),
info.hash().size(),
&sha256)) {
- LOG(INFO) << "PartitionInfo " << tag << " sha256:" << sha256
- << " length:" << tag.size();
+ LOG(INFO) << "PartitionInfo " << tag << " sha256: " << sha256
+ << " size: " << info.size();
} else {
LOG(ERROR) << "Base64Encode failed for tag: " << tag;
}
@@ -589,25 +589,21 @@
return true;
}
-bool DeltaPerformer::VerifyAppliedUpdate(const string& path,
- const string& kernel_path) {
- LOG(INFO) << "Verifying applied update.";
+bool DeltaPerformer::GetNewPartitionInfo(uint64_t* kernel_size,
+ vector<char>* kernel_hash,
+ uint64_t* rootfs_size,
+ vector<char>* rootfs_hash) {
TEST_AND_RETURN_FALSE(manifest_valid_ &&
manifest_.has_new_kernel_info() &&
manifest_.has_new_rootfs_info());
- const string* paths[] = { &kernel_path, &path };
- const PartitionInfo* infos[] = {
- &manifest_.new_kernel_info(), &manifest_.new_rootfs_info()
- };
- for (size_t i = 0; i < arraysize(paths); ++i) {
- OmahaHashCalculator hasher;
- TEST_AND_RETURN_FALSE(hasher.UpdateFile(*paths[i], infos[i]->size()));
- TEST_AND_RETURN_FALSE(hasher.Finalize());
- TEST_AND_RETURN_FALSE(hasher.raw_hash().size() == infos[i]->hash().size());
- TEST_AND_RETURN_FALSE(memcmp(hasher.raw_hash().data(),
- infos[i]->hash().data(),
- hasher.raw_hash().size()) == 0);
- }
+ *kernel_size = manifest_.new_kernel_info().size();
+ *rootfs_size = manifest_.new_rootfs_info().size();
+ vector<char> new_kernel_hash(manifest_.new_kernel_info().hash().begin(),
+ manifest_.new_kernel_info().hash().end());
+ vector<char> new_rootfs_hash(manifest_.new_rootfs_info().hash().begin(),
+ manifest_.new_rootfs_info().hash().end());
+ kernel_hash->swap(new_kernel_hash);
+ rootfs_hash->swap(new_rootfs_hash);
return true;
}
@@ -616,19 +612,19 @@
CHECK(manifest_valid_);
if (manifest_.has_old_kernel_info()) {
const PartitionInfo& info = manifest_.old_kernel_info();
- TEST_AND_RETURN_FALSE(current_kernel_hash_ != NULL &&
- current_kernel_hash_->size() == info.hash().size() &&
- memcmp(current_kernel_hash_->data(),
+ TEST_AND_RETURN_FALSE(!current_kernel_hash_.empty() &&
+ current_kernel_hash_.size() == info.hash().size() &&
+ memcmp(current_kernel_hash_.data(),
info.hash().data(),
- current_kernel_hash_->size()) == 0);
+ current_kernel_hash_.size()) == 0);
}
if (manifest_.has_old_rootfs_info()) {
const PartitionInfo& info = manifest_.old_rootfs_info();
- TEST_AND_RETURN_FALSE(current_rootfs_hash_ != NULL &&
- current_rootfs_hash_->size() == info.hash().size() &&
- memcmp(current_rootfs_hash_->data(),
+ TEST_AND_RETURN_FALSE(!current_rootfs_hash_.empty() &&
+ current_rootfs_hash_.size() == info.hash().size() &&
+ memcmp(current_rootfs_hash_.data(),
info.hash().data(),
- current_rootfs_hash_->size()) == 0);
+ current_rootfs_hash_.size()) == 0);
}
return true;
}
diff --git a/delta_performer.h b/delta_performer.h
index 0e3cb93..8a9914d 100644
--- a/delta_performer.h
+++ b/delta_performer.h
@@ -34,9 +34,7 @@
next_operation_num_(0),
buffer_offset_(0),
last_updated_buffer_offset_(kuint64max),
- block_size_(0),
- current_kernel_hash_(NULL),
- current_rootfs_hash_(NULL) {}
+ block_size_(0) {}
// Opens the kernel. Should be called before or after Open(), but before
// Write(). The kernel file will be close()d when Close() is called.
@@ -65,10 +63,16 @@
const std::string& update_check_response_hash,
const uint64_t update_check_response_size);
- // Verifies that the generated update is correct based on the hashes sent by
- // the server. Returns true on success, false otherwise.
- bool VerifyAppliedUpdate(const std::string& path,
- const std::string& kernel_path);
+ // Reads from the update manifest the expected sizes and hashes of the target
+ // kernel and rootfs partitions. These values can be used for applied update
+ // hash verification. This method must be called after the update manifest has
+ // been parsed (e.g., after closing the stream). Returns true on success, and
+ // false on failure (e.g., when the values are not present in the update
+ // manifest).
+ bool GetNewPartitionInfo(uint64_t* kernel_size,
+ std::vector<char>* kernel_hash,
+ uint64_t* rootfs_size,
+ std::vector<char>* rootfs_hash);
// Converts an ordered collection of Extent objects which contain data of
// length full_length to a comma-separated string. For each Extent, the
@@ -96,11 +100,11 @@
// success, false otherwise.
static bool ResetUpdateProgress(PrefsInterface* prefs, bool quick);
- void set_current_kernel_hash(const std::vector<char>* hash) {
+ void set_current_kernel_hash(const std::vector<char>& hash) {
current_kernel_hash_ = hash;
}
- void set_current_rootfs_hash(const std::vector<char>* hash) {
+ void set_current_rootfs_hash(const std::vector<char>& hash) {
current_rootfs_hash_ = hash;
}
@@ -199,8 +203,8 @@
// Hashes for the current partitions to be used for source partition
// verification.
- const std::vector<char>* current_kernel_hash_;
- const std::vector<char>* current_rootfs_hash_;
+ std::vector<char> current_kernel_hash_;
+ std::vector<char> current_rootfs_hash_;
DISALLOW_COPY_AND_ASSIGN(DeltaPerformer);
};
diff --git a/delta_performer_unittest.cc b/delta_performer_unittest.cc
index 42f237b..238731a 100755
--- a/delta_performer_unittest.cc
+++ b/delta_performer_unittest.cc
@@ -315,11 +315,11 @@
OmahaHashCalculator::RawHashOfFile(a_img,
image_size,
&rootfs_hash));
- performer.set_current_rootfs_hash(&rootfs_hash);
+ performer.set_current_rootfs_hash(rootfs_hash);
vector<char> kernel_hash;
EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(old_kernel_data,
&kernel_hash));
- performer.set_current_kernel_hash(&kernel_hash);
+ performer.set_current_kernel_hash(kernel_hash);
EXPECT_EQ(0, performer.Open(a_img.c_str(), 0, 0));
EXPECT_TRUE(performer.OpenKernel(old_kernel.c_str()));
@@ -347,7 +347,27 @@
kUnittestPublicKeyPath,
OmahaHashCalculator::OmahaHashOfData(delta),
delta.size()));
- EXPECT_TRUE(performer.VerifyAppliedUpdate(a_img, old_kernel));
+
+ uint64_t new_kernel_size;
+ vector<char> new_kernel_hash;
+ uint64_t new_rootfs_size;
+ vector<char> new_rootfs_hash;
+ EXPECT_TRUE(performer.GetNewPartitionInfo(&new_kernel_size,
+ &new_kernel_hash,
+ &new_rootfs_size,
+ &new_rootfs_hash));
+ EXPECT_EQ(4096, new_kernel_size);
+ vector<char> expected_new_kernel_hash;
+ EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(new_kernel_data,
+ &expected_new_kernel_hash));
+ EXPECT_TRUE(expected_new_kernel_hash == new_kernel_hash);
+ EXPECT_EQ(image_size, new_rootfs_size);
+ vector<char> expected_new_rootfs_hash;
+ EXPECT_EQ(image_size,
+ OmahaHashCalculator::RawHashOfFile(b_img,
+ image_size,
+ &expected_new_rootfs_hash));
+ EXPECT_TRUE(expected_new_rootfs_hash == new_rootfs_hash);
}
}
diff --git a/download_action.cc b/download_action.cc
index d06fb79..d6ae97d 100644
--- a/download_action.cc
+++ b/download_action.cc
@@ -65,10 +65,8 @@
writer_ = decompressing_file_writer_.get();
} else {
delta_performer_.reset(new DeltaPerformer(prefs_));
- delta_performer_->set_current_kernel_hash(
- &install_plan_.current_kernel_hash);
- delta_performer_->set_current_rootfs_hash(
- &install_plan_.current_rootfs_hash);
+ delta_performer_->set_current_kernel_hash(install_plan_.kernel_hash);
+ delta_performer_->set_current_rootfs_hash(install_plan_.rootfs_hash);
writer_ = delta_performer_.get();
}
}
@@ -169,11 +167,13 @@
LOG(ERROR) << "Download of " << install_plan_.download_url
<< " failed due to payload verification error.";
code = kActionCodeDownloadPayloadVerificationError;
- } else if (!delta_performer_->VerifyAppliedUpdate(
- install_plan_.install_path, install_plan_.kernel_install_path)) {
- LOG(ERROR) << "Download of " << install_plan_.download_url
- << " failed due to applied update verification error.";
- code = kActionCodeDownloadAppliedUpdateVerificationError;
+ } else if (!delta_performer_->GetNewPartitionInfo(
+ &install_plan_.kernel_size,
+ &install_plan_.kernel_hash,
+ &install_plan_.rootfs_size,
+ &install_plan_.rootfs_hash)) {
+ LOG(ERROR) << "Unable to get new partition hash info.";
+ code = kActionCodeDownloadNewPartitionInfoError;
}
} else {
// Makes sure the hash and size are correct for an old-style full update.
@@ -196,7 +196,7 @@
// Write the path to the output pipe if we're successful.
if (code == kActionCodeSuccess && HasOutputPipe())
- SetOutputObject(GetInputObject());
+ SetOutputObject(install_plan_);
processor_->ActionComplete(this, code);
}
diff --git a/filesystem_copier_action.cc b/filesystem_copier_action.cc
index f3f71bd..7da54a8 100755
--- a/filesystem_copier_action.cc
+++ b/filesystem_copier_action.cc
@@ -32,12 +32,14 @@
namespace chromeos_update_engine {
namespace {
-const off_t kCopyFileBufferSize = 512 * 1024;
+const off_t kCopyFileBufferSize = 128 * 1024;
} // namespace {}
FilesystemCopierAction::FilesystemCopierAction(
- bool copying_kernel_install_path)
+ bool copying_kernel_install_path,
+ bool verify_hash)
: copying_kernel_install_path_(copying_kernel_install_path),
+ verify_hash_(verify_hash),
src_stream_(NULL),
dst_stream_(NULL),
read_done_(false),
@@ -68,44 +70,49 @@
}
install_plan_ = GetInputObject();
- if (install_plan_.is_full_update || install_plan_.is_resume) {
- // No copy needed. Done!
+ // Note that we do need to run hash verification for new-style full updates
+ // but currently the |is_full_update| field is set to true only for old-style
+ // full updates and we don't have any expected partition info in that case.
+ if (install_plan_.is_full_update ||
+ (!verify_hash_ && install_plan_.is_resume)) {
+ // No copy or hash verification needed. Done!
if (HasOutputPipe())
SetOutputObject(install_plan_);
abort_action_completer.set_code(kActionCodeSuccess);
return;
}
- string source = copy_source_;
+ const string destination = copying_kernel_install_path_ ?
+ install_plan_.kernel_install_path :
+ install_plan_.install_path;
+ string source = verify_hash_ ? destination : copy_source_;
if (source.empty()) {
source = copying_kernel_install_path_ ?
utils::BootKernelDevice(utils::BootDevice()) :
utils::BootDevice();
}
-
- const string destination = copying_kernel_install_path_ ?
- install_plan_.kernel_install_path :
- install_plan_.install_path;
-
int src_fd = open(source.c_str(), O_RDONLY);
if (src_fd < 0) {
PLOG(ERROR) << "Unable to open " << source << " for reading:";
return;
}
- int dst_fd = open(destination.c_str(),
- O_WRONLY | O_TRUNC | O_CREAT,
+
+ if (!verify_hash_) {
+ int dst_fd = open(destination.c_str(),
+ O_WRONLY | O_TRUNC | O_CREAT,
0644);
- if (dst_fd < 0) {
- close(src_fd);
- PLOG(ERROR) << "Unable to open " << install_plan_.install_path
- << " for writing:";
- return;
+ if (dst_fd < 0) {
+ close(src_fd);
+ PLOG(ERROR) << "Unable to open " << install_plan_.install_path
+ << " for writing:";
+ return;
+ }
+
+ dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
}
DetermineFilesystemSize(src_fd);
-
src_stream_ = g_unix_input_stream_new(src_fd, TRUE);
- dst_stream_ = g_unix_output_stream_new(dst_fd, TRUE);
for (int i = 0; i < 2; i++) {
buffer_[i].resize(kCopyFileBufferSize);
@@ -126,22 +133,22 @@
}
}
-void FilesystemCopierAction::Cleanup(bool success) {
+void FilesystemCopierAction::Cleanup(ActionExitCode code) {
for (int i = 0; i < 2; i++) {
g_object_unref(canceller_[i]);
canceller_[i] = NULL;
}
g_object_unref(src_stream_);
src_stream_ = NULL;
- g_object_unref(dst_stream_);
- dst_stream_ = NULL;
+ if (dst_stream_) {
+ g_object_unref(dst_stream_);
+ dst_stream_ = NULL;
+ }
if (cancelled_)
return;
- if (success && HasOutputPipe())
+ if (code == kActionCodeSuccess && HasOutputPipe())
SetOutputObject(install_plan_);
- processor_->ActionComplete(
- this,
- success ? kActionCodeSuccess : kActionCodeError);
+ processor_->ActionComplete(this, code);
}
void FilesystemCopierAction::AsyncReadReadyCallback(GObject *source_object,
@@ -164,19 +171,21 @@
} else {
buffer_valid_size_[index] = bytes_read;
buffer_state_[index] = kBufferStateFull;
- }
-
- if (bytes_read > 0) {
filesystem_size_ -= bytes_read;
}
-
SpawnAsyncActions();
if (bytes_read > 0) {
+ // If read_done_ is set, SpawnAsyncActions may finalize the hash so the hash
+ // update below would happen too late.
+ CHECK(!read_done_);
if (!hasher_.Update(buffer_[index].data(), bytes_read)) {
LOG(ERROR) << "Unable to update the hash.";
failed_ = true;
}
+ if (verify_hash_) {
+ buffer_state_[index] = kBufferStateEmpty;
+ }
}
}
@@ -235,23 +244,26 @@
}
if (failed_ || cancelled_) {
if (!reading && !writing) {
- Cleanup(false);
+ Cleanup(kActionCodeError);
}
return;
}
for (int i = 0; i < 2; i++) {
if (!reading && !read_done_ && buffer_state_[i] == kBufferStateEmpty) {
+ int64_t bytes_to_read = std::min(static_cast<int64_t>(buffer_[0].size()),
+ filesystem_size_);
g_input_stream_read_async(
src_stream_,
buffer_[i].data(),
- GetBytesToRead(),
+ bytes_to_read,
G_PRIORITY_DEFAULT,
canceller_[i],
&FilesystemCopierAction::StaticAsyncReadReadyCallback,
this);
reading = true;
buffer_state_[i] = kBufferStateReading;
- } else if (!writing && buffer_state_[i] == kBufferStateFull) {
+ } else if (!writing && !verify_hash_ &&
+ buffer_state_[i] == kBufferStateFull) {
g_output_stream_write_async(
dst_stream_,
buffer_[i].data(),
@@ -266,22 +278,43 @@
}
if (!reading && !writing) {
// We're done!
+ ActionExitCode code = kActionCodeSuccess;
if (hasher_.Finalize()) {
- LOG(INFO) << "hash: " << hasher_.hash();
- if (copying_kernel_install_path_) {
- install_plan_.current_kernel_hash = hasher_.raw_hash();
+ LOG(INFO) << "Hash: " << hasher_.hash();
+ if (verify_hash_) {
+ if (copying_kernel_install_path_) {
+ if (install_plan_.kernel_hash != hasher_.raw_hash()) {
+ code = kActionCodeNewKernelVerificationError;
+ LOG(ERROR) << "New kernel verification failed.";
+ }
+ } else {
+ if (install_plan_.rootfs_hash != hasher_.raw_hash()) {
+ code = kActionCodeNewRootfsVerificationError;
+ LOG(ERROR) << "New rootfs verification failed.";
+ }
+ }
} else {
- install_plan_.current_rootfs_hash = hasher_.raw_hash();
+ if (copying_kernel_install_path_) {
+ install_plan_.kernel_hash = hasher_.raw_hash();
+ } else {
+ install_plan_.rootfs_hash = hasher_.raw_hash();
+ }
}
- Cleanup(true);
} else {
LOG(ERROR) << "Unable to finalize the hash.";
- Cleanup(false);
+ code = kActionCodeError;
}
+ Cleanup(code);
}
}
void FilesystemCopierAction::DetermineFilesystemSize(int fd) {
+ if (verify_hash_) {
+ filesystem_size_ = copying_kernel_install_path_ ?
+ install_plan_.kernel_size : install_plan_.rootfs_size;
+ LOG(INFO) << "Filesystem size: " << filesystem_size_;
+ return;
+ }
filesystem_size_ = kint64max;
int block_count = 0, block_size = 0;
if (!copying_kernel_install_path_ &&
@@ -292,8 +325,4 @@
}
}
-int64_t FilesystemCopierAction::GetBytesToRead() {
- return std::min(static_cast<int64_t>(buffer_[0].size()), filesystem_size_);
-}
-
} // namespace chromeos_update_engine
diff --git a/filesystem_copier_action.h b/filesystem_copier_action.h
index 6dbde41..0658597 100644
--- a/filesystem_copier_action.h
+++ b/filesystem_copier_action.h
@@ -37,7 +37,8 @@
class FilesystemCopierAction : public Action<FilesystemCopierAction> {
public:
- explicit FilesystemCopierAction(bool copying_kernel_install_path);
+ FilesystemCopierAction(bool copying_kernel_install_path,
+ bool verify_hash);
typedef ActionTraits<FilesystemCopierAction>::InputObjectType
InputObjectType;
@@ -58,7 +59,8 @@
FRIEND_TEST(FilesystemCopierActionTest, RunAsRootDetermineFilesystemSizeTest);
// Ping-pong buffers generally cycle through the following states:
- // Empty->Reading->Full->Writing->Empty.
+ // Empty->Reading->Full->Writing->Empty. In hash verification mode the state
+ // is never set to Writing.
enum BufferState {
kBufferStateEmpty,
kBufferStateReading,
@@ -82,23 +84,24 @@
void SpawnAsyncActions();
// Cleans up all the variables we use for async operations and tells the
- // ActionProcessor we're done w/ success as passed in. |cancelled_| should be
+ // ActionProcessor we're done w/ |code| as passed in. |cancelled_| should be
// true if TerminateProcessing() was called.
- void Cleanup(bool success);
+ void Cleanup(ActionExitCode code);
// Determine, if possible, the source file system size to avoid copying the
// whole partition. Currently this supports only the root file system assuming
// it's ext3-compatible.
void DetermineFilesystemSize(int fd);
- // Returns the number of bytes to read based on the size of the buffer and the
- // filesystem size.
- int64_t GetBytesToRead();
-
// If true, this action is copying to the kernel_install_path from
// the install plan, otherwise it's copying just to the install_path.
const bool copying_kernel_install_path_;
+ // If true, this action is running in applied update hash verification mode --
+ // it computes a hash for the target install path and compares it against the
+ // expected value.
+ const bool verify_hash_;
+
// The path to copy from. If empty (the default), the source is from the
// passed in InstallPlan.
std::string copy_source_;
diff --git a/filesystem_copier_action_unittest.cc b/filesystem_copier_action_unittest.cc
index 032a24d..2ce3cc4 100644
--- a/filesystem_copier_action_unittest.cc
+++ b/filesystem_copier_action_unittest.cc
@@ -27,9 +27,12 @@
class FilesystemCopierActionTest : public ::testing::Test {
protected:
+ // |verify_hash|: 0 - no hash verification, 1 -- successful hash verification,
+ // 2 -- hash verification failure.
void DoTest(bool run_out_of_space,
bool terminate_early,
- bool use_kernel_partition);
+ bool use_kernel_partition,
+ int verify_hash);
void SetUp() {
}
void TearDown() {
@@ -90,13 +93,14 @@
TEST_F(FilesystemCopierActionTest, RunAsRootSimpleTest) {
ASSERT_EQ(0, getuid());
- DoTest(false, false, false);
-
- DoTest(false, false, true);
+ DoTest(false, false, false, 0);
+ DoTest(false, false, true, 0);
}
+
void FilesystemCopierActionTest::DoTest(bool run_out_of_space,
bool terminate_early,
- bool use_kernel_partition) {
+ bool use_kernel_partition,
+ int verify_hash) {
GMainLoop *loop = g_main_loop_new(g_main_context_default(), FALSE);
string a_loop_file;
@@ -142,10 +146,29 @@
// Set up the action objects
InstallPlan install_plan;
install_plan.is_full_update = false;
- if (use_kernel_partition)
- install_plan.kernel_install_path = b_dev;
- else
- install_plan.install_path = b_dev;
+ if (verify_hash) {
+ if (use_kernel_partition) {
+ install_plan.kernel_install_path = a_dev;
+ install_plan.kernel_size =
+ kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
+ EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
+ a_loop_data,
+ &install_plan.kernel_hash));
+ } else {
+ install_plan.install_path = a_dev;
+ install_plan.rootfs_size =
+ kLoopFileSize - ((verify_hash == 2) ? 1 : 0);
+ EXPECT_TRUE(OmahaHashCalculator::RawHashOfData(
+ a_loop_data,
+ &install_plan.rootfs_hash));
+ }
+ } else {
+ if (use_kernel_partition) {
+ install_plan.kernel_install_path = b_dev;
+ } else {
+ install_plan.install_path = b_dev;
+ }
+ }
ActionProcessor processor;
FilesystemCopierActionTestDelegate delegate;
@@ -153,7 +176,8 @@
processor.set_delegate(&delegate);
ObjectFeederAction<InstallPlan> feeder_action;
- FilesystemCopierAction copier_action(use_kernel_partition);
+ FilesystemCopierAction copier_action(use_kernel_partition,
+ verify_hash != 0);
ObjectCollectorAction<InstallPlan> collector_action;
BondActions(&feeder_action, &copier_action);
@@ -163,7 +187,9 @@
processor.EnqueueAction(&copier_action);
processor.EnqueueAction(&collector_action);
- copier_action.set_copy_source(a_dev);
+ if (!verify_hash) {
+ copier_action.set_copy_source(a_dev);
+ }
feeder_action.set_obj(install_plan);
StartProcessorCallbackArgs start_callback_args;
@@ -181,21 +207,26 @@
EXPECT_EQ(kActionCodeError, delegate.code());
return;
}
+ if (verify_hash == 2) {
+ EXPECT_EQ(use_kernel_partition ?
+ kActionCodeNewKernelVerificationError :
+ kActionCodeNewRootfsVerificationError,
+ delegate.code());
+ return;
+ }
EXPECT_EQ(kActionCodeSuccess, delegate.code());
// Make sure everything in the out_image is there
vector<char> a_out;
- vector<char> b_out;
EXPECT_TRUE(utils::ReadFile(a_dev, &a_out));
- EXPECT_TRUE(utils::ReadFile(b_dev, &b_out));
- EXPECT_TRUE(ExpectVectorsEq(a_out, b_out));
+ if (!verify_hash) {
+ vector<char> b_out;
+ EXPECT_TRUE(utils::ReadFile(b_dev, &b_out));
+ EXPECT_TRUE(ExpectVectorsEq(a_out, b_out));
+ }
EXPECT_TRUE(ExpectVectorsEq(a_loop_data, a_out));
EXPECT_TRUE(collector_action.object() == install_plan);
- if (terminate_early) {
- // sleep so OS can clean up
- sleep(1);
- }
}
class FilesystemCopierActionTest2Delegate : public ActionProcessorDelegate {
@@ -219,7 +250,7 @@
processor.set_delegate(&delegate);
- FilesystemCopierAction copier_action(false);
+ FilesystemCopierAction copier_action(false, false);
ObjectCollectorAction<InstallPlan> collector_action;
BondActions(&copier_action, &collector_action);
@@ -242,7 +273,7 @@
const char* kUrl = "http://some/url";
InstallPlan install_plan(true, false, kUrl, 0, "", "", "");
feeder_action.set_obj(install_plan);
- FilesystemCopierAction copier_action(false);
+ FilesystemCopierAction copier_action(false, false);
ObjectCollectorAction<InstallPlan> collector_action;
BondActions(&feeder_action, &copier_action);
@@ -268,7 +299,7 @@
const char* kUrl = "http://some/url";
InstallPlan install_plan(false, true, kUrl, 0, "", "", "");
feeder_action.set_obj(install_plan);
- FilesystemCopierAction copier_action(false);
+ FilesystemCopierAction copier_action(false, false);
ObjectCollectorAction<InstallPlan> collector_action;
BondActions(&feeder_action, &copier_action);
@@ -299,7 +330,7 @@
"/no/such/file",
"/no/such/file");
feeder_action.set_obj(install_plan);
- FilesystemCopierAction copier_action(false);
+ FilesystemCopierAction copier_action(false, false);
ObjectCollectorAction<InstallPlan> collector_action;
BondActions(&copier_action, &collector_action);
@@ -313,14 +344,26 @@
EXPECT_EQ(kActionCodeError, delegate.code_);
}
+TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashTest) {
+ ASSERT_EQ(0, getuid());
+ DoTest(false, false, false, 1);
+ DoTest(false, false, true, 1);
+}
+
+TEST_F(FilesystemCopierActionTest, RunAsRootVerifyHashFailTest) {
+ ASSERT_EQ(0, getuid());
+ DoTest(false, false, false, 2);
+ DoTest(false, false, true, 2);
+}
+
TEST_F(FilesystemCopierActionTest, RunAsRootNoSpaceTest) {
ASSERT_EQ(0, getuid());
- DoTest(true, false, false);
+ DoTest(true, false, false, 0);
}
TEST_F(FilesystemCopierActionTest, RunAsRootTerminateEarlyTest) {
ASSERT_EQ(0, getuid());
- DoTest(false, true, false);
+ DoTest(false, true, false, 0);
}
TEST_F(FilesystemCopierActionTest, RunAsRootDetermineFilesystemSizeTest) {
@@ -336,7 +379,7 @@
for (int i = 0; i < 2; ++i) {
bool is_kernel = i == 1;
- FilesystemCopierAction action(is_kernel);
+ FilesystemCopierAction action(is_kernel, false);
EXPECT_EQ(kint64max, action.filesystem_size_);
{
int fd = HANDLE_EINTR(open(img.c_str(), O_RDONLY));
diff --git a/generate_delta_main.cc b/generate_delta_main.cc
index 39a0e08..6e9e553 100644
--- a/generate_delta_main.cc
+++ b/generate_delta_main.cc
@@ -90,8 +90,8 @@
vector<char> root_hash(root_info.hash().begin(),
root_info.hash().end());
DeltaPerformer performer(&prefs);
- performer.set_current_kernel_hash(&kern_hash);
- performer.set_current_rootfs_hash(&root_hash);
+ performer.set_current_kernel_hash(kern_hash);
+ performer.set_current_rootfs_hash(root_hash);
CHECK_EQ(performer.Open(FLAGS_old_image.c_str(), 0, 0), 0);
CHECK(performer.OpenKernel(FLAGS_old_kernel.c_str()));
vector<char> buf(1024 * 1024);
diff --git a/install_plan.h b/install_plan.h
index 9911d32..08472c8 100644
--- a/install_plan.h
+++ b/install_plan.h
@@ -29,7 +29,9 @@
size(size),
download_hash(hash),
install_path(install_path),
- kernel_install_path(kernel_install_path) {}
+ kernel_install_path(kernel_install_path),
+ kernel_size(0),
+ rootfs_size(0) {}
InstallPlan() : is_full_update(false), is_resume(false), size(0) {}
bool is_full_update;
@@ -39,8 +41,22 @@
std::string download_hash; // hash of the data at the url
std::string install_path; // path to install device
std::string kernel_install_path; // path to kernel install device
- std::vector<char> current_kernel_hash; // computed by FileSystemCopierAction
- std::vector<char> current_rootfs_hash; // computed by FileSystemCopierAction
+
+ // The fields below are used for kernel and rootfs verification. The flow is:
+ //
+ // 1. FilesystemCopierAction(verify_hash=false) computes and fills in the
+ // source partition sizes and hashes.
+ //
+ // 2. DownloadAction verifies the source partition sizes and hashes against
+ // the expected values transmitted in the update manifest. It fills in the
+ // expected applied partition sizes and hashes based on the manifest.
+ //
+ // 4. FilesystemCopierAction(verify_hashes=true) computes and verifies the
+ // applied partition sizes and hashes against the expected values.
+ uint64_t kernel_size;
+ uint64_t rootfs_size;
+ std::vector<char> kernel_hash;
+ std::vector<char> rootfs_hash;
bool operator==(const InstallPlan& that) const {
return (is_full_update == that.is_full_update) &&
diff --git a/update_attempter.cc b/update_attempter.cc
index 529338a..85500e6 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -139,7 +139,7 @@
LOG(ERROR) << "Unable to initialize Omaha request device params.";
return;
}
-
+
obeying_proxies_ = true;
if (obey_proxies || proxy_manual_checks_ == 0) {
LOG(INFO) << "forced to obey proxies";
@@ -175,9 +175,9 @@
shared_ptr<OmahaResponseHandlerAction> response_handler_action(
new OmahaResponseHandlerAction(prefs_));
shared_ptr<FilesystemCopierAction> filesystem_copier_action(
- new FilesystemCopierAction(false));
+ new FilesystemCopierAction(false, false));
shared_ptr<FilesystemCopierAction> kernel_filesystem_copier_action(
- new FilesystemCopierAction(true));
+ new FilesystemCopierAction(true, false));
shared_ptr<OmahaRequestAction> download_started_action(
new OmahaRequestAction(prefs_,
omaha_request_params_,
@@ -193,6 +193,10 @@
new OmahaEvent(
OmahaEvent::kTypeUpdateDownloadFinished),
new LibcurlHttpFetcher(GetProxyResolver())));
+ shared_ptr<FilesystemCopierAction> filesystem_verifier_action(
+ new FilesystemCopierAction(false, true));
+ shared_ptr<FilesystemCopierAction> kernel_filesystem_verifier_action(
+ new FilesystemCopierAction(true, true));
shared_ptr<PostinstallRunnerAction> postinstall_runner_action(
new PostinstallRunnerAction);
shared_ptr<OmahaRequestAction> update_complete_action(
@@ -213,6 +217,9 @@
actions_.push_back(shared_ptr<AbstractAction>(download_started_action));
actions_.push_back(shared_ptr<AbstractAction>(download_action));
actions_.push_back(shared_ptr<AbstractAction>(download_finished_action));
+ actions_.push_back(shared_ptr<AbstractAction>(filesystem_verifier_action));
+ actions_.push_back(shared_ptr<AbstractAction>(
+ kernel_filesystem_verifier_action));
actions_.push_back(shared_ptr<AbstractAction>(postinstall_runner_action));
actions_.push_back(shared_ptr<AbstractAction>(update_complete_action));
@@ -233,6 +240,10 @@
BondActions(kernel_filesystem_copier_action.get(),
download_action.get());
BondActions(download_action.get(),
+ filesystem_verifier_action.get());
+ BondActions(filesystem_verifier_action.get(),
+ kernel_filesystem_verifier_action.get());
+ BondActions(kernel_filesystem_verifier_action.get(),
postinstall_runner_action.get());
SetStatusAndNotify(UPDATE_STATUS_CHECKING_FOR_UPDATE);
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 6d61c4e..2f60609 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -129,7 +129,7 @@
EXPECT_EQ(kActionCodeOmahaResponseHandlerError,
GetErrorCodeForAction(&omaha_response_handler_action,
kActionCodeError));
- FilesystemCopierAction filesystem_copier_action(false);
+ FilesystemCopierAction filesystem_copier_action(false, false);
EXPECT_EQ(kActionCodeFilesystemCopierError,
GetErrorCodeForAction(&filesystem_copier_action, kActionCodeError));
PostinstallRunnerAction postinstall_runner_action;
@@ -236,6 +236,8 @@
OmahaRequestAction::StaticType(),
DownloadAction::StaticType(),
OmahaRequestAction::StaticType(),
+ FilesystemCopierAction::StaticType(),
+ FilesystemCopierAction::StaticType(),
PostinstallRunnerAction::StaticType(),
OmahaRequestAction::StaticType()
};