Upon source hash validation failure, log ext4 remount information
When source hash verification fails, check if the current partition
is an ext4 that has been remounted.
Log mount count and date.
Based on corresponding functionality in recovery.
Bug: 72074823
Test: manual - Confirm that remount count is present in the log when
installing an update and the system has been remounted
Change-Id: I3cf12c9f93fa5ef9f73f0a1b6a795eb2a3e9335e
diff --git a/Android.mk b/Android.mk
index 5a3129e..d79d89b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -141,6 +141,7 @@
payload_consumer/file_writer.cc \
payload_consumer/filesystem_verifier_action.cc \
payload_consumer/install_plan.cc \
+ payload_consumer/mount_history.cc \
payload_consumer/payload_constants.cc \
payload_consumer/payload_verifier.cc \
payload_consumer/postinstall_runner_action.cc \
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 7c94c71..6540675 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -50,6 +50,7 @@
#include "update_engine/payload_consumer/extent_reader.h"
#include "update_engine/payload_consumer/extent_writer.h"
#include "update_engine/payload_consumer/file_descriptor_utils.h"
+#include "update_engine/payload_consumer/mount_history.h"
#if USE_MTD
#include "update_engine/payload_consumer/mtd_file_descriptor.h"
#endif
@@ -1079,8 +1080,10 @@
// 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) {
brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
operation.src_sha256_hash().end());
@@ -1107,6 +1110,9 @@
LOG(ERROR) << "Operation source (offset:size) in blocks: "
<< base::JoinString(source_extents, ",");
+ // Log remount history if this device is an ext4 partition.
+ LogMountHistory(source_fd);
+
*error = ErrorCode::kDownloadStateInitializationError;
return false;
}
@@ -1131,7 +1137,8 @@
&source_hash));
if (operation.has_src_sha256_hash()) {
- TEST_AND_RETURN_FALSE(ValidateSourceHash(source_hash, operation, error));
+ TEST_AND_RETURN_FALSE(
+ ValidateSourceHash(source_hash, operation, source_fd_, error));
}
return true;
@@ -1217,8 +1224,8 @@
total_blocks -= read_blocks;
}
TEST_AND_RETURN_FALSE(source_hasher.Finalize());
- TEST_AND_RETURN_FALSE(
- ValidateSourceHash(source_hasher.raw_hash(), operation, error));
+ TEST_AND_RETURN_FALSE(ValidateSourceHash(
+ source_hasher.raw_hash(), operation, source_fd_, error));
return true;
}
diff --git a/payload_consumer/mount_history.cc b/payload_consumer/mount_history.cc
new file mode 100644
index 0000000..43a75b3
--- /dev/null
+++ b/payload_consumer/mount_history.cc
@@ -0,0 +1,72 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/payload_consumer/mount_history.h"
+
+#include <inttypes.h>
+
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/time/time.h>
+
+#include "update_engine/common/utils.h"
+
+namespace chromeos_update_engine {
+void LogMountHistory(const FileDescriptorPtr blockdevice_fd) {
+ static constexpr ssize_t kBlockSize = 4096;
+
+ if (blockdevice_fd == nullptr) {
+ return;
+ }
+
+ brillo::Blob block0_buffer(kBlockSize);
+ ssize_t bytes_read;
+
+ if (!utils::PReadAll(
+ blockdevice_fd, block0_buffer.data(), kBlockSize, 0, &bytes_read)) {
+ LOG(WARNING) << "PReadAll failed";
+ return;
+ }
+
+ if (bytes_read != kBlockSize) {
+ LOG(WARNING) << "Could not read an entire block";
+ return;
+ }
+
+ // https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout
+ // Super block starts from block 0, offset 0x400
+ // 0x2C: len32 Mount time
+ // 0x30: len32 Write time
+ // 0x34: len16 Number of mounts since the last fsck
+ // 0x38: len16 Magic signature 0xEF53
+
+ time_t mount_time =
+ *reinterpret_cast<uint32_t*>(&block0_buffer[0x400 + 0x2C]);
+ uint16_t mount_count =
+ *reinterpret_cast<uint16_t*>(&block0_buffer[0x400 + 0x34]);
+ uint16_t magic = *reinterpret_cast<uint16_t*>(&block0_buffer[0x400 + 0x38]);
+
+ if (magic == 0xEF53) {
+ if (mount_count > 0) {
+ LOG(WARNING) << "Device was remounted R/W " << mount_count << " times. "
+ << "Last remount happened on "
+ << base::Time::FromTimeT(mount_time) << ".";
+ }
+ }
+}
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/mount_history.h b/payload_consumer/mount_history.h
new file mode 100644
index 0000000..ba0c65d
--- /dev/null
+++ b/payload_consumer/mount_history.h
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_PAYLOAD_CONSUMER_MOUNT_HISTORY_H_
+#define UPDATE_ENGINE_PAYLOAD_CONSUMER_MOUNT_HISTORY_H_
+
+#include "update_engine/payload_consumer/file_descriptor.h"
+
+namespace chromeos_update_engine {
+// Try to parse an ext4 from the partition specified by |blockdevice_fd|.
+// If ext4 header exists and remount is detected, log mount count and date.
+void LogMountHistory(const FileDescriptorPtr blockdevice_fd);
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_PAYLOAD_CONSUMER_MOUNT_HISTORY_H_
diff --git a/update_engine.gyp b/update_engine.gyp
index f312a1d..f72ca14 100644
--- a/update_engine.gyp
+++ b/update_engine.gyp
@@ -181,6 +181,7 @@
'payload_consumer/file_writer.cc',
'payload_consumer/filesystem_verifier_action.cc',
'payload_consumer/install_plan.cc',
+ 'payload_consumer/mount_history.cc',
'payload_consumer/payload_constants.cc',
'payload_consumer/payload_verifier.cc',
'payload_consumer/postinstall_runner_action.cc',