DM-verity 

Data Mapper Verity의 약자로 쓰이는데, 루트 파일 시스템(Root FS)의 검증에 쓰인다. 과거에 안드로이드에 쓰였지만 현재는 점차 임베디드에 쓰이기 시작한다. 기본 원리는 아래의 해시 트리(Hash-Tree)를 만드는 것인데, Data Block마다 Hash를 생성해서 가장 아래 level의 hash 노드를 만들기 시작하고 그 위 level의 hash 노드를 그 아래 level에 hash node를 이용하여 만들어 점차 트리를 완성시켜가는데, 이때 가장 맨 위의 Hash 노드를 Root Hash라고 하며 안전하게 보관되어져야한다. 이 Root Hash값을 이용해서 dm-verity를 검증해야하기 때문.   

이러한 Hash tree를 Merkel Tree라고도 한다. 

https://www.timesys.com/security/dm-verity-without-an-initramfs/

 

1. 블록 장치 생성 + 파일 시스템 설정

# truncate -s 10G data_partition.ext4
# mkfs -t ext4 data_partition.ext4
# mkdir mnt 
# mount -o loop data_partition.ext4 mnt/ 
# echo "hello" > mnt/one.txt 
# echo "integrity" > mnt/two.txt 
# umount mnt/ 
# truncate -s 100M hash_partition.verity

10G의 크기를 갖는 블록을 하나 생성하여 ext4 파일 시스템을 적용한다. 그리고 그 안에 one.txt, two.txt를 만들고 난 후 unmount를 한다.

이후 100M 크기의 hash의 값을 갖는 영역을 생성해낸다. 이곳에 dm-verity의 merkle-tree가 저장된다.

 

2. dm-verity format

# veritysetup -v --debug format data_partition.ext4 hash_partition.verity > root_hash.txt

 

root_hash.txt의 내용

# cryptsetup 2.2.2 processing "veritysetup -v --debug format data_partition.img hash_partition.img" 
# Running command format. 
# Allocating context for crypt device hash_partition.img. 
# Trying to open and read device hash_partition.img with direct-io. 
# Initialising device-mapper backend library. 
# Formatting device hash_partition.img as type VERITY. 
# Crypto backend (OpenSSL 1.1.1f  31 Mar 2020) initialized in cryptsetup library version 2.2.2. 
# Detected kernel Linux 5.13.0-52-generic x86_64. 
# Setting ciphertext data device to data_partition.img. 
# Trying to open and read device data_partition.img with direct-io. 
# Hash creation sha256, data device data_partition.img, data blocks 2621440, hash_device hash_partition.img, offset 1. 
# Using 4 hash levels. 
# Data device size required: 10737418240 bytes. 
# Hash device size required: 84557824 bytes. 
# Updating VERITY header of size 512 on device hash_partition.img, offset 0. 
VERITY header information for hash_partition.img 
UUID:               4da1ecb5-5111-4922-8747-5e867036d9de 
Hash type:          1 
Data blocks:        2621440 
Data block size:    4096 
Hash block size:    4096 
Hash algorithm:     sha256 
Salt:       	     f2790cf141405152cf61b6eb176128ad0676b41524dd32ac39760d3be2d495cf 
Root hash:          a2a8fd07889deb10b4cdf53c01637ed373212cd7d0877a8aa9ae6fd4240f0f71 
# Releasing crypt device hash_partition.img context. 
# Releasing device-mapper backend. 
# Closing read write fd for hash_partition.img. 
Command successful.

Root Hash(a2a8fd07889deb10b4cdf53c01637ed373212cd7d0877a8aa9ae6fd4240f0f71)의 내용은 trusted된 내용이어야하고, 안전하게 보관되어야한다.

 

3. dm-verity open

# veritysetup open \ 
>         data_partition.ext4 \ 
>         verity-test \ 
>         hash_partition.verity \ 
>         a2a8fd07889deb10b4cdf53c01637ed373212cd7d0877a8aa9ae6fd4240f0f71

data_partition.ext4의 mapper를 생성한다.

/dev/mapper/verity-test 가 생성된 것을 확인할 수 있다.

# mkdir mnt 
# mount /dev/mapper/verity-test mnt/ 
mount: /home/ubuntu/ext4/mnt: WARNING: source write-protected, mounted read-only.
# cat mnt/one.txt mnt/two.txt 
hello
integrity

read-only로 mount 되었다.

 

4. dm-verity verify

user-space에서 검증이 가능하다.

  • 검증 성공 시
# veritysetup verify \
> /dev/mapper/verity-test \
> hash_partition.verity \
> a2a8fd07889deb10b4cdf53c01637ed373212cd7d0877a8aa9ae6fd4240f0f71
#
  • 검증 실패 시

  hash의 값을 변경(끝 네자리 0f71 0f73)

# veritysetup verify \
> /dev/mapper/verity-test \
> hash_partition.verity \
> a2a8fd07889deb10b4cdf53c01637ed373212cd7d0877a8aa9ae6fd4240f0f73
Verification of root hash failed.

 

5. Corruption 발생 처리

dm-verity는 디스크를 binary level 수준으로 보호하기 때문에 한 비트라도 어긋나게 되면 corruption 발생 처리하며 mount되지 않는다.

disk를 read-write로 mount하는 것 만으로도 meta-data 변형이 일어나기 때문에 binary가 변경된다. 따라서 corruption을 일으키기 충분하다.

# umount mnt/ 
# veritysetup close verity-test 
# mount -o loop data_partition.ext4 mnt/ 
# umount mnt/ 
# veritysetup open \ 
>         data_partition.ext4 \ 
>         verity-test \ 
>         hash_partition.verity \ 
>         a2a8fd07889deb10b4cdf53c01637ed373212cd7d0877a8aa9ae6fd4240f0f71 
Verity device detected corruption after activation 
root# mount /dev/mapper/verity-test mnt/ 
mount: /path/to/mnt: can't read superblock on /dev/mapper/verity-testroot## mount /dev/mapper/verity

 

dmesg를 확인하면 kernel에서 dm-verity의 log를 확인 할 수 있다.

[412036.212897] device-mapper: verity: 7:16: data block 0 is corrupted 
[412036.212996] device-mapper: verity: 7:16: data block 0 is corrupted 
[412036.213009] buffer_io_error: 91 callbacks suppressed 
[412036.213011] Buffer I/O error on dev dm-0, logical block 0, async page read 
[412036.223697] device-mapper: verity: 7:16: data block 0 is corrupted

 

5. dm-verity status

현재 mapping 상태를 확인한다.

# veritysetup status verity-test
/dev/mapper/verity-test is active.
  type:        VERITY
  status:      corrupted
  hash type:   1
  data block:  4096
  hash block:  4096
  hash name:   sha256
  salt:        f2790cf141405152cf61b6eb176128ad0676b41524dd32ac39760d3be2d495cf
  data device: /dev/loop11
  data loop:   /home/ubuntu/ext4/data_partition.ext4
  size:        20971520 sectors
  mode:        readonly
  hash device: /dev/loop10
  hash loop:   /home/ubuntu/ext4/hash_partition.verity
  hash offset: 8 sectors
  root hash:   a2a8fd07889deb10b4cdf53c01637ed373212cd7d0877a8aa9ae6fd4240f0f71

 

6. dm-verity close

mapping을 제거한다.

# veritysetup close verity-test

/dev/mapper에서 사라진것을 확인할 수 있다.

 

Reference)

https://www.timesys.com/security/dm-verity-without-an-initramfs/

 

DM-Verity Without an Initramfs - Timesys

Learn how you can implement file system verification on your embedded system without the use of an initramfs. This can significantly save boot time and storage requirements in many situations.

www.timesys.com

https://www.starlab.io/blog/dm-verity-in-embedded-device-security

반응형
블로그 이미지

REAKWON

와나진짜

,