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

Commit d79dd844 authored by Bowgo Tsai's avatar Bowgo Tsai
Browse files

libfs_avb: refactoring

This commit has the following changes:

    1. Builds libfs_avb via "fs_mgr/libfs_avb/Android.bp" instead of
       "fs_mgr/Android.bp", and removes the libfs_avb source
       dependencies on "fs_mgr/fs_mgr_priv.h".

    2. Moves static functions in fs_avb.cpp into util.cpp or
       avb_util.cpp, depending on whether the function is related to
       AVB or not.

    3. Introduces two host unit tests: libfs_avb_test and
       libfs_avb_internal_test, the former is to test public
       <fs_avb/fs_avb.h> APIs, while the latter is to test libfs_avb
       internal functions.

    4. Splits fs_avb_unittest_util.* into:
       - fs_avb_test_util.* (host static lib: libfs_avb_test_util),
       - basic_test.cpp (host executable: libfs_avb_test)

Bug: 112103720
Bug: 117960205
Test: atest libfs_avb_test
Test: atest libfs_avb_internal_test
Test: boot a device
Change-Id: I11d6c9e9019e20b594d9321b9a28118d4806e5a7
parent 3ffb4ab8
Loading
Loading
Loading
Loading
+0 −25
Original line number Diff line number Diff line
@@ -102,28 +102,3 @@ cc_library_static {
    export_include_dirs: ["include_fstab"],
    header_libs: ["libbase_headers"],
}

cc_library_static {
    name: "libfs_avb",
    defaults: ["fs_mgr_defaults"],
    recovery_available: true,
    export_include_dirs: ["libfs_avb/include"],
    srcs: [
        "libfs_avb/avb_ops.cpp",
        "libfs_avb/fs_avb.cpp",
    ],
    static_libs: [
        "libavb",
        "libfstab",
        "libdm",
    ],
    export_static_lib_headers: [
        "libfstab",
    ],
    shared_libs: [
        "libcrypto",
    ],
    header_libs: [
        "libbase_headers",
    ],
}
+100 −0
Original line number Diff line number Diff line
@@ -14,13 +14,41 @@
// limitations under the License.
//

cc_test_host {
    name: "libfs_avb_host_unittest",
cc_library_static {
    name: "libfs_avb",
    defaults: ["fs_mgr_defaults"],
    recovery_available: true,
    host_supported: true,
    export_include_dirs: ["include"],
    srcs: [
        "avb_ops.cpp",
        "avb_util.cpp",
        "fs_avb.cpp",
        "util.cpp",
    ],
    static_libs: [
        "libavb",
        "libdm",
        "libfstab",
    ],
    export_static_lib_headers: [
        "libfstab",
    ],
    shared_libs: [
        "libcrypto",
    ],
    header_libs: [
        "libbase_headers",
    ],
}

cc_defaults {
    name: "libfs_avb_host_test_defaults",
    required: [
        "avbtool",
    ],
    data: [
        "data/*",
        "tests/data/*",
    ],
    static_libs: [
        "libgtest_host",
@@ -29,12 +57,44 @@ cc_test_host {
        "libbase",
        "libchrome",
    ],
    srcs: [
        "fs_avb_unittest_util.cpp",
    ],
    target: {
        darwin: {
            enabled: false,
        },
    },
    cflags: [
        "-DHOST_TEST",
    ],
}

cc_library_host_static {
    name: "libfs_avb_test_util",
    defaults: ["libfs_avb_host_test_defaults"],
    srcs: [
        "tests/fs_avb_test_util.cpp",
    ],
}

cc_test_host {
    name: "libfs_avb_test",
    defaults: ["libfs_avb_host_test_defaults"],
    static_libs: [
        "libfs_avb_test_util",
    ],
    srcs: [
        "tests/basic_test.cpp",
    ],
}

cc_test_host {
    name: "libfs_avb_internal_test",
    defaults: ["libfs_avb_host_test_defaults"],
    static_libs: [
        "libfs_avb_test_util",
        "libfstab",
    ],
    srcs: [
        "util.cpp",
        "tests/util_test.cpp",
    ],
}
+2 −2
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@
#include <libavb/libavb.h>
#include <utils/Compat.h>

#include "fs_mgr_priv.h"
#include "util.h"

using namespace std::literals;

@@ -127,7 +127,7 @@ AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t of
    const std::string path = "/dev/block/by-name/"s + partition;

    // Ensures the device path (a symlink created by init) is ready to access.
    if (!fs_mgr_wait_for_file(path, 1s)) {
    if (!WaitForFile(path, 1s)) {
        return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
    }

+178 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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 "avb_util.h"

#include <array>
#include <sstream>

#include <android-base/file.h>
#include <android-base/unique_fd.h>

#include "util.h"

using android::base::unique_fd;

namespace android {
namespace fs_mgr {

// Constructs dm-verity arguments for sending DM_TABLE_LOAD ioctl to kernel.
// See the following link for more details:
// https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity
bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
                          const std::string& root_digest, const std::string& blk_device,
                          android::dm::DmTable* table) {
    // Loads androidboot.veritymode from kernel cmdline.
    std::string verity_mode;
    if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
        verity_mode = "enforcing";  // Defaults to enforcing when it's absent.
    }

    // Converts veritymode to the format used in kernel.
    std::string dm_verity_mode;
    if (verity_mode == "enforcing") {
        dm_verity_mode = "restart_on_corruption";
    } else if (verity_mode == "logging") {
        dm_verity_mode = "ignore_corruption";
    } else if (verity_mode != "eio") {  // Default dm_verity_mode is eio.
        LERROR << "Unknown androidboot.veritymode: " << verity_mode;
        return false;
    }

    std::ostringstream hash_algorithm;
    hash_algorithm << hashtree_desc.hash_algorithm;

    android::dm::DmTargetVerity target(0, hashtree_desc.image_size / 512,
                                       hashtree_desc.dm_verity_version, blk_device, blk_device,
                                       hashtree_desc.data_block_size, hashtree_desc.hash_block_size,
                                       hashtree_desc.image_size / hashtree_desc.data_block_size,
                                       hashtree_desc.tree_offset / hashtree_desc.hash_block_size,
                                       hash_algorithm.str(), root_digest, salt);
    if (hashtree_desc.fec_size > 0) {
        target.UseFec(blk_device, hashtree_desc.fec_num_roots,
                      hashtree_desc.fec_offset / hashtree_desc.data_block_size,
                      hashtree_desc.fec_offset / hashtree_desc.data_block_size);
    }
    if (!dm_verity_mode.empty()) {
        target.SetVerityMode(dm_verity_mode);
    }
    // Always use ignore_zero_blocks.
    target.IgnoreZeroBlocks();

    LINFO << "Built verity table: '" << target.GetParameterString() << "'";

    return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
}

bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc,
                           const std::string& salt, const std::string& root_digest,
                           bool wait_for_verity_dev) {
    android::dm::DmTable table;
    if (!ConstructVerityTable(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) ||
        !table.valid()) {
        LERROR << "Failed to construct verity table.";
        return false;
    }
    table.set_readonly(true);

    const std::string mount_point(basename(fstab_entry->mount_point.c_str()));
    android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
    if (!dm.CreateDevice(mount_point, table)) {
        LERROR << "Couldn't create verity device!";
        return false;
    }

    std::string dev_path;
    if (!dm.GetDmDevicePathByName(mount_point, &dev_path)) {
        LERROR << "Couldn't get verity device path!";
        return false;
    }

    // Marks the underlying block device as read-only.
    SetBlockDeviceReadOnly(fstab_entry->blk_device);

    // Updates fstab_rec->blk_device to verity device name.
    fstab_entry->blk_device = dev_path;

    // Makes sure we've set everything up properly.
    if (wait_for_verity_dev && !WaitForFile(dev_path, 1s)) {
        return false;
    }

    return true;
}

bool GetHashtreeDescriptor(const std::string& partition_name,
                           const std::vector<VBMetaData>& vbmeta_images,
                           AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt,
                           std::string* out_digest) {
    bool found = false;
    const uint8_t* desc_partition_name;

    for (size_t i = 0; i < vbmeta_images.size() && !found; i++) {
        // Get descriptors from vbmeta_images[i].
        size_t num_descriptors;
        std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
                avb_descriptor_get_all(vbmeta_images[i].data(), vbmeta_images[i].size(),
                                       &num_descriptors),
                avb_free);

        if (!descriptors || num_descriptors < 1) {
            continue;
        }

        for (size_t j = 0; j < num_descriptors && !found; j++) {
            AvbDescriptor desc;
            if (!avb_descriptor_validate_and_byteswap(descriptors[j], &desc)) {
                LWARNING << "Descriptor[" << j << "] is invalid";
                continue;
            }
            if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
                desc_partition_name =
                        (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
                if (!avb_hashtree_descriptor_validate_and_byteswap(
                            (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
                    continue;
                }
                if (out_hashtree_desc->partition_name_len != partition_name.length()) {
                    continue;
                }
                // Notes that desc_partition_name is not NUL-terminated.
                std::string hashtree_partition_name((const char*)desc_partition_name,
                                                    out_hashtree_desc->partition_name_len);
                if (hashtree_partition_name == partition_name) {
                    found = true;
                }
            }
        }
    }

    if (!found) {
        LERROR << "Partition descriptor not found: " << partition_name.c_str();
        return false;
    }

    const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len;
    *out_salt = BytesToHex(desc_salt, out_hashtree_desc->salt_len);

    const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len;
    *out_digest = BytesToHex(desc_digest, out_hashtree_desc->root_digest_len);

    return true;
}

}  // namespace fs_mgr
}  // namespace android
+45 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#pragma once

#include <string>
#include <vector>

#include <libavb/libavb.h>
#include <libdm/dm.h>

#include "fs_avb/fs_avb.h"

namespace android {
namespace fs_mgr {

// AvbHashtreeDescriptor to dm-verity table setup.
bool GetHashtreeDescriptor(const std::string& partition_name,
                           const std::vector<VBMetaData>& vbmeta_images,
                           AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt,
                           std::string* out_digest);

bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
                          const std::string& root_digest, const std::string& blk_device,
                          android::dm::DmTable* table);

bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const AvbHashtreeDescriptor& hashtree_desc,
                           const std::string& salt, const std::string& root_digest,
                           bool wait_for_verity_dev);

}  // namespace fs_mgr
}  // namespace android
Loading