實現Dm-Verity在Android System Image上

此篇主要介紹如何在一個大容量的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

 

build_verity_tree
./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.img

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

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)
#build the verity table
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。

 #build the verity table signature
Output

verity_signer /tmp/tmpef_myU.table build/target/product/security/verity.pk8 /tmp/tmpTtayTQ.sig

用verity.pk8去sign verity table

#build the metadata block
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

# build the full verified image
  1. 將verity_metadata.img接在verity.img後面

cat /tmp/tmp7U4bxd_verity_images/verity_metadata.img >> /tmp/tmp7U4bxd_verity_images/verity.img

  1. 透過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

  1. 將verity_fec.img接在verity.img後面

cat /tmp/tmp7U4bxd_verity_images/verity_fec.img >> /tmp/tmp7U4bxd_verity_images/verity.img

  1. 將匯集好的verity.img 用sparse的格式合併至system.img

append2simg out/target/product/msm8996/obj/PACKAGING/systemimage_intermediates/system.img /tmp/tmp7U4bxd_verity_images/verity.img

7. 問題討論: