Skip to content

Commit a4ffc15

Browse files
Mikulas Patockakergon
authored andcommitted
dm: add verity target
This device-mapper target creates a read-only device that transparently validates the data on one underlying device against a pre-generated tree of cryptographic checksums stored on a second device. Two checksum device formats are supported: version 0 which is already shipping in Chromium OS and version 1 which incorporates some improvements. Signed-off-by: Mikulas Patocka <[email protected]> Signed-off-by: Mandeep Singh Baines <[email protected]> Signed-off-by: Will Drewry <[email protected]> Signed-off-by: Elly Jones <[email protected]> Cc: Milan Broz <[email protected]> Cc: Olof Johansson <[email protected]> Cc: Steffen Klassert <[email protected]> Cc: Andrew Morton <[email protected]> Signed-off-by: Alasdair G Kergon <[email protected]>
1 parent a66cc28 commit a4ffc15

File tree

4 files changed

+1128
-0
lines changed

4 files changed

+1128
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
dm-verity
2+
==========
3+
4+
Device-Mapper's "verity" target provides transparent integrity checking of
5+
block devices using a cryptographic digest provided by the kernel crypto API.
6+
This target is read-only.
7+
8+
Construction Parameters
9+
=======================
10+
<version> <dev> <hash_dev> <hash_start>
11+
<data_block_size> <hash_block_size>
12+
<num_data_blocks> <hash_start_block>
13+
<algorithm> <digest> <salt>
14+
15+
<version>
16+
This is the version number of the on-disk format.
17+
18+
0 is the original format used in the Chromium OS.
19+
The salt is appended when hashing, digests are stored continuously and
20+
the rest of the block is padded with zeros.
21+
22+
1 is the current format that should be used for new devices.
23+
The salt is prepended when hashing and each digest is
24+
padded with zeros to the power of two.
25+
26+
<dev>
27+
This is the device containing the data the integrity of which needs to be
28+
checked. It may be specified as a path, like /dev/sdaX, or a device number,
29+
<major>:<minor>.
30+
31+
<hash_dev>
32+
This is the device that that supplies the hash tree data. It may be
33+
specified similarly to the device path and may be the same device. If the
34+
same device is used, the hash_start should be outside of the dm-verity
35+
configured device size.
36+
37+
<data_block_size>
38+
The block size on a data device. Each block corresponds to one digest on
39+
the hash device.
40+
41+
<hash_block_size>
42+
The size of a hash block.
43+
44+
<num_data_blocks>
45+
The number of data blocks on the data device. Additional blocks are
46+
inaccessible. You can place hashes to the same partition as data, in this
47+
case hashes are placed after <num_data_blocks>.
48+
49+
<hash_start_block>
50+
This is the offset, in <hash_block_size>-blocks, from the start of hash_dev
51+
to the root block of the hash tree.
52+
53+
<algorithm>
54+
The cryptographic hash algorithm used for this device. This should
55+
be the name of the algorithm, like "sha1".
56+
57+
<digest>
58+
The hexadecimal encoding of the cryptographic hash of the root hash block
59+
and the salt. This hash should be trusted as there is no other authenticity
60+
beyond this point.
61+
62+
<salt>
63+
The hexadecimal encoding of the salt value.
64+
65+
Theory of operation
66+
===================
67+
68+
dm-verity is meant to be setup as part of a verified boot path. This
69+
may be anything ranging from a boot using tboot or trustedgrub to just
70+
booting from a known-good device (like a USB drive or CD).
71+
72+
When a dm-verity device is configured, it is expected that the caller
73+
has been authenticated in some way (cryptographic signatures, etc).
74+
After instantiation, all hashes will be verified on-demand during
75+
disk access. If they cannot be verified up to the root node of the
76+
tree, the root hash, then the I/O will fail. This should identify
77+
tampering with any data on the device and the hash data.
78+
79+
Cryptographic hashes are used to assert the integrity of the device on a
80+
per-block basis. This allows for a lightweight hash computation on first read
81+
into the page cache. Block hashes are stored linearly-aligned to the nearest
82+
block the size of a page.
83+
84+
Hash Tree
85+
---------
86+
87+
Each node in the tree is a cryptographic hash. If it is a leaf node, the hash
88+
is of some block data on disk. If it is an intermediary node, then the hash is
89+
of a number of child nodes.
90+
91+
Each entry in the tree is a collection of neighboring nodes that fit in one
92+
block. The number is determined based on block_size and the size of the
93+
selected cryptographic digest algorithm. The hashes are linearly-ordered in
94+
this entry and any unaligned trailing space is ignored but included when
95+
calculating the parent node.
96+
97+
The tree looks something like:
98+
99+
alg = sha256, num_blocks = 32768, block_size = 4096
100+
101+
[ root ]
102+
/ . . . \
103+
[entry_0] [entry_1]
104+
/ . . . \ . . . \
105+
[entry_0_0] . . . [entry_0_127] . . . . [entry_1_127]
106+
/ ... \ / . . . \ / \
107+
blk_0 ... blk_127 blk_16256 blk_16383 blk_32640 . . . blk_32767
108+
109+
110+
On-disk format
111+
==============
112+
113+
Below is the recommended on-disk format. The verity kernel code does not
114+
read the on-disk header. It only reads the hash blocks which directly
115+
follow the header. It is expected that a user-space tool will verify the
116+
integrity of the verity_header and then call dmsetup with the correct
117+
parameters. Alternatively, the header can be omitted and the dmsetup
118+
parameters can be passed via the kernel command-line in a rooted chain
119+
of trust where the command-line is verified.
120+
121+
The on-disk format is especially useful in cases where the hash blocks
122+
are on a separate partition. The magic number allows easy identification
123+
of the partition contents. Alternatively, the hash blocks can be stored
124+
in the same partition as the data to be verified. In such a configuration
125+
the filesystem on the partition would be sized a little smaller than
126+
the full-partition, leaving room for the hash blocks.
127+
128+
struct superblock {
129+
uint8_t signature[8]
130+
"verity\0\0";
131+
132+
uint8_t version;
133+
1 - current format
134+
135+
uint8_t data_block_bits;
136+
log2(data block size)
137+
138+
uint8_t hash_block_bits;
139+
log2(hash block size)
140+
141+
uint8_t pad1[1];
142+
zero padding
143+
144+
uint16_t salt_size;
145+
big-endian salt size
146+
147+
uint8_t pad2[2];
148+
zero padding
149+
150+
uint32_t data_blocks_hi;
151+
big-endian high 32 bits of the 64-bit number of data blocks
152+
153+
uint32_t data_blocks_lo;
154+
big-endian low 32 bits of the 64-bit number of data blocks
155+
156+
uint8_t algorithm[16];
157+
cryptographic algorithm
158+
159+
uint8_t salt[384];
160+
salt (the salt size is specified above)
161+
162+
uint8_t pad3[88];
163+
zero padding to 512-byte boundary
164+
}
165+
166+
Directly following the header (and with sector number padded to the next hash
167+
block boundary) are the hash blocks which are stored a depth at a time
168+
(starting from the root), sorted in order of increasing index.
169+
170+
Status
171+
======
172+
V (for Valid) is returned if every check performed so far was valid.
173+
If any check failed, C (for Corruption) is returned.
174+
175+
Example
176+
=======
177+
178+
Setup a device:
179+
dmsetup create vroot --table \
180+
"0 2097152 "\
181+
"verity 1 /dev/sda1 /dev/sda2 4096 4096 2097152 1 "\
182+
"4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
183+
"1234000000000000000000000000000000000000000000000000000000000000"
184+
185+
A command line tool veritysetup is available to compute or verify
186+
the hash tree or activate the kernel driver. This is available from
187+
the LVM2 upstream repository and may be supplied as a package called
188+
device-mapper-verity-tools:
189+
git://sources.redhat.com/git/lvm2
190+
http://sourceware.org/git/?p=lvm2.git
191+
http://sourceware.org/cgi-bin/cvsweb.cgi/LVM2/verity?cvsroot=lvm2
192+
193+
veritysetup -a vroot /dev/sda1 /dev/sda2 \
194+
4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076

drivers/md/Kconfig

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,4 +370,24 @@ config DM_FLAKEY
370370
---help---
371371
A target that intermittently fails I/O for debugging purposes.
372372

373+
config DM_VERITY
374+
tristate "Verity target support (EXPERIMENTAL)"
375+
depends on BLK_DEV_DM && EXPERIMENTAL
376+
select CRYPTO
377+
select CRYPTO_HASH
378+
select DM_BUFIO
379+
---help---
380+
This device-mapper target creates a read-only device that
381+
transparently validates the data on one underlying device against
382+
a pre-generated tree of cryptographic checksums stored on a second
383+
device.
384+
385+
You'll need to activate the digests you're going to use in the
386+
cryptoapi configuration.
387+
388+
To compile this code as a module, choose M here: the module will
389+
be called dm-verity.
390+
391+
If unsure, say N.
392+
373393
endif # MD

drivers/md/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ obj-$(CONFIG_DM_LOG_USERSPACE) += dm-log-userspace.o
4242
obj-$(CONFIG_DM_ZERO) += dm-zero.o
4343
obj-$(CONFIG_DM_RAID) += dm-raid.o
4444
obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o
45+
obj-$(CONFIG_DM_VERITY) += dm-verity.o
4546

4647
ifeq ($(CONFIG_DM_UEVENT),y)
4748
dm-mod-objs += dm-uevent.o

0 commit comments

Comments
 (0)