• DM-VERITY流程分析


    DM-Verity分析报告

     

    0.问题的表现形式

    1.dm-verity的初始化及验证流程

    1.1 dm-verity的初始化

    初始化dm的log:

    [    3.579718] md: Waiting for all devices to be available before autodetect

    [    3.586549] md: If you don't use raid, use raid=noautodetect

    [    3.594550] md: Autodetecting RAID arrays.

    [    3.598761] md: autorun ...

    [    3.601609] md: ... autorun DONE.

    [    3.604970] device-mapper: init: attempting early device configuration.

    [    3.614256] device-mapper: init: adding target '0 5255168 verity 1 /dev/mmcblk0p9 /dev/mmcblk0p9 4096 4096 656896 656896 sha256 0f8f00f5bf0797addffd383983ec81f1293ee90a0c0afb02adb2fbcdfff93ffd f4b71f5526c591e1d9fbc943b7e503846b4724a9ebf6d57820c2caf3cc631585 10 restart_on_corruption ignore_zero_blocks use_fec_from_device /dev/mmcblk0p9 fec_roots 2 fec_blocks 662070 fec_start 662070'

    具体的调用函数栈如下:

    系统中的初始化函数是

    int verity_ctr(),调用堆栈如下所示:

    [    3.648189] CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.14.61 #1

    [    3.654207] Hardware name: Semidrive v9 REF Board (DT)

    [    3.659353] Call trace:

    [    3.661815] [] dump_backtrace+0x0/0x230

    [    3.667224] [] show_stack+0x24/0x30

    [    3.672287] [] dump_stack+0xbc/0xf4

    [    3.677350] [] verity_ctr+0x2c/0xa28

    [    3.682499] [] dm_table_add_target+0x128/0x318

    [    3.688518] [] dm_run_setup+0x480/0x570

    [    3.693927] [] prepare_namespace+0x58/0x190

    [    3.699682] [] kernel_init_freeable+0x264/0x288

    [    3.705787] [] kernel_init+0x18/0x110

    [    3.711022] [] ret_from_fork+0x10/0x1c

    [    3.727681] device-mapper: init: dm-0 is ready

    根据系统传入的参数,初始化dm-verity的功能,参数的含义如下:

    1)Verity target version(verity target 版本号)

    版本号:1

    2)Data block device(存储实际待校验数据的块设备)

    存储数据的块设备:/dev/mmcblk0p9

    3)Hash block device(存储校验使用到hash的块设备,一般情况跟data block device是同一个)

    存储校验hash的块设备:/dev/mmcblk0p9

    4)Data block size(数据块设备的每块存储size)

    4096,即为4k

    5)Hash block size(hash块设备的每块存储size)

    4096, 即为4k

    6)Num data block(数据块设备占用的块数量)

    数据块数量656896, 即0-656895

    7)Hash start block(hash设备在存储设备的起始位置)

    656896

    8)Hash algo(hash算法)

    Sha256

    9)root digest(对应上面说的 root hash)

    0f8f00f5bf0797addffd383983ec81f1293ee90a0c0afb02adb2fbcdfff93ffd

    10)Salt(用于计算hash的盐值)

    f4b71f5526c591e1d9fbc943b7e503846b4724a9ebf6d57820c2caf3cc631585

    在内核中加入的打印:

      printk("v->hash_start = %d\n", v->hash_start);

        printk("v->data_start = %d\n", v->data_start);

           printk("v->data_blocks = %d\n", v->data_blocks);

           printk("v->hash_start =%d\n", v->hash_start);

           printk("v->hash_blocks = %d\n",v->hash_blocks);

           printk("v->data_dev_block_bits=%d\n", v->data_dev_block_bits);

           printk("v->hash_dev_block_bits=%d\n", v->hash_dev_block_bits);

           printk("v->hash_per_block_bits=%d\n", v->hash_per_block_bits);

           printk("v->levels=%d\n", v->levels);

           printk("v->version =%d\n",v->version);

           printk("v->digest_size=%d\n",v->digest_size);

    [    3.954883] hash level block[2]= 656896

    [    3.958759] hash level block[1]= 656897

    [    3.962625] hash level block[0]= 656938

    [    3.796016] v->hash_start = 656896

    [    3.799467] v->data_start = 0

    [    3.802485] v->data_blocks = 656896

    [    3.806021] v->hash_start =656896

    [    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 = 5132个4k块

    Level 1 :  5132/128= 41个4k块

    Level 2:  40 /128 = 0,即1个4k块

    共 5132+41+1 = 5174 个块

     

    1.2 dm-verity的文件系统访问流程

    verity_map()中打包bio,  注册回调函数bio->bi_end_io = verity_end_io;

    然后向驱动层发出请求:   generic_make_request(bio);在文件系统总读完数据后,会有执行注册的回调函数,在回调函数Verity_end_io中会验证hash;

    1.2.1申请文件系统访问,及注册回调函数

    访问文件系统总的函数调用堆栈如下所示:

    [   17.596778] [] el0_ia+0x1c/0x20

    [   17.606073] CPU: 0 PID: 1 Comm: systemd Not tainted 4.14.61 #1

    [   17.611963] Hardware name: Semidrive v9 REF Board (DT)

    [   17.617110] Call trace:

    [   17.619570] [] dump_backtrace+0x0/0x230

    [   17.624979] [] show_stack+0x24/0x30

    [   17.630043] [] dump_stack+0xbc/0xf4

    [   17.635107] [] verity_map+0x28/0x240   //dm-verity封装了一层

    [   17.640257] [] __map_bio+0x98/0x350

    [   17.645318] [] __split_and_process_non_flush+0x12c/0x328

    [   17.652203] [] __split_and_process_bio+0x1a8/0x388

    [   17.658567] [] dm_make_request+0x7c/0x110

    [   17.664151] [] generic_make_request+0xcc/0x290 //发出bio请求

    [   17.670168] [] submit_bio+0xbc/0x1f0

    [   17.675318] [] submit_bh_wbc+0x17c/0x1d8

    [   17.680813] [] ll_rw_block+0xf4/0xf8

    [   17.685963] [] ext4_bread_batch+0x134/0x1d0

    [   17.691720] [] ext4_find_entry+0x124/0x3f8

    [   17.697389] [] ext4_lookup+0x6c/0x210

    [   17.702626] [] lookup_slow+0xc4/0x1b0     //文件路径查找

    [   17.707861] [] walk_component+0x204/0x318

    [   17.713443] [] path_lookupat+0x8c/0x1f0

    [   17.718852] [] path_openat+0x8a0/0xb98

    [   17.724173] [] do_filp_open+0x70/0xe8

    [   17.729408] [] do_sys_open+0x178/0x260

    [   17.734730] [] SyS_openat+0x3c/0x50   //系统调用打开某个文件

     

     

    1.2.2 dm-verity回调函数的验证hash的过程

     

    上图中,是判断数据块是否被验证过了,下文中会提到hash树的块被验证过了,在缓存中保留着。

     

     

     

     

     

    2.问题的分析方法

    2.1 方法

     

    打印出当前出错块的

    1.want_digest,保存在hash树中的该验证块的hash值;

                       2.real_digest,根据实际读到的块中的数据,计算出来的hash值;

                       3.打印出数据块;

                       4.用dd命令直接把某块数据拿出来,比对3中的数据块是否正确;

    根据log分析,打印出来的数据,与用dd命令直接取出来的数据块数据是一样的,可以证明送入hash计算的原始数据是正确的,不存在内存踩踏。

        所以有可能是hash运算中本身出现了问题。

    2.2 工具

    char *bin2hex(char *dst, const void *src, size_t count)

    dd if=文件系统路径 of=输出路径 bs=4096 count=1 skip=块号

    例如:dd if=/dev/sda1 of=/root/out.txt bs=4096 count=1 skip=6752256

    /root/out.txt文件内容就是从块号中读到的内容    bs是块大小(这里为4K) count表示连续读几块   skip是从第几块开始读

    dd if=/dev/mmcblk0p9 of=/media/user/ddtest.bin bs=4096 count=1 skip=657824

    3.附录

    参考的博客:dm-verity原理剖析_内核工匠的博客-CSDN博客

  • 相关阅读:
    Educational Codeforces Round 32 G. Xor-MST 启发式合并字典树、Boruvka求最小生成树 + 最小异或字典树、分治
    Golang与Java的并发性能对比
    2.3.1 协程设计原理与汇编实现
    [文档] torch.distributions.Categorical
    cadence SPB17.4 - 比较同名焊盘文件(.pad)是否内容相同
    星岛专栏|从Web3发展看金融与科技的融合之道
    博客园商业化之路-开篇:开源的脚步,商业化的出路
    React学习---初识React
    [附源码]计算机毕业设计室内设计类网站Springboot程序
    【专栏】RPC系列(理论)-协议与序列化
  • 原文地址:https://blog.csdn.net/lieye_leaves/article/details/127980483