summaryrefslogtreecommitdiff
path: root/dynamic_partition_control_android_unittest.cc
diff options
context:
space:
mode:
authorYifan Hong <elsk@google.com>2020-03-26 12:47:05 -0700
committerYifan Hong <elsk@google.com>2020-04-08 11:16:27 -0700
commitcba9c46108cc230c20ecdebfd7d48b597a4e3faf (patch)
tree7a2738e3aa27f36ea63cd59a03fa523a56ff8b72 /dynamic_partition_control_android_unittest.cc
parentcc8d4e8e69eb2dac876e3d5a4c0bcf4b1e97389f (diff)
Add DynamicPartitionControl::EraseSystemOtherAvbFooter
Erase AVB footer of system other partition prior to any updates so that if an update overwrites it partially, and the device rolled back (or even before we finish writing the partition), and the device factory resets, mapping system_other as /postinstall won't trigger verity errors and reboots the device. Fixes: 152444348 Test: apply update, rollback, then FDR Test: apply update, then set sys.cppreopt=requested; observe that /postinstall cannot be mounted. Change-Id: I62e5bb8f4c31d9a1beff485c47fc4b07a3a5686b (cherry picked from commit 2969290920696611a67aed184baf71cac062b416) Merged-In: I62e5bb8f4c31d9a1beff485c47fc4b07a3a5686b
Diffstat (limited to 'dynamic_partition_control_android_unittest.cc')
-rw-r--r--dynamic_partition_control_android_unittest.cc141
1 files changed, 138 insertions, 3 deletions
diff --git a/dynamic_partition_control_android_unittest.cc b/dynamic_partition_control_android_unittest.cc
index 457ea108..20819182 100644
--- a/dynamic_partition_control_android_unittest.cc
+++ b/dynamic_partition_control_android_unittest.cc
@@ -23,12 +23,16 @@
#include <base/strings/string_util.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <libavb/libavb.h>
#include "update_engine/common/mock_prefs.h"
+#include "update_engine/common/test_utils.h"
#include "update_engine/dynamic_partition_test_utils.h"
#include "update_engine/mock_dynamic_partition_control.h"
using android::dm::DmDeviceState;
+using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
+using chromeos_update_engine::test_utils::ScopedTempFile;
using std::string;
using testing::_;
using testing::AnyNumber;
@@ -36,6 +40,7 @@ using testing::AnyOf;
using testing::Invoke;
using testing::NiceMock;
using testing::Not;
+using testing::Optional;
using testing::Return;
namespace chromeos_update_engine {
@@ -64,6 +69,9 @@ class DynamicPartitionControlAndroidTest : public ::testing::Test {
*device = GetDmDevice(partition_name_suffix);
return true;
}));
+
+ ON_CALL(dynamicControl(), EraseSystemOtherAvbFooter(_, _))
+ .WillByDefault(Return(true));
}
// Return the mocked DynamicPartitionControlInterface.
@@ -90,12 +98,15 @@ class DynamicPartitionControlAndroidTest : public ::testing::Test {
// Set the fake metadata to return when LoadMetadataBuilder is called on
// |slot|.
- void SetMetadata(uint32_t slot, const PartitionSuffixSizes& sizes) {
+ void SetMetadata(uint32_t slot,
+ const PartitionSuffixSizes& sizes,
+ uint32_t partition_attr = 0) {
EXPECT_CALL(dynamicControl(),
LoadMetadataBuilder(GetSuperDevice(slot), slot, _))
.Times(AnyNumber())
- .WillRepeatedly(Invoke([sizes](auto, auto, auto) {
- return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes));
+ .WillRepeatedly(Invoke([sizes, partition_attr](auto, auto, auto) {
+ return NewFakeMetadata(PartitionSuffixSizesToManifest(sizes),
+ partition_attr);
}));
}
@@ -757,4 +768,128 @@ TEST_F(DynamicPartitionControlAndroidTest, ResetUpdate) {
ASSERT_TRUE(dynamicControl().ResetUpdate(&prefs));
}
+TEST_F(DynamicPartitionControlAndroidTest, IsAvbNotEnabledInFstab) {
+ // clang-format off
+ std::string fstab_content =
+ "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical\n" // NOLINT(whitespace/line_length)
+ "/dev/block/by-name/system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other\n"; // NOLINT(whitespace/line_length)
+ // clang-format on
+ ScopedTempFile fstab;
+ ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
+ ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
+ Optional(false));
+}
+
+TEST_F(DynamicPartitionControlAndroidTest, IsAvbEnabledInFstab) {
+ // clang-format off
+ std::string fstab_content =
+ "system /postinstall ext4 ro,nosuid,nodev,noexec slotselect_other,logical,avb_keys=/foo\n"; // NOLINT(whitespace/line_length)
+ // clang-format on
+ ScopedTempFile fstab;
+ ASSERT_TRUE(test_utils::WriteFileString(fstab.path(), fstab_content));
+ ASSERT_THAT(dynamicControl().RealIsAvbEnabledInFstab(fstab.path()),
+ Optional(true));
+}
+
+TEST_P(DynamicPartitionControlAndroidTestP, AvbNotEnabledOnSystemOther) {
+ ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
+ .WillByDefault(Invoke([&](auto source_slot,
+ auto target_slot,
+ const auto& name,
+ auto path,
+ auto should_unmap) {
+ return dynamicControl().RealGetSystemOtherPath(
+ source_slot, target_slot, name, path, should_unmap);
+ }));
+ ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
+ .WillByDefault(Return(false));
+ EXPECT_TRUE(
+ dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
+}
+
+TEST_P(DynamicPartitionControlAndroidTestP, NoSystemOtherToErase) {
+ SetMetadata(source(), {{S("system"), 100_MiB}});
+ ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
+ .WillByDefault(Return(true));
+ std::string path;
+ bool should_unmap;
+ ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
+ source(), target(), T("system"), &path, &should_unmap));
+ ASSERT_TRUE(path.empty()) << path;
+ ASSERT_FALSE(should_unmap);
+ ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
+ .WillByDefault(Invoke([&](auto source_slot,
+ auto target_slot,
+ const auto& name,
+ auto path,
+ auto should_unmap) {
+ return dynamicControl().RealGetSystemOtherPath(
+ source_slot, target_slot, name, path, should_unmap);
+ }));
+ EXPECT_TRUE(
+ dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
+}
+
+TEST_P(DynamicPartitionControlAndroidTestP, SkipEraseUpdatedSystemOther) {
+ PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), 100_MiB}};
+ SetMetadata(source(), sizes, LP_PARTITION_ATTR_UPDATED);
+ ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
+ .WillByDefault(Return(true));
+ std::string path;
+ bool should_unmap;
+ ASSERT_TRUE(dynamicControl().RealGetSystemOtherPath(
+ source(), target(), T("system"), &path, &should_unmap));
+ ASSERT_TRUE(path.empty()) << path;
+ ASSERT_FALSE(should_unmap);
+ ON_CALL(dynamicControl(), GetSystemOtherPath(_, _, _, _, _))
+ .WillByDefault(Invoke([&](auto source_slot,
+ auto target_slot,
+ const auto& name,
+ auto path,
+ auto should_unmap) {
+ return dynamicControl().RealGetSystemOtherPath(
+ source_slot, target_slot, name, path, should_unmap);
+ }));
+ EXPECT_TRUE(
+ dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
+}
+
+TEST_P(DynamicPartitionControlAndroidTestP, EraseSystemOtherAvbFooter) {
+ constexpr uint64_t file_size = 1_MiB;
+ static_assert(file_size > AVB_FOOTER_SIZE);
+ ScopedTempFile system_other;
+ brillo::Blob original(file_size, 'X');
+ ASSERT_TRUE(test_utils::WriteFileVector(system_other.path(), original));
+ std::string mnt_path;
+ ScopedLoopbackDeviceBinder dev(system_other.path(), true, &mnt_path);
+ ASSERT_TRUE(dev.is_bound());
+
+ brillo::Blob device_content;
+ ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
+ ASSERT_EQ(original, device_content);
+
+ PartitionSuffixSizes sizes{{S("system"), 100_MiB}, {T("system"), file_size}};
+ SetMetadata(source(), sizes);
+ ON_CALL(dynamicControl(), IsAvbEnabledOnSystemOther())
+ .WillByDefault(Return(true));
+ EXPECT_CALL(dynamicControl(),
+ GetSystemOtherPath(source(), target(), T("system"), _, _))
+ .WillRepeatedly(
+ Invoke([&](auto, auto, const auto&, auto path, auto should_unmap) {
+ *path = mnt_path;
+ *should_unmap = false;
+ return true;
+ }));
+ ASSERT_TRUE(
+ dynamicControl().RealEraseSystemOtherAvbFooter(source(), target()));
+
+ device_content.clear();
+ ASSERT_TRUE(utils::ReadFile(mnt_path, &device_content));
+ brillo::Blob new_expected(original);
+ // Clear the last AVB_FOOTER_SIZE bytes.
+ new_expected.resize(file_size - AVB_FOOTER_SIZE);
+ new_expected.resize(file_size, '\0');
+ ASSERT_EQ(new_expected, device_content);
+}
+
} // namespace chromeos_update_engine