LXR | KVM | PM | Time | Interrupt | Systems Performance | Bootup Optimization

device-mapper(3):(veritysetup/keyctl/dmsetup/openssl)创建私钥、签名并进行dm-verity的签名验证

 接前《device-mapper(2):块设备数据完整性验证功能dm-verity》,对dm-verity增加验签功能:

  • veritysetup生成镜像的hash数据,以及生成dm-verity设备所需的信息。
  • openssl生成RSA2048私钥;生成包含公钥的自签名证书;对veritysetup生成的root_hash进行签名。
  • 将包含公钥的自签名证书内嵌到内核镜像中。
  • 分别对镜像、镜像的hash数据、签名+verity table生成多个volume的ubi文件。
  • 启动内核,挂载分区从分区中获取签名+verity table,使用dmsetup对root_hash进行验签,通过后创建对应的dm设备。

1 veritysetup生成hash和相关信息(dmsetup使用)

通过veritysetup可以生成分区镜像的hash数据,并输出相关信息:

veritysetup format --data-block-szie=4096 --hash-block-size=4096 custom.squashfs custom.squashfs.hash -s - > custom_metadata/custom.squashfs.info

根据veritysetup输出信息,生成dmsetup创建dm设备所需table信息:

0 9760 verity 1 /dev/ubiblock1_0 /dev/ubiblock1_1 4096 4096 1220 1 sha256 adcc8887a4347c7e6790ccc06ed3aee3342a62b4383e26c8895862657a609e68 - 2 root_hash_sig_key_desc custom_signature

2 生成密钥、自签名证书、创建签名并验证签名(@PC)

按照如下步骤准备数据:

  • 生成RSA2048私钥。
  • 使用生成的私钥生成自签名证书,里面包含公钥。嵌入到内核镜像中。
  • 使用私钥加上证书对hash字串进行签名,得到签名数据。
    • 注意:这里一定要是字串,并且不能有回车等字符。严格要求和传入bootargs的root_hash一致。曾经掉在坑里:使用字串对应的二进制进行签名;生成的字串多了个0x0a。
      通过grep "Root hash" custom.squashfs.info | awk -v ORS= '{print $3}' > custom_hash.txt来解决上面问题。
  • 在PC验证签名是否有效。
  • 中间输出签名的详细信息和asn1格式数据用于问题定位。
# 生成 RSA 私钥PEM (Base64 编码的 PKCS#8 格式)
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048

# 生成自签名证书(PEM格式(Base64 编码的 X.509 证书),含 CA 扩展)
openssl req -new -x509 -key private_key.pem -out certificate.pem -days 36500 -subj "/CN=DM-Verity Root CA" -addext "basicConstraints=critical,CA:TRUE"

# 假设 root_hash 是待签名的数据文件,生成DER编码(二进制格式PKCS#7/CMS结构)
openssl cms -sign -in custom_hash.txt -signer certificate.pem -inkey private_key.pem -binary -noattr -md sha256 -outform DER -out custom_metadata/custom_hash.sig

# 验证签名有效性(用户态测试)
openssl cms -verify -in custom_metadata/custom_hash.sig -inform DER -content custom_hash.txt -binary -signer certificate.pem -out /dev/null

# 输出签名的详细信息
openssl cms -in custom_metadata/custom_hash.sig -inform DER -cmsout -print -noout

# 输出ans1格式数据
openssl asn1parse -inform DER -in custom_metadata/custom_hash.sig -i

3 固化自签名证书

配置内核将上面生成的包含公钥的自签名证书嵌入到内核中:

Cryptographic API
  ->Certificates for signature checking
    ->Provide system-wide ring of trusted keys
      ->Additional X.509 keys for default system keyring--指定固化到内核中的公钥路径。

4 dmsetup

dmsetup 是 Linux 中用于管理和控制 Device Mapper 框架的核心命令行工具。Device Mapper 是 Linux 内核提供的用于创建虚拟块设备的基础设施,是 LVM、软件 RAID (dm-raid)、加密 (dm-crypt/LUKS)、快照、精简配置 (thin provisioning) 和多路径 I/O 等技术的底层引擎。

dmsetup 允许你直接与这些映射设备交互,执行创建、删除、查询、修改和状态监控等操作。

4.1 主要用法和常用命令

1. 列出 Device Mapper 设备:

sudo dmsetup ls

列出所有当前加载的 Device Mapper 设备的名称及其关联的设备号 (major:minor)。
示例输出:myvg-mylv (253:0)

sudo dmsetup ls --tree

以树状结构显示设备之间的依赖关系(例如,一个精简池设备上创建的精简卷)。

sudo dmsetup info

显示所有设备的基本信息(名称、设备号、状态、映射表条目数等)。

sudo dmsetup info <device_name>

显示指定设备的详细信息。

2. 查看设备映射表:

sudo dmsetup table

显示所有 Device Mapper 设备的当前映射表。这个表定义了虚拟设备如何映射到底层物理设备(或其它虚拟设备)的哪些扇区范围。

sudo dmsetup table <device_name>

显示指定设备的映射表。
示例输出 (一个线性设备):0 20971520 linear /dev/sda1 2048
含义:此设备从 0 扇区开始,长度 20971520 个扇区,以线性方式映射到物理设备 /dev/sda1 上从 2048 扇区开始的位置。

3. 查看设备状态:

sudo dmsetup status

显示所有 Device Mapper 设备的当前状态信息。状态信息的内容和格式取决于设备使用的目标类型 (target type)。

sudo dmsetup status <device_name>

显示指定设备的状态信息。
示例输出 (一个精简卷):0 20971520 thin 253:1 5
含义:目标类型是 thin,元数据设备是 253:1,此精简卷的内部 ID 是 5。

4. 创建新设备:

sudo dmsetup create <device_name> --readonly --table "$(cat <table_file>)"

创建一个新的 Device Mapper 设备。
<device_name>:要创建的逻辑设备名称(将在 /dev/mapper/ 下出现)。
<table_file>:一个包含设备映射表定义的文件。这个文件通常由更高级的工具(如 lvcreate, cryptsetup)生成,但也可以手动创建。
手动创建表文件示例 (mytable.txt):

0 200000 linear /dev/sdb1 0
200000 100000 linear /dev/sdc1 0

创建一个名为 <device_name> 的设备,它:
前 200000 个扇区映射到 /dev/sdb1 的起始扇区。
接下来的 100000 个扇区映射到 /dev/sdc1 的起始扇区。

5. 删除设备:

sudo dmsetup remove <device_name>

删除指定的 Device Mapper 设备。设备必须处于未使用(未挂载、没有打开的文件描述符)状态。

sudo dmsetup remove_all

尝试删除所有可删除的 Device Mapper 设备(通常需要先卸载文件系统和停止相关服务)。极其危险,慎用!

6. 重命名设备:

sudo dmsetup rename <old_device_name> <new_device_name>

将设备重命名。

7. 挂起和恢复设备:

sudo dmsetup suspend <device_name>

挂起(暂停)对指定设备的 I/O 操作。通常用于在修改映射表之前冻结设备状态。

sudo dmsetup resume <device_name>

恢复之前被挂起的设备,允许 I/O 继续。在修改映射表后必须执行此操作以使新表生效。

8. 重新加载映射表:

sudo dmsetup reload <device_name> <table_file>

这是修改现有设备映射表的标准流程:
1. sudo dmsetup suspend <device_name> (挂起设备)
2. sudo dmsetup reload <device_name> <new_table_file> (加载新表定义到内核)
3. sudo dmsetup resume <device_name> (恢复设备,新表生效)
新表必须与旧表描述的扇区范围兼容(通常大小不能改变,除非目标支持如 linear 扩展)。

9. 清除设备:

sudo dmsetup clear <device_name>

强制清除设备的映射表并将其置于挂起状态。比 remove 更底层,通常用于恢复损坏的设备状态。谨慎使用!

10. 处理依赖项:

sudo dmsetup deps <device_name>

显示指定设备所依赖的其他设备(major:minor 列表)。

11. 操作消息 (Message):

sudo dmsetup message <device_name> <sector> <message>

向指定设备的特定扇区发送一条控制消息。消息内容高度依赖于设备使用的目标类型 (thin, cache, era, integrity 等)。这是与复杂目标交互进行配置或状态查询的低级方式。

sudo dmsetup wait <device_name>

等待指定设备上所有未完成的消息处理完成。

4.2 重要注意事项

1. 权限: 绝大多数 dmsetup 操作都需要 root 权限 (sudo)。
2. 高级工具: 对于常见的存储管理任务(创建 LVM 逻辑卷、设置 LUKS 加密、配置多路径),强烈建议优先使用更高级、更安全的专用工具:
LVM: pvcreate, vgcreate, lvcreate, lvdisplay, lvs, lvextend 等
LUKS 加密: cryptsetup
多路径 I/O: multipath, multipathd
精简配置: lvconvert --type thin-pool, lvcreate -V ... --thin ...
这些工具在底层最终会调用 dmsetup 或直接与内核 Device Mapper 接口通信,但它们封装了复杂的映射表构建逻辑和状态管理,提供了更安全、用户友好的界面。
3. 直接操作风险: 直接使用 dmsetup create, reload, remove 等命令操作映射表是底层操作,错误使用(尤其是映射表定义错误)极易导致数据丢失或系统不稳定。仅在明确知道自己在做什么,且高级工具无法满足特定需求时才使用。
4. 依赖关系: 删除或修改一个被其他 Device Mapper 设备依赖的设备会导致上层设备失效。
5. 设备节点: 创建的 Device Mapper 设备通常出现在 /dev/mapper/ 目录下(如 /dev/mapper/myvg-mylv),也可以通过 /dev/dm-X(X 是数字)访问。

4.3 创建、卸载实例

挂载分区,创建dm设备:

dmsetup create custom-verity --readonly --table "0 9760 verity 1 /dev/ubiblock1_0 /dev/ubiblock1_1 4096 4096 1220 1 sha256 adcc8887a4347c7e6790ccc06ed3aee3342a62b4383e26c8895862657a609e68 -"
dmsetup create custom-verity --readonly --table "0 9760 verity 1 /dev/ubiblock1_0 /dev/ubiblock1_1 4096 4096 1220 1 sha256 adcc8887a4347c7e6790ccc06ed3aee3342a62b4383e26c8895862657a609e68 - 2 root_hash_sig_key_desc custom_signature"
dmsetup create custom-verity --readonly --table "0 9760 verity 1 /dev/ubiblock1_0 /dev/ubiblock1_1 4096 4096 1220 1 sha256 adcc8887a4347c7e6790ccc06ed3aee3342a62b4383e26c8895862657a609e68 - 2 root_hash_sig_key_desc custom_signature"
dmsetup status
dmsetup remove /dev/dm-1

必须要加--readonly,因为verity设备必须是只读。

dmsetup 是 Linux Device Mapper 的瑞士军刀,提供了强大的底层设备映射管理能力。它的核心功能包括列出设备、查看映射表/状态、创建、删除、重命名、挂起/恢复、重载映射表以及发送控制消息。虽然功能强大,但因其操作直接作用于内核映射层,风险较高。日常存储管理应优先使用 lvm2, cryptsetup, multipath-tools 等高级封装工具。dmsetup 的主要价值在于故障排除、高级配置调试、编写自定义脚本以及理解 Device Mapper 工作原理。使用时务必谨慎并确保理解命令的含义和潜在影响。

5 创建ubiblock设备、加载签名、dmsetup进行dm-verity验签、挂载分区

创建ubiblock设备:

#创建ubiblock设备,卸载/dev/ubiblock1_0:
ubiblock --create /dev/ubi1_0
ubiblock --create /dev/ubi1_1
ubiblock --create /dev/ubi1_2

挂载custom_metadata目录,获取签名和verity table:

mount -t squashfs -o ro /dev/ubiblock1_2 /mnt/custom_metadata 

将签名进入到内核中:

#通过keyctl将签名加入到内核中,并查看user keyring:
cat /mnt/custom_metadata/custom_hash.sig | keyctl padd user custom_signature @u

keyctl list @u

掉坑之二:由于未注意keyctl add和keyctl padd区别,使用keyctl add直接将路径作为签名插入内核。应该使用管道输入给keyctl padd。

 dmsetup创建dm设备:

dmsetup create custom-verity --readonly --table "$(cat <path-to-table>)"
dmsetup status dmsetup remove
/dev/dm-0

挂载dm设备:

#必须要加--readonly,因为verity设备必须是只读。
mount -t squashfs -o ro /dev/mapper/custom-verity /mnt/custom

 通过挂载dm设备名,而不是/dev/dm-x,避免顺序导致文件名和设备不匹配问题。

posted on 2025-07-19 23:59  ArnoldLu  阅读(136)  评论(0)    收藏  举报

导航