blob: 21d929fe305f94d672c9750b5a435913a175b50a [file] [log] [blame]
dm-bht provides a block hash tree implementation. The use of dm-bht allows
for integrity checking of a given block device without reading the entire
set of blocks into memory before use.
In particular, dm-bht supplies an interface for creating and verifying a tree
of cryptographic digests with any algorithm supported by the kernel crypto API.
The `verity' target is the motivating example.
Theory of operation
dm-bht is logically comprised of multiple nodes organized in a tree-like
structure. Each node in the tree is a cryptographic hash. If it is a leaf
node, the hash is of some block data on disk. If it is an intermediary node,
then the hash is of a number of child nodes.
dm-bht has a given depth starting at 1 (ignoring the root node). Each level in
the tree is concretely made up of dm_bht_entry structs. Each entry in the tree
is a collection of neighboring nodes that fit in one page-sized block. The
number is determined based on PAGE_SIZE and the size of the selected
cryptographic digest algorithm. The hashes are linearly ordered in this entry
and any unaligned trailing space is ignored but included when calculating the
parent node.
The tree looks something like:
alg= sha256, num_blocks = 32767
[ root ]
/ . . . \
[entry_0] [entry_1]
/ . . . \ . . . \
[entry_0_0] . . . [entry_0_127] . . . . [entry_1_127]
/ ... \ / . . . \ / \
blk_0 ... blk_127 blk_16256 blk_16383 blk_32640 . . . blk_32767
root is treated independently from the depth and the blocks are expected to
be hashed and supplied to the dm-bht. hash blocks that make up the entry
contents are expected to be read from disk.
dm-bht does not handle I/O directly but instead expects the consumer to
supply callbacks. The read callback will always receive a page-align value
to pass to the block device layer to read in a hash value.
The API provides mechanisms for reading and verifying a tree. When reading, all
required data for the hash tree should be populated for a block before
attempting a verify. This can be done by calling dm_bht_populate(). When all
data is ready, a call to dm_bht_verify_block() with the expected hash value will
perform both the direct block hash check and the hashes of the parent and
neighboring nodes where needed to ensure validity up to the root hash. Note,
dm_bht_set_root_hexdigest() should be called before any verification attempts