此篇主要介紹如何在一個大容量的image上實現Dm-Verity。
根據Android官網說明有Build Dm-Verify System Image共有六大步驟: https://source.android.com/security/verifiedboot/dm-verity
1.Generate an ext4 system image
2.Generate a hash tree for that image
3.Build a dm-verity table for that hash tree
4.Sign that dm-verity table to produce a table signature
5.Bundle the table signature and dm-verity table into verity metadata
6.Concatenate the system image, the verity metadata, and the hash tree
下圖為從一個Android System image到整合Dm-Verity的Build process
Build DM-Verity image Flow
1. Generate an ext4 system image
./tools/releasetools/build_image.py
def BuildImage(in_dir, prop_dict, out_file, target_out=None):
print("BuildImage: in_dir = %s, out_file = %s" % (in_dir, out_file))
….
try:
if reserved_blocks and fs_type.startswith("ext4"):
print "fs type is ext4"
(ext4fs_output, exit_code) = RunCommand(build_command)
else:
print "fs type is not ext4"
(_, exit_code) = RunCommand(build_command)
print("Running %s command, exit code = %d" % (build_command, exit_code))
Build log
BuildImage: in_dir = out/target/product/msm8996/system, out_file = out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img
fs type is not ext4
Running: mkuserimg.sh -s out/target/product/msm8996/system out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img ext4 system 4756439040 -D out/target/product/msm8996/system -L system out/target/product/msm8996/root/file_contexts.bin
make_ext4fs -s -T -1 -S out/target/product/msm8996/root/file_contexts.bin -L system -l 4756439040 -a system out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img out/target/product/msm8996/system out/target/product/msm8996/system
Creating filesystem with parameters:
Size: 4756439040
Block size: 4096
Blocks per group: 32768
Inodes per group: 8080
Inode size: 256
Journal blocks: 18144
Label: system
Blocks: 1161240
Block groups: 36
Reserved block group size: 287
Created filesystem with 7551/290880 inodes and 506909/1161240 blocks
Running ['mkuserimg.sh', '-s', 'out/target/product/msm8996/system', 'out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img', 'ext4', 'system', '4756439040', '-D', 'out/target/product/msm8996/system', '-L', 'system', 'out/target/product/msm8996/root/file_contexts.bin'] command, exit code = 0
2. Generate a hash tree for that image
def BuildVerityTree(sparse_image_path, verity_image_path, prop_dict):
cmd = "build_verity_tree -A %s %s %s" % (
FIXED_SALT, sparse_image_path, verity_image_path)
print cmd
./system/extras/verity/build_verity_tree.cpp
Input
build_verity_tree -A aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7 out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmpvBA1pC_verity_images/verity.img
Output
34f19e211fb368c4942c84c7c8628690edf7d11863ba79aff9d0e1d6fdae2a75 (root hash)
aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7
並會在/tmp下產生verity.img,存放hash tree,最重要的是root hash
Verity.img3. Build a dm-verity table for that hash tree
4. Sign that dm-verity table to produce a table signature
5. Bundle the table signature and dm-verity table into verity metadata
cmd_template = (
"system/extras/verity/build_verity_metadata.py %s %s %s %s %s %s %s")
cmd = cmd_template % (image_size, verity_metadata_path, root_hash, salt,
block_device, signer_path, key)
print cmd
Build log
system/extras/verity/build_verity_metadata.py 4756439040 /tmp/tmpkk4y9m_verity_images/verity_metadata.img 0cb70db07b594a58cdf5a1bcf61ec72dc86d98fd9817c05520b87130d89a6039 aee087a5be3b982978c923f566a94613496b417f2af592639bc80d141e34dfe7 /dev/block/bootdevice/by-name/system verity_signer build/target/product/security/verity.pk8
def build_verity_metadata(data_blocks, metadata_image, root_hash,
salt, block_device, signer_path, signing_key):
# 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)
# build the metadata block
metadata_block = build_metadata_block(verity_table, signature)
# write it to the outfile
with open(metadata_image, "wb") as f:
f.write(metadata_block)
The format of verity_table
table = "1 %s %s %s %s %s %s sha256 %s %s"
“1 /dev/block/bootdevice/by-name/system /dev/block/bootdevice/by-name/system 4096 4096 (4756439040/4096) (4756439040/4096) root_hash salt”
ver: on-disk hash version
0 is the original format used in the Chromium OS.
The salt is appended when hashing, digests are stored continuously and
the rest of the block is padded with zeroes.
1 is the current format that should be used for new devices.
The salt is prepended when hashing and each digest is padded with zeroes to the power of two.
將相關參數(主要是root_hash)組成verity table。
Output
verity_signer /tmp/tmpef_myU.table build/target/product/security/verity.pk8 /tmp/tmpTtayTQ.sig
用verity.pk8去sign verity table
def build_metadata_block(verity_table, signature):
table_len = len(verity_table)
block = struct.pack("II256sI", MAGIC_NUMBER, VERSION, signature, table_len)
0xb001b001 0x0 256 byte
block += verity_table
block = block.ljust(METADATA_SIZE, '\x00')
return block
The format of the verity metadata
0xb001b001, 0x0, signature(256 bytes), table length(4 bytes), verity table, \x00
將以上數據合併產生verity_metadata.img
6. Concatenate the system image, the verity metadata, and the hash tree
- 將verity_metadata.img接在verity.img後面
cat /tmp/tmp7U4bxd_verity_images/verity_metadata.img >> /tmp/tmp7U4bxd_verity_images/verity.img
- 透過fec tool做一個防止遺漏資料的補強,輸入參數為system.img和verity.img(verity_metadata.img已接在後面),產生verity_fec.img
fec -e out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmp7U4bxd_verity_images/verity.img /tmp/tmp7U4bxd_verity_images/verity_fec.img
- 將verity_fec.img接在verity.img後面
cat /tmp/tmp7U4bxd_verity_images/verity_fec.img >> /tmp/tmp7U4bxd_verity_images/verity.img
- 將匯集好的verity.img 用sparse的格式合併至system.img
append2simg out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmp7U4bxd_verity_images/verity.img
7. 問題討論:
- Hash tree 怎麼產生的,演算法有點複雜,要花時間trace code,Android官網有稍微提到。
- system/extras/verity/build_verity_tree.cpp
- Android 官網: https://source.android.com/security/verifiedboot/dm-verity.html
- What is FEC?
- FEC: forward error correction
- 簡單說是運用在防止存取資料時的錯誤,參考網址https://www.kernel.org/doc/Documentation/device-mapper/verity.txt
- Kernel如何把system mount成dm-0,To be continued~