AVB源码学习(四):AVB2.0-libavb库介绍1

简介: AVB源码学习(四):AVB2.0-libavb库介绍1


前言

首先要介绍一下本篇文章的两个目标,带着这两个目标我们来分析一下libavb库的实现。

  • 1、android AVB是如何完成 verify校验这项任务的?
  • 2、采用了什么样的设计来完成verify校验任务?

上篇内容之一:“InitAvbHandle:AVB调用exterlan/avb/libavb库完成分区的校验”

源码

没有源码的,可以看google提供的路径:

https://android.googlesource.com/platform/system/core/+/master/init/first_stage_mount.cpp

1、bool FirstStageMountVBootV2::InitAvbHandle()

@first_stage_mount.cpp
bool FirstStageMountVBootV2::InitAvbHandle() {
    if (avb_handle_) return true;  // Returns true if the handle is already initialized.
    avb_handle_ = AvbHandle::Open();
    if (!avb_handle_) {
        PLOG(ERROR) << "Failed to open AvbHandle";
        return false;
    }
    // Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
    setenv("INIT_AVB_VERSION", avb_handle_->avb_version().c_str(), 1);
    return true;
}

2、AvbUniquePtr AvbHandle::Open()

实现在fs_avb.cpp

AvbUniquePtr AvbHandle::Open() {
//判断设备是否lock,这里是通过读系统属性ro.boot.verifiedbootstate来判断的,这个后面我专门搞篇文章来讲一下。
    bool allow_verification_error = IsAvbPermissive();
//创建AvbHandle实例
    AvbUniquePtr avb_handle(new AvbHandle());
    if (!avb_handle) {
        LERROR << "Failed to allocate AvbHandle";
        return nullptr;
    }
     //实例化AvbOps管理类对象,私有成员中有AvbOps avb_ops_
    FsManagerAvbOps avb_ops;
    AvbSlotVerifyFlags flags = allow_verification_error
                                       ? AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
                                       : AVB_SLOT_VERIFY_FLAGS_NONE;
     //调用AvbSlotVerify函数进行verify校验
    AvbSlotVerifyResult verify_result =
            avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->vbmeta_images_);
     ...
   //后面verify之后的结果代码也比较简单就不分析了,我们重点分析校验流程

3、 avb_ops.AvbSlotVerify

AvbSlotVerify实现在avb_ops.cpp中的avb_slot_verify函数,注意这里requested_partitions默认为空,不管是Uboot中调用libavb库,还是android init中调用libavb库,都是类似的处理逻辑。

AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
                                                   AvbSlotVerifyFlags flags,
                                                   std::vector<VBMetaData>* out_vbmeta_images) {
    const char* requested_partitions[] = {nullptr};
    // Local resource to store vbmeta images from avb_slot_verify();
    AvbSlotVerifyData* avb_slot_data;
    // The |hashtree_error_mode| field doesn't matter as it only
    // influences the generated kernel cmdline parameters.
    auto verify_result =
            avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
                            AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &avb_slot_data);
    if (!avb_slot_data) return verify_result;

进入avb校验

1、入口avb_slot_verify.c

avb_slot_verify函数流程会非常的长,对这个代码不熟悉的人估计会晕在里面,会有函数嵌套调用。我们分段进行说明:

第一个参数ops,是一个函数结构体对象指针

FsManagerAvbOps::FsManagerAvbOps() {
//初始化avb_ops_成员的对象,主要有这六个回调函数,这些google设计的非常巧妙,用户将来可自定义各家的实现方式,google不做限制,只保留空的回调接口,在avb验证流程中会触发,后面代码分析流程中会做介绍。
    memset(&avb_ops_, 0, sizeof(AvbOps));
    avb_ops_.read_from_partition = read_from_partition;
    avb_ops_.read_rollback_index = dummy_read_rollback_index;
    avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
    avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked;
    avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
    avb_ops_.get_size_of_partition = dummy_get_size_of_partition;
    // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
    avb_ops_.user_data = this;
}

我们进入到avb_slot_verify函数中分析

AvbSlotVerifyResult avb_slot_verify(AvbOps* ops,
                                    const char* const* requested_partitions,
                                    const char* ab_suffix,
                                    AvbSlotVerifyFlags flags,
                                    AvbHashtreeErrorMode hashtree_error_mode,
                                    AvbSlotVerifyData** out_data) {
  AvbSlotVerifyResult ret;
  AvbSlotVerifyData* slot_data = NULL;
  AvbAlgorithmType algorithm_type = AVB_ALGORITHM_TYPE_NONE;
  bool using_boot_for_vbmeta = false;
  AvbVBMetaImageHeader toplevel_vbmeta;
  bool allow_verification_error =
      (flags & AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR);
  AvbCmdlineSubstList* additional_cmdline_subst = NULL;
  /* Fail early if we're missing the AvbOps needed for slot verification. */
  //先判断下面五个基本的回调函数接口是否存在,不存在会报错,即使不实现也需要实现个空内容。
  avb_assert(ops->read_is_device_unlocked != NULL);
  avb_assert(ops->read_from_partition != NULL);
  avb_assert(ops->get_size_of_partition != NULL);
  avb_assert(ops->read_rollback_index != NULL);
  avb_assert(ops->get_unique_guid_for_partition != NULL);
。。。
  //判断是否没有vbmeta分区,默认是有vbmeta分区设计的,但是也可以append到其他分区上 这种我们先不考虑
  if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
    if (ops->validate_public_key_for_partition == NULL) {
      avb_error(
          "AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION was passed but the "
          "validate_public_key_for_partition() operation isn't implemented.\n");
      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_ARGUMENT;
      goto fail;
    }
  } else {
  //默认我们是使用这种方式,需要校验vbmeta分区的public key接口是否存在,这个接口用来判断vbmeta公钥hash key是否匹配。
    avb_assert(ops->validate_vbmeta_public_key != NULL);
  }
  //alloc分配内存
  slot_data = avb_calloc(sizeof(AvbSlotVerifyData));
  if (slot_data == NULL) {
    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
    goto fail;
  }
  slot_data->vbmeta_images =
      avb_calloc(sizeof(AvbVBMetaData) * MAX_NUMBER_OF_VBMETA_IMAGES);
  if (slot_data->vbmeta_images == NULL) {
    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
    goto fail;
  }
  slot_data->loaded_partitions =
      avb_calloc(sizeof(AvbPartitionData) * MAX_NUMBER_OF_LOADED_PARTITIONS);
  if (slot_data->loaded_partitions == NULL) {
    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
    goto fail;
  }
  //给additional_cmdline_subst也alloc分配内存,这个是后面需要将avb校验的结果转成数据append到cmdline中,传递给init使用的。
  additional_cmdline_subst = avb_new_cmdline_subst_list();
  if (additional_cmdline_subst == NULL) {
    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
    goto fail;
  }
if (flags & AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION) {
   ...
   //同上,我们不分析没有vbmeta分区的情况
  } else {
    //加载和校验vbmeta分区,这个函数流程非常长,我们等会分析,先看完后续的流程
    ret = load_and_verify_vbmeta(ops,
                                 requested_partitions,
                                 ab_suffix,
                                 flags,
                                 allow_verification_error,
                                 0 /* toplevel_vbmeta_flags */,
                                 0 /* rollback_index_location */,
                                 "vbmeta",
                                 avb_strlen("vbmeta"),
                                 NULL /* expected_public_key */,
                                 0 /* expected_public_key_length */,
                                 slot_data,
                                 &algorithm_type,
                                 additional_cmdline_subst);
     //在设备lock的情况且校验失败,直接异常                      
    if (!allow_verification_error && ret != AVB_SLOT_VERIFY_RESULT_OK) {
      goto fail;
    }
  }
  //根据校验结果判断是否可继续引导启动
    if (!result_should_continue(ret)) {
    goto fail;
  }
  //将校验的结果数据slot_data拷贝给toplevel_vbemta,避免修改原数据。
  avb_vbmeta_image_header_to_host_byte_order(
      (const AvbVBMetaImageHeader*)slot_data->vbmeta_images[0].vbmeta_data,
      &toplevel_vbmeta);
//根据toplevel_vbmeta vbmete头信息中flags bit位是否为disable verification,
//这个就是传说中的adb disable-verity修改的那个Bit位了,估计很多人都不知道adb这条命令干了啥,其实就是修改了vbmeta分区Header头信息中的这个bit位
if (toplevel_vbmeta.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
    /* Since verification is disabled we didn't process any
     * descriptors and thus there's no cmdline... so set root= such
     * that the system partition is mounted.
     */
    avb_assert(slot_data->cmdline == NULL);
    // Devices with dynamic partitions won't have system partition.
    // Instead, it has a large super partition to accommodate *.img files.
    // See b/119551429 for details.
    if (has_system_partition(ops, ab_suffix)) {
      slot_data->cmdline =
          avb_strdup("root=PARTUUID=$(ANDROID_SYSTEM_PARTUUID)");
    } else {
      // The |cmdline| field should be a NUL-terminated string.
      slot_data->cmdline = avb_strdup("");
    }
    if (slot_data->cmdline == NULL) {
      ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
      goto fail;
    }
  } else {
   /* If requested, manage dm-verity mode... */
   //这里是不是很奇怪,怎么又判断了hashtree了?其实是google设计的函数共用的功能,这个函数也可以用来校验其他Hashtree类型的分区,比如system和vendor等
    AvbHashtreeErrorMode resolved_hashtree_error_mode = hashtree_error_mode;
    if (hashtree_error_mode ==
        AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO) {
      AvbIOResult io_ret;
      io_ret = avb_manage_hashtree_error_mode(
          ops, flags, slot_data, &resolved_hashtree_error_mode);
      if (io_ret != AVB_IO_RESULT_OK) {
        ret = AVB_SLOT_VERIFY_RESULT_ERROR_IO;
        if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
          ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
        }
        goto fail;
      }
    //调用avb_append_options追加androidboot.xxx属性到cmdline中,这个比较简单就不深入分析了。
    sub_ret = avb_append_options(ops,
                                 flags,
                                 slot_data,
                                 &toplevel_vbmeta,
                                 algorithm_type,
                                 hashtree_error_mode,
                                 resolved_hashtree_error_mode);
      if (slot_data->cmdline != NULL && avb_strlen(slot_data->cmdline) != 0) {
    char* new_cmdline;
    new_cmdline = avb_sub_cmdline(ops,
                                  slot_data->cmdline,
                                  ab_suffix,
                                  using_boot_for_vbmeta,
                                  additional_cmdline_subst);
    if (new_cmdline != slot_data->cmdline) {
      if (new_cmdline == NULL) {
        ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
        goto fail;
      }
      avb_free(slot_data->cmdline);
      slot_data->cmdline = new_cmdline;
    }
  }
  if (out_data != NULL) {
    *out_data = slot_data;
  } else {
    avb_slot_verify_data_free(slot_data);
  }

2、load_and_verify_vbmeta

我们回到load_and_verify_vbmeta这个函数,看下如何加载和校验vbmeta分区及vbmeta下的子分区的

static AvbSlotVerifyResult load_and_verify_vbmeta(
    AvbOps* ops,
    const char* const* requested_partitions,
    const char* ab_suffix,
    AvbSlotVerifyFlags flags,
    bool allow_verification_error,
    AvbVBMetaImageFlags toplevel_vbmeta_flags,
    int rollback_index_location,
    const char* partition_name,
    size_t partition_name_len,
    const uint8_t* expected_public_key,
    size_t expected_public_key_length,
    AvbSlotVerifyData* slot_data,
    AvbAlgorithmType* out_algorithm_type,
    AvbCmdlineSubstList* out_additional_cmdline_subst) {
...
  //在分析load_and_verify_vbmeta前,我们先看一下AvbVBMetaImageHeader结构体
  AvbVBMetaImageHeader vbmeta_header;

不分析AvbVBMetaImageHeader 结构体,估计很难明白这个函数是在校验啥东东。

//能看到AvbVBMetaImageHeader头信息中主要由三部分组成
Header data: vbmeta的header数据,固定长度256字节。
Authentication data:认证校验数据,长度不固定,主要包含签名和公钥等信息。
Auxiliary data:辅助数据,主要包含vbmeta中其他分区的descriptor描述信息。
 *  +-----------------------------------------+
 *  | Header data - fixed size                |
 *  +-----------------------------------------+
 *  | Authentication data - variable size     |
 *  +-----------------------------------------+
 *  | Auxiliary data - variable size          |
 *  +-----------------------------------------+
 //每一项参数,代码中都有进行说明
typedef struct AvbVBMetaImageHeader {
   魔术AVB0占四个字节
  /*   0: Four bytes equal to "AVB0" (AVB_MAGIC). */
  uint8_t magic[AVB_MAGIC_LEN];
   AVB的版本号信息1.0.0
  /*   4: The major version of libavb required for this header. */
  uint32_t required_libavb_version_major;
  /*   8: The minor version of libavb required for this header. */
  uint32_t required_libavb_version_minor;
  签名信息长度和辅助信息长度
  /*  12: The size of the signature block. */
  uint64_t authentication_data_block_size;
  /*  20: The size of the auxiliary data block. */
  uint64_t auxiliary_data_block_size;
  使用的签名算法类型
  /*  28: The verification algorithm used, see |AvbAlgorithmType| enum. */
  uint32_t algorithm_type;
  签名数据的在header中的Body的Hash偏移位置
  /*  32: Offset into the "Authentication data" block of hash data. */
  uint64_t hash_offset;
  数据Body的Hash大小
  /*  40: Length of the hash data. */
  uint64_t hash_size;
  签名数据的偏移位置
  /*  48: Offset into the "Authentication data" block of signature data. */
  uint64_t signature_offset;
  签名数据的大小
  /*  56: Length of the signature data. */
  uint64_t signature_size;
  公钥的偏移位置
  /*  64: Offset into the "Auxiliary data" block of public key data. */
  uint64_t public_key_offset;
  公钥的长度
  /*  72: Length of the public key data. */
  uint64_t public_key_size;
  公钥metadata的偏移位置和长度
  /*  80: Offset into the "Auxiliary data" block of public key metadata. */
  uint64_t public_key_metadata_offset;
  /*  88: Length of the public key metadata. Must be set to zero if there
   *  is no public key metadata.
   */
  uint64_t public_key_metadata_size;
  子分区的descriptor描述信息的偏移位置和长度
  /*  96: Offset into the "Auxiliary data" block of descriptor data. */
  uint64_t descriptors_offset;
  /* 104: Length of descriptor data. */
  uint64_t descriptors_size;
  vbmeta的rollback回滚值
  /* 112: The rollback index which can be used to prevent rollback to
   *  older versions.
   */
  uint64_t rollback_index;
  vbmeta的flags标志位,是否disable-verification等
  /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be
   * set to zero if the vbmeta image is not a top-level image.
   */
  uint32_t flags;
  预留的字节,为将来可扩展准备
  /* 124: Reserved to ensure |release_string| start on a 16-byte
   * boundary. Must be set to zeroes.
   */
  uint8_t reserved0[4];
  /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
   * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
   * terminated. Applications must not make assumptions about how this
   * string is formatted.
   */
  uint8_t release_string[AVB_RELEASE_STRING_SIZE];
  /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
   * bytes. This must be set to zeroes.
   */
  uint8_t reserved[80];
} AVB_ATTR_PACKED AvbVBMetaImageHeader;

好了,知道vbmeta头结构体后,我们继续分析load_and_verify_vbmeta代码

//alloc申请内存
  vbmeta_buf = avb_malloc(vbmeta_size);
  if (vbmeta_buf == NULL) {
    ret = AVB_SLOT_VERIFY_RESULT_ERROR_OOM;
    goto out;
  }
  //触发avb_ops.cpp中第一个回调函数,本文的下面段落中有说明
  //android侧只实现了这一个回调函数,其余的都留给厂商自己实现了,在UBOOT中就可以开发定制了。
  io_ret = ops->read_from_partition(ops,
                                    full_partition_name,
                                    vbmeta_offset,
                                    vbmeta_size,
                                    vbmeta_buf,
                                    &vbmeta_num_read);
   //加载完vbmeta数据后,需要对vbmeta数据进行校验,调用avb_vbmeta_image_verify函数
   //本文下面专门讲,这里先分析后续的流程
   vbmeta_ret =
      avb_vbmeta_image_verify(vbmeta_buf, vbmeta_num_read, &pk_data, &pk_len);
  //vbmeta基础数据verify通过后,校验一下公钥hash是否匹配,是否本次andorid源码编译产生的key
  //这个数据是在android编译的时候产生的,
  //validate_vbmeta_public_key是第二个回调函数,厂家可自定义实现,比如把key存储中其他地方
  //android默认为空,直接返回
      avb_assert(is_main_vbmeta);
      io_ret = ops->validate_vbmeta_public_key(ops,
                                                 pk_data,
                                                 pk_len,
                                                 pk_metadata,
                                                 pk_metadata_len,
                                                 &key_is_trusted);
   //紧接着会校验vbmeta的rollback回滚值,android默认为空,直接返回
   //这是第三个回调函数
  io_ret = ops->read_rollback_index(
      ops, rollback_index_location_to_use, &stored_rollback_index);
  //同时下面代码还有rollback_index回滚值的比较判断,主要是比较存储中的index值和vbmeta中的index值
  //更新策略为:当vbmeta中的index大于存储中的值,将存储中的值更新到存储空间;
  //如果vbmeta中的index小于存储中的值,启动boot失败,防止用户降级版本。
  //android默认为空实现,默认index为0,不需要更新写入。
  //加载vbmeta中descrptor其他分区的信息,比如vbmeta_system/boot/vendor_boot等分区的信息
  descriptors =
      avb_descriptor_get_all(vbmeta_buf, vbmeta_num_read, &num_descriptors);
  for (n = 0; n < num_descriptors; n++) {
    AvbDescriptor desc;
    if (!avb_descriptor_validate_and_byteswap(descriptors[n], &desc)) {
      avb_errorv(full_partition_name, ": Descriptor is invalid.\n", NULL);
      ret = AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA;
      goto out;
    }
//如果decriptor分区是hash类型,比如boot分区,调用load_and_verify_hash_partition计算hash并进行比较
    switch (desc.tag) {
      case AVB_DESCRIPTOR_TAG_HASH: {
        AvbSlotVerifyResult sub_ret;
        sub_ret = load_and_verify_hash_partition(ops,
                                                 requested_partitions,
                                                 ab_suffix,
                                                 allow_verification_error,
                                                 descriptors[n],
                                                 slot_data);
        if (sub_ret != AVB_SLOT_VERIFY_RESULT_OK) {
          ret = sub_ret;
          if (!allow_verification_error || !result_should_continue(ret)) {
            goto out;
          }
        }
      } break;
      case AVB_DESCRIPTOR_TAG_CHAIN_PARTITION: {
      case AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE: {
  //如果是hashtree类型,比如system分区,调用read_persistent_digest读此分区的digest信息
      case AVB_DESCRIPTOR_TAG_HASHTREE: {
        ret = read_persistent_digest(ops,
                                       part_name,
                                       digest_len,
                                       NULL /* initial_digest */,
                                       digest_buf);
   好了,这个函数到这里就基本上差不多了。

现在这个函数中,还有两个子函数还没有分析,

3、read_from_partition函数

其中ReadFromPartition的实现比较简单,找到vbmeta的dev节点名称,打开fd,调用read函数,将64KB的vbmeta数据全加载出来。

static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
                                       size_t num_bytes, void* buffer, size_t* out_num_read) {
    return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
            partition, offset, num_bytes, buffer, out_num_read);
}
AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
                                               size_t num_bytes, void* buffer,
                                               size_t* out_num_read) {
    std::string path = "/dev/block/by-name/"s + partition;
    // Ensures the device path (a symlink created by init) is ready to access.
    if (!WaitForFile(path, 1s)) {
        LERROR << "Device path not found: " << path;
        // Falls back to logical path if the physical path is not found.
        // This mostly only works for emulator (no bootloader). Because in normal
        // device, bootloader is unable to read logical partitions. So if libavb in
        // the bootloader failed to read a physical partition, it will failed to boot
        // the HLOS and we won't reach the code here.
        path = GetLogicalPath(partition);
        if (path.empty() || !WaitForFile(path, 1s)) return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
        LINFO << "Fallback to use logical device path: " << path;
    }
    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
    if (fd < 0) {
        PERROR << "Failed to open " << path;
        return AVB_IO_RESULT_ERROR_IO;
    }
    // If offset is negative, interprets its absolute value as the
    //  number of bytes from the end of the partition.
    if (offset < 0) {
        off64_t total_size = lseek64(fd, 0, SEEK_END);
        if (total_size == -1) {
            PERROR << "Failed to lseek64 to end of the partition";
            return AVB_IO_RESULT_ERROR_IO;
        }
        offset = total_size + offset;
        // Repositions the offset to the beginning.
        if (lseek64(fd, 0, SEEK_SET) == -1) {
            PERROR << "Failed to lseek64 to the beginning of the partition";
            return AVB_IO_RESULT_ERROR_IO;
        }
    }
    // On Linux, we never get partial reads from block devices (except
    // for EOF).
    ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
    if (num_read < 0 || (size_t)num_read != num_bytes) {
        PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset;
        return AVB_IO_RESULT_ERROR_IO;
    }
    if (out_num_read != nullptr) {
        *out_num_read = num_read;
    }
    return AVB_IO_RESULT_OK;
}

4、avb_vbmeta_image_verify函数

这个函数因为这里面涉及到RSA算法的验签流程,内容也很多,慢慢分析一下。

AvbVBMetaVerifyResult avb_vbmeta_image_verify(
    const uint8_t* data,
    size_t length,
    const uint8_t** out_public_key_data,
    size_t* out_public_key_length) {
    ...
    //首先判断是不是以“AVB0”开头的,vim打开vbmeta.img就可以看到是以AVB0开头
  /* Ensure magic is correct. */
  if (avb_safe_memcmp(data, AVB_MAGIC, AVB_MAGIC_LEN) != 0) {
    avb_error("Magic is incorrect.\n");
    goto out;
  }
  //把数据拷贝到到h AvbVBMetaImageHeader中
  avb_vbmeta_image_header_to_host_byte_order((const AvbVBMetaImageHeader*)data,
                                             &h);
  //比较avbtool的版本号 avbtool 1.10
  if ((h.required_libavb_version_major != AVB_VERSION_MAJOR) ||
      (h.required_libavb_version_minor > AVB_VERSION_MINOR)) {
    avb_error("Mismatch between image version and libavb version.\n");
    ret = AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION;
    goto out;
  }
//判断authentication和auxiliary数据大小是不是64字节的整数倍
  if ((h.authentication_data_block_size & 0x3f) != 0 ||
      (h.auxiliary_data_block_size & 0x3f) != 0) {
    avb_error("Block size is not a multiple of 64.\n");
    goto out;
  }
//判断hash和signature内容在vbmeta header中
  uint64_t hash_end;
  if (!avb_safe_add(&hash_end, h.hash_offset, h.hash_size) ||
      hash_end > h.authentication_data_block_size) {
    avb_error("Hash is not entirely in its block.\n");
    goto out;
  }
  uint64_t signature_end;
  if (!avb_safe_add(&signature_end, h.signature_offset, h.signature_size) ||
      signature_end > h.authentication_data_block_size) {
    avb_error("Signature is not entirely in its block.\n");
    goto out;
  }
//判断public key和public key metadata内容在vbmeta header中
  /* Ensure public key is entirely in the Auxiliary data block. */
  uint64_t pubkey_end;
  if (!avb_safe_add(&pubkey_end, h.public_key_offset, h.public_key_size) ||
      pubkey_end > h.auxiliary_data_block_size) {
    avb_error("Public key is not entirely in its block.\n");
    goto out;
  }
  /* Ensure public key metadata (if set) is entirely in the Auxiliary
   * data block. */
  if (h.public_key_metadata_size > 0) {
    uint64_t pubkey_md_end;
    if (!avb_safe_add(&pubkey_md_end,
                      h.public_key_metadata_offset,
                      h.public_key_metadata_size) ||
        pubkey_md_end > h.auxiliary_data_block_size) {
      avb_error("Public key metadata is not entirely in its block.\n");
      goto out;
    }
  }
//判断RSA algorithm的type和长度是不是符合
  if (h.algorithm_type == AVB_ALGORITHM_TYPE_NONE) {
    ret = AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED;
  avb_error("pis algoth type none AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED!\n");
    goto out;
  }
  /* Ensure algorithm field is supported. */
  algorithm = avb_get_algorithm_data(h.algorithm_type);
  if (!algorithm) {
    avb_error("Invalid or unknown algorithm.\n");
    goto out;
  }
  /* Bail if the embedded hash size doesn't match the chosen algorithm. */
  if (h.hash_size != algorithm->hash_len) {
    avb_error("Embedded hash has wrong size.\n");
    goto out;
  }
//到这里基本的检查项就完成了,接下来就是验证数据是不是匹配了
  header_block = data;
  authentication_block = header_block + sizeof(AvbVBMetaImageHeader);
  auxiliary_block = authentication_block + h.authentication_data_block_size;
//我们编译vbmeta应该是使用的SHA256_RSA4096,所以走下面这段逻辑
  switch (h.algorithm_type) {
    /* Explicit fall-through: */
    case AVB_ALGORITHM_TYPE_SHA256_RSA2048:
    case AVB_ALGORITHM_TYPE_SHA256_RSA4096:
    case AVB_ALGORITHM_TYPE_SHA256_RSA8192:
      avb_sha256_init(&sha256_ctx);
      avb_sha256_update(
          &sha256_ctx, header_block, sizeof(AvbVBMetaImageHeader));
      avb_sha256_update(
          &sha256_ctx, auxiliary_block, h.auxiliary_data_block_size);
      computed_hash = avb_sha256_final(&sha256_ctx);
      break;
    //验证hash是否相等
    if (avb_safe_memcmp(authentication_block + h.hash_offset,
                      computed_hash,
                      h.hash_size) != 0) {
    avb_error("Hash does not match!\n");
    ret = AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH;
    goto out;
  }
   //验证signature签名是否匹配
  verification_result =
      avb_rsa_verify(auxiliary_block + h.public_key_offset,
                     h.public_key_size,
                     authentication_block + h.signature_offset,
                     h.signature_size,
                     authentication_block + h.hash_offset,
                     h.hash_size,
                     algorithm->padding,
                     algorithm->padding_len);
}

我们单独开一篇好好分析一下。

目录
相关文章
|
6月前
|
安全 Linux Android开发
AVB源码学习(七):AVB2.0-Super动态分区介绍
AVB源码学习(七):AVB2.0-Super动态分区介绍
395 0
|
6月前
|
存储 安全 算法
AVB源码学习(一):AVB2.0工作原理及编译配置
AVB源码学习(一):AVB2.0工作原理及编译配置
802 0
|
6月前
|
安全 数据安全/隐私保护 Android开发
AVB源码学习(二):Uboot阶段AVB2.0校验流程
AVB源码学习(二):Uboot阶段AVB2.0校验流程
389 0
|
6月前
|
Linux Android开发
AVB源码学习(六):AVB2.0 Device Mapper和Dm verity详解
AVB源码学习(六):AVB2.0 Device Mapper和Dm verity详解
476 0
|
6月前
|
Android开发
Android源码学习(五):AVB2.0-libavb库介绍2
Android源码学习(五):AVB2.0-libavb库介绍2
292 0
|
6月前
|
安全 Android开发 C语言
一文搞懂AVB的使用
一文搞懂AVB的使用
308 0
|
6月前
|
安全 Android开发
AVB源码学习(三):AVB2.0 Init阶段安全启动流程
AVB源码学习(三):AVB2.0 Init阶段安全启动流程
332 0
|
6月前
|
存储 安全 Android开发
Android安全启动学习(三):AVB校验的内容、怎么校验、AVB的作用
Android安全启动学习(三):AVB校验的内容、怎么校验、AVB的作用
513 0
|
开发工具 git
编译Gstreamer遇到的问题 autopoint: not found
编译Gstreamer遇到的问题 autopoint: not found
143 0
|
Oracle Java 关系型数据库
华为云aarch64架构下载jdk;Linux上jdk无法执行二进制文件及​gzip: stdin: invalid compressed data–format violated​报错
华为云aarch64架构下载jdk;Linux上jdk无法执行二进制文件及​gzip: stdin: invalid compressed data–format violated​报错
571 0