avb校验相关与块校验原理

2023-11-11 00:20
文章标签 校验 原理 相关 avb

本文主要是介绍avb校验相关与块校验原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、启动校验流程

edk2/QcomModulePkg/Library/avb/VerifiedBoot.c
DEBUG ((EFI_D_ERROR, "LoadImageAndAuth failed %r\n", Status)); in LoadImageAndAuth()edk2/QcomModulePkg/Application/LinuxLoader/LinuxLoader.c
DEBUG ((EFI_D_ERROR, "LoadImageAndAuth failed: %r\n", Status));BootLib/PartitionTableUpdate.c
/QcomModulePkg/Library/avb/libavb/avb_slot_verify.c
LinuxLoaderEntryStatus = GetRebootReason (&BootReason);校验启动原因EnumeratePartitions()FindPtnActiveSlotUpdatePartitionEntries()   -----   加载avb分区LoadImageAndAuth      ---------------                  VerifiedBoot.c FindBootableSlot    --------------         PartitionTableUpdate.c//errorGetBootPartitionEntry HandleActiveSlotUnbootable          //一直返回错误GetBootPartitionEntry             // BootEntry       检测没过GetActiveSlot                     //successGetBootPartitionEntry    -----    for()LoadImageAndAuthVB2  ---------------           VerifiedBoot.c avb_should_update_rollbackIsCurrentSlotBootableavb_slot_verify    ------------------      avb_slot_verify.cload_and_verify_vbmetaops->read_from_partition(ops,  AvbReadFromPartition"Load Image %a total time: %lu ms \n"avb_vbmeta_image_verifyavb_rsa_verifyiavb_parse_key_data                 //Unexpected key lengthavb_manage_hashtree_error_modeavb_append_options   //avb 根据resolved_hashtree_error_mode 设置verity_modecmdline_append_option    //设置verity_mode到slot_data->cmdlineavb_sub_cmdlineHandleActiveSlotUnbootable                //当前槽置为unbootableAppendVBCmdLine      //cmdline赋值到VBCmdLineDisplayVerifiedBootScreenDisplayVerifiedBootMenuBootLinux (&Info);UpdateCmdLineAddtoBootConfigList   //gBS = SystemTable->BootServices;这里会利用uefi boot服务记录map

二、通用块设备层对请求的处理

2.1 块设备概述

在这里插入图片描述

在这里插入图片描述
• 块设备的控制器传输的固定数据单元大小称为扇区(sector)。因此I/O调度器
和块设备驱动必须以扇区为单位管理数据。
• 虚拟文件系统、映射层(mapping layer)管理磁盘数据的逻辑单元大小称为块
(block)。对于文件系统来说,块是最小的磁盘数据存储单元。
• 前面在分散/聚合DMA中,我们提到块设备驱动应该能够处理称为“段”的数据
单元;每个“段”是内存中的一页或页的一部分,“段”中的数据在磁盘上是
连续的。
• 磁盘缓冲区处理的数据单元大小为“页”,每个对应一个页帧。(注1)
• 通用块设备层粘合所有上层和底层的部分,这样它就知道扇区、块、段和数据
页。

在这里插入图片描述
bi_io_vecs指向一个bio_vec结构体数组,该结构体链表包含了一个特定I/O操作所需要
使用到的所有段(segment)。每个bio_vec结构都是一个形式为<page, offset, len>的向量,
它描述的是一个特定的段:段所在的物理页、块在物理页中的偏移量、从给定偏移量开始的
块长度。整个bio_io_vec结构体数组表示了一个完整的缓冲区。bio_vec结构体定义在文件
include/linux/bio.h中。

内核使用gendisk结构,定义在include/linux/genhd.h中,来表示一个独立的磁盘设备。
实际上内核还使用gendisk表示分区,但是驱动程序不需要了解这些。在gendisk结构中的许
多成员必须由驱动程序进行初始化。
物理磁盘通常被分成多个逻辑分区。每个块设备文件可以表示一个整个物理磁盘或者其
中的一个分区。如/dev/sda、/dev/sda1、/dev/sda2等。若一个物理磁盘有多个分区,则磁
盘的布局保存在hd_struct数据结构数组中,数组的地址由gendisk结构体中的part成员保存。
hd_struct数据结构的定义在文件include/linux/genhd.h中。
在这里插入图片描述
当内核在系统中发现一个新磁盘时,调用alloc_disk()分配相关数据结构,如gendisk,
hd_struct等,然后调用add_disk()将磁盘添加到系统中。注意:一旦调用了add_disk,
磁盘设备就被“激活“,表示可以使用,并随时会调用它们提供的方法。

2.2向通用块设备层发送请求

  1. 上层下发磁盘数据请求
  2. 通用块层申请bio结构,将请求的数据分段记录到bio中
  3. 如果请求的数据大于一个bio允许的最大数据量,则将请求分成多个bio
  4. 调用submit_bio提交bio请求
  5. submit_bio函数经过层层调用,最终调用块设备请求队列中的make_request_fn成员函数将bio提交给I/O调度层进行处理

generic_make_request函数将bio连接到current->bio_list链表中,并调用__generic_make_request函数提交链表中所有的bio。
在这里插入图片描述
__generic_make_request函数最终会调用块设备的请求队列中的make_request_fn成员函数将bio请求发送给I/O调度层,至此对磁盘的数据请求离开通用块层,进入下一层——I/O调度层
在这里插入图片描述

2.3 动态校验流程

verity_mapbio->bi_end_io = verity_end_io;verity_end_ioINIT_WORK(&io->work, verity_work);queue_work(io->v->verify_wq, &io->work);verity_workverity_finish_ioverity_verify_iostruct bio *bio = dm_bio_from_per_bio_datafor (b = 0; b < io->n_blocks; b++)verity_fec_decodeDMWARN_LIMIT("%s: FEC: recursion too deep", v->data_dev->name);verity_handle_errDMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,type_str, block);__submit_bioblk_mq_submit_biobio_endio                                        ///kernel_platform/msm-kernel/block/bio.cbio->bi_end_io
struct dm_verity_io {
72  	struct dm_verity *v;
73  
74  	/* original value of bio->bi_end_io */
75  	bio_end_io_t *orig_bi_end_io;
76  
77  	sector_t block;
78  	unsigned n_blocks;
79  
80  	struct bvec_iter iter;
81  
82  	struct work_struct work;
83  
84  	/*
85  	 * Three variably-size fields follow this struct:
86  	 *
87  	 * u8 hash_req[v->ahash_reqsize];
88  	 * u8 real_digest[v->digest_size];
89  	 * u8 want_digest[v->digest_size];
90  	 *
91  	 * To access them use: verity_io_hash_req(), verity_io_real_digest()
92  	 * and verity_io_want_digest().
93  	 */
94  };
int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
335  			  sector_t block, u8 *digest, bool *is_zero)
336  {
337  	int r = 0, i;
339  	if (likely(v->levels)) {
340  		/*
341  		 * First, we try to get the requested hash for
342  		 * the current block. If the hash block itself is
343  		 * verified, zero is returned. If it isn't, this
344  		 * function returns 1 and we fall back to whole
345  		 * chain verification.
346  		 */
347  		r = verity_verify_level(v, io, block, 0, true, digest);
348  		if (likely(r <= 0))
349  			goto out;
350  	}
352  	memcpy(digest, v->root_digest, v->digest_size);
354  	for (i = v->levels - 1; i >= 0; i--) {
355  		r = verity_verify_level(v, io, block, i, false, digest);
356  		if (unlikely(r))
357  			goto out;
358  	}
359  out:
360  	if (!r && v->zero_digest)
361  		*is_zero = !memcmp(v->zero_digest, digest, v->digest_size);
362  	else
363  		*is_zero = false;
364  
365  	return r;
366  }

2.4 核心校验数据

struct dm_verity {
35  	struct dm_dev *data_dev;
36  	struct dm_dev *hash_dev;
37  	struct dm_target *ti;
38  	struct dm_bufio_client *bufio;
39  	char *alg_name;
40  	struct crypto_ahash *tfm;
41  	u8 *root_digest;	/* digest of the root block */
42  	u8 *salt;		/* salt: its size is salt_size */
43  	u8 *zero_digest;	/* digest for a zero block */
44  	unsigned salt_size;
45  	sector_t data_start;	/* data offset in 512-byte sectors */
46  	sector_t hash_start;	/* hash start in blocks */
47  	sector_t data_blocks;	/* the number of data blocks */
48  	sector_t hash_blocks;	/* the number of hash blocks */
49  	unsigned char data_dev_block_bits;	/* log2(data blocksize) */
50  	unsigned char hash_dev_block_bits;	/* log2(hash blocksize) */
51  	unsigned char hash_per_block_bits;	/* log2(hashes in hash block) */
52  	unsigned char levels;	/* the number of tree levels */
53  	unsigned char version;
54  	unsigned digest_size;	/* digest size for the current hash algorithm */
55  	unsigned int ahash_reqsize;/* the size of temporary space for crypto */
56  	int hash_failed;	/* set to 1 if hash of any block failed */
57  	enum verity_mode mode;	/* mode for handling verification errors */
58  	unsigned corrupted_errs;/* Number of errors for corrupted blocks */
59
60  	struct workqueue_struct *verify_wq;
61
62  	/* starting blocks for each tree level. 0 is the lowest level. */
63  	sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
64
65  	struct dm_verity_fec *fec;	/* forward error correction */
66  	unsigned long *validated_blocks; /* bitset blocks validated */
67
68  	char *signature_key_desc; /* signature keyring reference */
69  };
70
[??? 3.809367] v->hash_blocks = 662070??662070-656896=5174[??? 3.812900] v->data_dev_block_bits=12
[??? 3.816608] v->hash_dev_block_bits=12
[??? 3.820279] v->hash_per_block_bits=7?? (4096/32 = 128, 指一个4K块上有128个哈希值)
[??? 3.823888] v->levels=3
[??? 3.826380] v->version =1
[??? 3.829033] v->digest_size=32
数据块有656896X4X1024? (超过了2G)
Level 0 :? 656896/128 = 51324k块
Level 1 :? 5132/128= 414k块
Level 2:? 40 /128 = 0,即14k块
共 5132+41+1 = 5174 个块
static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
193  				 sector_t *hash_block, unsigned *offset)
194  {
195  	sector_t position = verity_position_at_level(v, block, level);
196  	unsigned idx;
198  	*hash_block = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
200  	if (!offset)
201  		return;
203  	idx = position & ((1 << v->hash_per_block_bits) - 1);
204  	if (!v->version)
205  		*offset = idx * v->digest_size;
206  	else
207  		*offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
208  }static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
92  					 int level)
93  {
94  	return block >> (level * v->hash_per_block_bits);
95  }

三、init用户态流程

FirstStageMainFirstStageMount::DoFirstStageMountFirstStageMount::MountPartitionsFirstStageMount::MountPartitionFirstStageMountVBootV2::SetUpDmVerityAvbHandle::LoadAndVerifyVbmetaFailed to load offline vbmeta for

四 清除panic标识

adb shell
reboot "dm-verity enforcing"
reboot "dm-verity device corrupted"

五 dm-verity建立过程

在Device Mapper(DM)中使用dm-verity时,需要配置一个哈希树(hash tree),以便验证块设备上的数据的完整性。这通常通过在dmsetup命令中的目标表(target table)参数中指定相关参数来完成。以下是如何为dm-mapper中的dm-verity构建一个哈希树配置表的一般步骤:

  1. 创建源块设备:首先,你需要创建一个普通的块设备,通常是一个已经存在的块设备,例如硬盘分区或者一个镜像文件。

  2. 选择哈希算法:确定要使用的哈希算法。dm-verity支持多种哈希算法,包括SHA-256、SHA-1、SHA-512等。你需要选择一个适合你的需求的哈希算法。

  3. 生成哈希表:使用生成哈希表的工具,例如veritysetup工具,来为源块设备生成哈希表。这个哈希表包含了块设备中每个块的哈希值。通常,你可以运行以下命令来生成哈希表:

veritysetup format /dev/source_device /dev/mapper/verity_device

其中,/dev/source_device 是源块设备,/dev/mapper/verity_device 是dm-verity设备。这个命令将生成哈希表并将其存储在dm-verity设备上。

  1. 配置dm-verity目标:使用dmsetup命令配置dm-verity目标。你需要提供哈希树的根哈希值、块大小、源块设备和dm-verity设备的名称。通常,配置表看起来像这样:
dmsetup create verity_device --table '0 <block_size> verity <root_hash> /dev/source_device /dev/mapper/verity_device'

其中,<block_size> 是块的大小,<root_hash> 是哈希树的根哈希值。

  1. 使用dm-verity设备:一旦dm-verity设备被创建,你可以像使用任何其他块设备一样使用它。数据将在读取时被验证,以确保其完整性。

这里的关键是生成哈希表并配置dm-verity目标,以便验证数据的完整性。哈希表是dm-verity验证数据完整性所必需的,因为它包含了源数据块的哈希值,用于验证数据是否被篡改。配置表指定了如何使用哈希表以及其他相关参数。配置表的格式取决于dm-verity目标的实现和你的需求,但通常是一个包含所需参数的文本字符串。

ubuntu 上dm-mapper相关信息:

astro@astrox:~/code/test$ sudo lvdisplay --maps /dev/mapper/ubuntu--vg-ubuntu--lv--- Logical volume ---LV Path                /dev/ubuntu-vg/ubuntu-lvLV Name                ubuntu-lvVG Name                ubuntu-vgLV UUID                fSgsCj-fCWR-JeiN-WWQL-xPdv-T1gZ-QO9f9MLV Write Access        read/writeLV Creation host, time ubuntu-server, 2023-05-09 09:07:38 +0000LV Status              available# open                 1LV Size                49.25 GiBCurrent LE             12608Segments               1Allocation             inheritRead ahead sectors     auto- currently set to     256Block device           253:0--- Segments ---Logical extents 0 to 12607:Type                linearPhysical volume     /dev/sda3Physical extents    0 to 12607

参考:
https://aliez22.github.io/posts/11537/
https://www.shili8.cn/article/detail_20000194464.html

这篇关于avb校验相关与块校验原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/386278

相关文章

Python中使用uv创建环境及原理举例详解

《Python中使用uv创建环境及原理举例详解》uv是Astral团队开发的高性能Python工具,整合包管理、虚拟环境、Python版本控制等功能,:本文主要介绍Python中使用uv创建环境及... 目录一、uv工具简介核心特点:二、安装uv1. 通过pip安装2. 通过脚本安装验证安装:配置镜像源(可

CSS3中的字体及相关属性详解

《CSS3中的字体及相关属性详解》:本文主要介绍了CSS3中的字体及相关属性,详细内容请阅读本文,希望能对你有所帮助... 字体网页字体的三个来源:用户机器上安装的字体,放心使用。保存在第三方网站上的字体,例如Typekit和Google,可以link标签链接到你的页面上。保存在你自己Web服务器上的字

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

Nacos注册中心和配置中心的底层原理全面解读

《Nacos注册中心和配置中心的底层原理全面解读》:本文主要介绍Nacos注册中心和配置中心的底层原理的全面解读,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录临时实例和永久实例为什么 Nacos 要将服务实例分为临时实例和永久实例?1.x 版本和2.x版本的区别

apache的commons-pool2原理与使用实践记录

《apache的commons-pool2原理与使用实践记录》ApacheCommonsPool2是一个高效的对象池化框架,通过复用昂贵资源(如数据库连接、线程、网络连接)优化系统性能,这篇文章主... 目录一、核心原理与组件二、使用步骤详解(以数据库连接池为例)三、高级配置与优化四、典型应用场景五、注意事

Python FastAPI实现JWT校验的完整指南

《PythonFastAPI实现JWT校验的完整指南》在现代Web开发中,构建安全的API接口是开发者必须面对的核心挑战之一,本文将深入探讨如何基于FastAPI实现JWT(JSONWebToken... 目录一、JWT认证的核心原理二、项目初始化与环境配置三、安全密码处理机制四、JWT令牌的生成与验证五、

电脑系统Hosts文件原理和应用分享

《电脑系统Hosts文件原理和应用分享》Hosts是一个没有扩展名的系统文件,当用户在浏览器中输入一个需要登录的网址时,系统会首先自动从Hosts文件中寻找对应的IP地址,一旦找到,系统会立即打开对应... Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开,其作用就是将一些常用的网址域名与其对应

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

Spring Validation中9个数据校验工具使用指南

《SpringValidation中9个数据校验工具使用指南》SpringValidation作为Spring生态系统的重要组成部分,提供了一套强大而灵活的数据校验机制,本文给大家介绍了Spring... 目录1. Bean Validation基础注解常用注解示例在控制器中应用2. 自定义约束验证器定义自

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I