android AVB2.0(五)Device Mapper和Dm verity详解

一、Device Mapper

1. Device Mapper概述

Device mapper是LINUX提供的一种逻辑设备到物理设备的映射框架,中间传递消息的是用户自定义的target driver插件,用户可以编写好具体的IO请求的target driver就行,用户层可以使用ioctl命令的方式向底层进行通讯。
target driver主要定义对IO请求的处理规则,在device mapper中对target driver的操作已定义好了统一的接口,可实现几个常见的方法就行。同时device mapper提供了一种底层消息上报的机制,通过target driver将事件消息传递到用户空间。

在android的init启动的第一阶段中主要调用了InitDeviceMapper函数,来进行device mapper的初始化

原创不易,转载请注明出处 https://blog.csdn.net/jackone12347/article/details/122115691

2. Device Mapper的使用

在android的init启动的第一阶段中主要调用了InitDeviceMapper函数,来进行device mapper的初始化。
分析一下代码@block_dev_initializer.cpp

bool FirstStageMount::InitRequiredDevices(std::set<std::string> devices) {
    if (!block_dev_init_.InitDeviceMapper()) {
        return false;
    }
    if (devices.empty()) {
        return true;
    }
    return block_dev_init_.InitDevices(std::move(devices));
}


bool BlockDevInitializer::InitDeviceMapper() {
    const std::string dm_path = "/devices/virtual/misc/device-mapper";
    bool found = false;
    auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) {
        if (uevent.path == dm_path) {
            device_handler_->HandleUevent(uevent);
            found = true;
            return ListenerAction::kStop;
        }
        return ListenerAction::kContinue;
    };
    uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback);
    if (!found) {
        Timer t;
        uevent_listener_.Poll(dm_callback, 10s);
    }
    if (!found) {
         return false;
    }
    return true;
}

调用InitDmDevice函数初始化Device mapper 设备。通过代码分析来看,直观的功能是通过uevent上报的节点,在其中去查找dtsi中配置的各个分区;

如果找到了就从device集合中删除,添加个10秒的等待,如果10秒内都找不到这个分区,说明此分区可能没有挂载到文件系统,或者配置出错。

bool BlockDevInitializer::InitDmDevice(const std::string& device) {
auto uevent_callback = [&device_name, &device, this, &found](const Uevent& uevent) {
        if (uevent.device_name == device_name) {
device_handler_->HandleUevent(uevent);
            found = true;
            return ListenerAction::kStop;
        }
        return ListenerAction::kContinue;
    };
uevent_listener_.RegenerateUeventsForPath(syspath, uevent_callback);
    if (!found) {
Timer t;
        uevent_listener_.Poll(uevent_callback, 10s);
    }return true;
}

ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent,
                                                 std::set<std::string>* devices) {
    auto name = uevent.partition_name;
    if (name.empty()) {
        size_t base_idx = uevent.path.rfind('/');
        if (base_idx == std::string::npos) {
            return ListenerAction::kContinue;
        }
        name = uevent.path.substr(base_idx + 1);
    }
    auto iter = devices->find(name);
    if (iter == devices->end()) {
        return ListenerAction::kContinue;
    }
    devices->erase(iter);
    device_handler_->HandleUevent(uevent);
    return devices->empty() ? ListenerAction::kStop :     ListenerAction::kContinue;
}

二、Dm Verity

1. Dm Verity验证思想

上层应用通过文件系统读取某个block时,调用dm-verity读取对应的block,
dm-verity会根据verity-table调用block_device读取对应的block,然后逐层计算到根block,
计算得到root-hash和kernel中保存的root hash进行对比,hash值进行比较,如果相等,则说明该块没有被修改过,一切正常。

2. Hashtree脚本处理

2.1 镜像编译

编译system.img时调用了build_image.py脚本

define build-systemimage-target
  @echo "Target system fs image: $(1)"
  $(call generate-userimage-prop-dictionary,   $(systemimage_intermediates)/system_image_info.txt, \
      skip_fsck=true)
  $(hide) PATH=$(foreach p,$(INTERNAL_USERIMAGES_BINARY_PATHS),$(p):)$$PATH \
      build/make/tools/releasetools/build_image.py \
      $(TARGET_OUT) $(systemimage_intermediates)/system_image_info.txt $(1) $(TARGET_OUT) \

2.2 创建verity tree

/build/tools/releasetools/build_image.py中,调用build_verity_tree程序

def BuildImage(in_dir, prop_dict, out_file, target_out=None):
if verity_supported and is_verity_partition:
    if not MakeVerityEnabledImage(out_file, verity_fec_supported, prop_dict):
      return False
 
def MakeVerityEnabledImage(out_file, fec_supported, prop_dict):
   # build the verity tree and get the root hash and salt
  if not BuildVerityTree(out_file, verity_image_path, prop_dict):
    return False
 def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict):
  cmd = ["build_verity_tree", "-A", FIXED_SALT, sparse_image_path,
         verity_image_path]
  output, exit_code = RunCommand(cmd)
  if exit_code != 0:
    print("Could not build verity tree! Error: %s" % output)
    return False
  root, salt = output.split()
  prop_dict["verity_root_hash"] = root
  prop_dict["verity_salt"] = salt
  return True

调用到system\extras\verity\build_verity_tree.cpp,
过程包括:
根据block_size大小和hash_size大小,计算得到一个block可以存放的hash个数从level 0开始,计算需要多少个level;
创建数组verity_tree_levels, 用于指示每一个level在verity_tree中的起始地址;
创建数组verity_tree_level_blocks, 用于指示每一个level在verity_tree中的长度;
计算ext4 image中各个块的hash值存到verity_tree的level0,然后逐层往上计算各层的hash值,并填入verity_tree中相应的level。
在这里插入图片描述

2.3 创建metadata

def build_verity_metadata(data_blocks, metadata_image, root_hash, salt,
        block_device, signer_path, signing_key, signer_args=None,
        verity_disable=False):
    # build the verity table
    verity_table = build_verity_table(block_device, data_blocks, root_hash, salt)
    # build the verity table signature
    signature = sign_verity_table(verity_table, signer_path, signing_key, signer_args)
    # build the metadata block
    metadata_block = build_metadata_block(verity_table, signature, verity_disable)
    # write it to the outfile
    with open(metadata_image, "wb") as f:
        f.write(metadata_block)

build_verity_table函数中,第一个参数block_device描述了dm-verity设备对应了那个底层的block,第二个参数block_device指定了hash-tree存在于哪个block设备上,
BLOCK_SIZE参数为默认的4k, data_blocks描述了有多少个block,data_blocks + (METADATA_SIZE / BLOCK_SIZE)表示hash-tree在对应block设备上的偏移位置,
最后可找到hash-tree,root_hash为hash-tree的根hash。
另外,verity table是存在分区中的super block(超级块)之后的位置,便于找到校验的位置。

def build_verity_table(block_device, data_blocks, root_hash, salt):
    table = "1 %s %s %s %s %s %s sha256 %s %s"
    table %= (  block_device,
                block_device,
                BLOCK_SIZE,
                BLOCK_SIZE,
                data_blocks,
                data_blocks,
                root_hash,
                salt)
    return table

3. Dm verity设备的创建

3.1 SetUpDmVerity函数

调用的入口在Init的第一阶段的SetUpDmVerity函数。

Fstab::iterator end;
if (!MountPartition(current, false /* erase_same_mounts */, &end)) {}
 
bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end) {if (!SetUpDmVerity(&(*begin))) {
        PLOG(ERROR) << "Failed to setup verity for '" << begin->mount_point << "'";
        return false;
    }
}
else if (fstab_entry->fs_mgr_flags.avb) {
        //InitAvbHandle完成此分区的AVB验证
        if (!InitAvbHandle()) return false;
 
#然后执行创建hash tree table并建立与driver侧的ioctl交互连接。
        hashtree_result =
                avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);

相关代码在:system\core\fs_mgr\libfs_avb\ avb_util.cpp

bool HashtreeDmVeritySetup(FstabEntry* fstab_entry, const 	    	FsAvbHashtreeDescriptor& hashtree_desc,
                           bool wait_for_verity_dev) {
    android::dm::DmTable table;
    if (!ConstructVerityTable(hashtree_desc, fstab_entry->blk_device, &table) || !table.valid()) {
        LERROR << "Failed to construct verity table.";
        return false;
    }
    table.set_readonly(true);if (!dm.CreateDevice(device_name, table, &dev_path, timeout)) {
        LERROR << "Couldn't create verity device!";
        return false;
    }

3.2 hash table处理

Hash table传入的格式如下,中间做了序列号处理,其实就是一串长值拼成的字串。
调用的入口在Init的第一阶段的SetUpDmVerity函数。

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(),
            hashtree_desc.root_digest, hashtree_desc.salt);

CreateDevice函数里面有三个函数,分别实现了上述的几个ioctl命令,把拼接好的hashtable传到驱动侧。

bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
                                const std::chrono::milliseconds& timeout_ms) {
    std::string uuid = GenerateUuid();
    if (!CreateDevice(name, uuid)) {
        return false;
    }
    std::string unique_path;
    if (!LoadTableAndActivate(name, table)    || !GetDeviceUniquePath(name, &unique_path) ||
        !GetDmDevicePathByName(name, path)) {
        DeleteDevice(name);
        return false;
    }

对应的IOCTL命令

ioctl(fd_, DM_DEV_CREATE, &io)
ioctl(fd_, DM_TABLE_LOAD, io)
ioctl(fd_, DM_DEV_SUSPEND, io)

好了,以上就是Device Mapper和Dm verity的简介了,实际上的内容会更多,大家学习的过程中多多发现吧。

为方便与大家及时交流,弄了一个微信公众号,欢迎大家留言沟通~
在这里插入图片描述

### 回答1: Android AVB (Android Verified Boot) 是安卓系统中的一种安全功能,目的是确保用户设备上的操作系统和应用程序未被篡改。它使用了基于密钥的验证方法,以验证设备上的固件和启动程序的完整性和可靠性。 Android AVB的工作原理是,在设备启动时,固件和启动程序会被验证。首先,设备会检查固件和启动程序的数字签名,以确保它们是由受信任的开发者签名的。如果签名验证通过,则设备会继续启动,否则会发出警告或者拒绝启动。 除了验证签名外,Android AVB还会检查系统分区的哈希值是否与预期的哈希值匹配。这些哈希值是在设备正常运行时生成的,并被记录在一个被称为AVB表的数据结构中。如果发现系统分区的哈希值与预期的哈希值不匹配,设备将中断启动并显示一条警告信息。 通过使用Android AVB,设备能够有效防止来自未经授权的来源的操作系统和启动程序的篡改。这增加了设备的安全性,使用户能够放心使用设备,而不担心潜在的恶意软件或未经授权的更改。 总之,Android AVB是安卓系统中的一种安全功能,它通过验证数字签名和哈希值来确保设备上的操作系统和启动程序的完整性。它帮助防止未经授权的篡改,提高了设备的安全性。 ### 回答2: Android AVBAndroid Verified Boot)是安卓系统中的一种验证引导机制,它通过在设备启动过程中验证系统的完整性,防止未经授权的修改及恶意软件损害系统安全。以下是关于Android AVB的一些要点。 首先,Android AVB使用数字签名验证系统引导映像的完整性。在设备启动时,引导加载程序(Bootloader)会验证引导映像的签名,只有通过数字证书签名的映像才能被加载,这样可以确保系统引导过程没有受到非法篡改。 其次,Android AVB启用分区级别的验证,每个分区的映像都需要通过数字签名进行验证。这使得系统分区、供应商分区和OEM分区等可以被独立验证,并且可以防止未经授权修改。 另外,Android AVB还使用了完整性元数据(Integrity Metadata)来确保系统分区的数据安全。完整性元数据存储了每个分区的哈希值和签名信息,设备启动时会加载并验证这些元数据,以确保分区的数据没有被篡改。 最后,Android AVB还可以在设备上使用强制加密(Force Encryption)来确保用户数据的密钥只能被正确验证的引导映像解锁。这可以防止未经授权的访问或修改用户数据。 总的来说,Android AVB通过数字签名、分区级别的验证以及完整性元数据等机制,确保了安卓设备系统引导过程的完整性和安全性,并且防止了未经授权的修改和恶意软件的攻击。 ### 回答3: Android AVB是指Android Verified Boot的缩写,是一种用于验证和保护Android设备的引导过程的安全机制。它的目标是检测和阻止未经授权的软件从设备的启动过程中加载和运行。 Android Verified Boot通过使用数字签名和哈希算法来验证引导镜像的完整性和真实性。在设备启动的过程中,它会使用设备制造商预装的公钥来验证引导镜像的数字签名是否有效,并且只有当验证通过时才会加载和运行系统。这样可以防止未经授权的软件或者恶意代码被插入到引导过程中,提高了设备的安全性。 此外,Android AVB还可以更容易地检测到设备的Root状态和未经授权的修改。通过保护系统分区和检测分区是否已被修改,它可以提供更可靠的保护机制,防止未经授权的软件或者恶意代码对设备进行篡改。这可以帮助用户避免安全漏洞和数据泄露。 总之,Android AVB是一种用于验证和保护设备启动过程的安全机制,通过验证引导镜像的完整性和真实性,检测设备的Root状态和分区是否被修改,提高了Android设备的安全性。这有助于保护用户的个人数据和设备免受恶意软件和未经授权的修改的威胁。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值