Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ec71157 authored by David Anderson's avatar David Anderson
Browse files

libsnapshot: Reject bad cow versions.

Remove CowWriter::GetCowVersion. Instead, reject any update that asks
for VABC but has an unsupported version field. Do not fallback to legacy
VAB as the update was likely built improperly.

Bug: 280529365
Test: vts_libsnapshot_test
Change-Id: Ibc0f981801fd47bf39d7a19944134e4b3c66e5bf
parent d70a174e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@ static constexpr uint32_t kCowVersionMinor = 0;

static constexpr uint32_t kCowVersionManifest = 2;

static constexpr uint32_t kMinCowVersion = 1;
static constexpr uint32_t kMaxCowVersion = 2;

// This header appears as the first sequence of bytes in the COW. All fields
// in the layout are little-endian encoded. The on-disk layout is:
//
+0 −2
Original line number Diff line number Diff line
@@ -171,8 +171,6 @@ class CowWriter : public ICowWriter {

    uint64_t GetCowSize() override;

    uint32_t GetCowVersion() { return header_.prefix.major_version; }

  protected:
    virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
    virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
+18 −22
Original line number Diff line number Diff line
@@ -3202,39 +3202,20 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
    CHECK(current_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME &&
          target_metadata->GetBlockDevicePartitionName(0) == LP_METADATA_DEFAULT_PARTITION_NAME);

    std::map<std::string, SnapshotStatus> all_snapshot_status;

    // In case of error, automatically delete devices that are created along the way.
    // Note that "lock" is destroyed after "created_devices", so it is safe to use |lock| for
    // these devices.
    AutoDeviceList created_devices;

    const auto& dap_metadata = manifest.dynamic_partition_metadata();
    CowOptions options;
    CowWriter writer(options);
    bool cow_format_support = true;
    if (dap_metadata.cow_version() < writer.GetCowVersion()) {
        cow_format_support = false;
    }

    LOG(INFO) << " dap_metadata.cow_version(): " << dap_metadata.cow_version()
              << " writer.GetCowVersion(): " << writer.GetCowVersion();

    // Deduce supported features.
    bool userspace_snapshots = CanUseUserspaceSnapshots();
    bool legacy_compression = GetLegacyCompressionEnabledProperty();

    std::string vabc_disable_reason;
    if (!dap_metadata.vabc_enabled()) {
        vabc_disable_reason = "not enabled metadata";
    } else if (device_->IsRecovery()) {
        vabc_disable_reason = "recovery";
    } else if (!cow_format_support) {
        vabc_disable_reason = "cow format not supported";
    } else if (!KernelSupportsCompressedSnapshots()) {
        vabc_disable_reason = "kernel missing userspace block device support";
    }

    // Deduce supported features.
    bool userspace_snapshots = CanUseUserspaceSnapshots();
    bool legacy_compression = GetLegacyCompressionEnabledProperty();
    if (!vabc_disable_reason.empty()) {
        if (userspace_snapshots) {
            LOG(INFO) << "Userspace snapshots disabled: " << vabc_disable_reason;
@@ -3246,6 +3227,16 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
        legacy_compression = false;
    }

    if (legacy_compression || userspace_snapshots) {
        if (dap_metadata.cow_version() < kMinCowVersion ||
            dap_metadata.cow_version() > kMaxCowVersion) {
            LOG(ERROR) << "Manifest cow version is out of bounds (got: "
                       << dap_metadata.cow_version() << ", min: " << kMinCowVersion
                       << ", max: " << kMaxCowVersion << ")";
            return Return::Error();
        }
    }

    const bool using_snapuserd = userspace_snapshots || legacy_compression;
    if (!using_snapuserd) {
        LOG(INFO) << "Using legacy Virtual A/B (dm-snapshot)";
@@ -3278,6 +3269,11 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
        cow_creator.batched_writes = dap_metadata.vabc_feature_set().batch_writes();
    }

    // In case of error, automatically delete devices that are created along the way.
    // Note that "lock" is destroyed after "created_devices", so it is safe to use |lock| for
    // these devices.
    AutoDeviceList created_devices;
    std::map<std::string, SnapshotStatus> all_snapshot_status;
    auto ret = CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices,
                                             &all_snapshot_status);
    if (!ret.is_ok()) {
+18 −0
Original line number Diff line number Diff line
@@ -2688,6 +2688,24 @@ TEST_F(SnapshotUpdateTest, QueryStatusError) {
    ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
}

TEST_F(SnapshotUpdateTest, BadCowVersion) {
    if (!snapuserd_required_) {
        GTEST_SKIP() << "VABC only";
    }

    ASSERT_TRUE(sm->BeginUpdate());

    auto dynamic_partition_metadata = manifest_.mutable_dynamic_partition_metadata();
    dynamic_partition_metadata->set_cow_version(kMinCowVersion - 1);
    ASSERT_FALSE(sm->CreateUpdateSnapshots(manifest_));

    dynamic_partition_metadata->set_cow_version(kMaxCowVersion + 1);
    ASSERT_FALSE(sm->CreateUpdateSnapshots(manifest_));

    dynamic_partition_metadata->set_cow_version(kMaxCowVersion);
    ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
}

class FlashAfterUpdateTest : public SnapshotUpdateTest,
                             public WithParamInterface<std::tuple<uint32_t, bool>> {
  public: