| /* |
| * Copyright (C) 2010 The Chromium OS Authors <chromium-os-dev@chromium.org> |
| * |
| * Device-Mapper block hash tree interface. |
| * See Documentation/device-mapper/dm-bht.txt for details. |
| * |
| * This file is released under the GPLv2. |
| */ |
| #ifndef VERITY_DM_BHT_H_ |
| #define VERITY_DM_BHT_H_ |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #include <linux/crypto.h> |
| #include <linux/types.h> |
| |
| /* To avoid allocating memory for digest tests, we just setup a |
| * max to use for now. |
| */ |
| #define DM_BHT_MAX_DIGEST_SIZE 128 /* 1k hashes are unlikely for now */ |
| #define DM_BHT_SALT_SIZE 32 /* 256 bits of salt is a lot */ |
| |
| /* UNALLOCATED, PENDING, READY, and VERIFIED are valid states. All other |
| * values are entry-related return codes. |
| */ |
| #define DM_BHT_ENTRY_VERIFIED 8 /* 'nodes' has been checked against parent */ |
| #define DM_BHT_ENTRY_READY 4 /* 'nodes' is loaded and available */ |
| #define DM_BHT_ENTRY_PENDING 2 /* 'nodes' is being loaded */ |
| #define DM_BHT_ENTRY_UNALLOCATED 0 /* untouched */ |
| #define DM_BHT_ENTRY_ERROR -1 /* entry is unsuitable for use */ |
| #define DM_BHT_ENTRY_ERROR_IO -2 /* I/O error on load */ |
| |
| /* Additional possible return codes */ |
| #define DM_BHT_ENTRY_ERROR_MISMATCH -3 /* Digest mismatch */ |
| |
| /* dm_bht_entry |
| * Contains dm_bht->node_count tree nodes at a given tree depth. |
| * state is used to transactionally assure that data is paged in |
| * from disk. Unless dm_bht kept running crypto contexts for each |
| * level, we need to load in the data for on-demand verification. |
| */ |
| struct dm_bht_entry { |
| volatile int state; /* see defines */ |
| /* Keeping an extra pointer per entry wastes up to ~33k of |
| * memory if a 1m blocks are used (or 66 on 64-bit arch) |
| */ |
| void* io_context; /* Reserve a pointer for use during io */ |
| /* data should only be non-NULL if fully populated. */ |
| // NOLINTNEXTLINE(readability/multiline_comment) |
| u8* nodes; /* The hash data used to verify the children. |
| * Guaranteed to be page-aligned. */ |
| }; |
| |
| /* dm_bht_level |
| * Contains an array of entries which represent a page of hashes where |
| * each hash is a node in the tree at the given tree depth/level. |
| */ |
| struct dm_bht_level { |
| struct dm_bht_entry* entries; /* array of entries of tree nodes */ |
| unsigned int count; /* number of entries at this level */ |
| sector_t sector; /* starting sector for this level */ |
| }; |
| |
| /* opaque context, start, databuf, sector_count */ |
| typedef int (*dm_bht_callback)(void*, /* external context */ |
| sector_t, /* start sector */ |
| u8*, /* destination page */ |
| sector_t, /* num sectors */ |
| struct dm_bht_entry*); |
| /* dm_bht - Device mapper block hash tree |
| * dm_bht provides a fixed interface for comparing data blocks |
| * against a cryptographic hashes stored in a hash tree. It |
| * optimizes the tree structure for storage on disk. |
| * |
| * The tree is built from the bottom up. A collection of data, |
| * external to the tree, is hashed and these hashes are stored |
| * as the blocks in the tree. For some number of these hashes, |
| * a parent node is created by hashing them. These steps are |
| * repeated. |
| * |
| * TODO(wad): All hash storage memory is pre-allocated and freed once an |
| * entire branch has been verified. |
| */ |
| struct dm_bht { |
| /* Configured values */ |
| int depth; /* Depth of the tree including the root */ |
| unsigned int block_count; /* Number of blocks hashed */ |
| char hash_alg[CRYPTO_MAX_ALG_NAME]; |
| unsigned char salt[DM_BHT_SALT_SIZE]; |
| |
| /* This is a temporary hack to ease the transition to salting. It will |
| * be removed once salting is supported both in kernel and userspace, |
| * and the salt will default to all zeroes instead. */ |
| bool have_salt; |
| |
| /* Computed values */ |
| unsigned int node_count; /* Data size (in hashes) for each entry */ |
| unsigned int node_count_shift; /* first bit set - 1 */ |
| /* There is one per CPU so that verified can be simultaneous. */ |
| /* We assume we only have one CPU in userland. */ |
| struct hash_desc hash_desc[1]; /* Container for the hash alg */ |
| unsigned int digest_size; |
| sector_t sectors; /* Number of disk sectors used */ |
| |
| /* bool verified; Full tree is verified */ |
| u8 root_digest[DM_BHT_MAX_DIGEST_SIZE]; |
| struct dm_bht_level* levels; /* in reverse order */ |
| /* Callback for reading from the hash device */ |
| dm_bht_callback read_cb; |
| }; |
| |
| /* Constructor for struct dm_bht instances. */ |
| int dm_bht_create(struct dm_bht* bht, |
| unsigned int block_count, |
| const char* alg_name); |
| /* Destructor for struct dm_bht instances. Does not free @bht */ |
| int dm_bht_destroy(struct dm_bht* bht); |
| |
| /* Basic accessors for struct dm_bht */ |
| sector_t dm_bht_sectors(const struct dm_bht* bht); |
| void dm_bht_set_read_cb(struct dm_bht* bht, dm_bht_callback read_cb); |
| int dm_bht_set_root_hexdigest(struct dm_bht* bht, const u8* hexdigest); |
| int dm_bht_root_hexdigest(struct dm_bht* bht, u8* hexdigest, int available); |
| void dm_bht_set_salt(struct dm_bht* bht, const char* hexsalt); |
| int dm_bht_salt(struct dm_bht* bht, char* hexsalt); |
| |
| /* Functions for loading in data from disk for verification */ |
| bool dm_bht_is_populated(struct dm_bht* bht, unsigned int block); |
| int dm_bht_populate(struct dm_bht* bht, void* read_cb_ctx, unsigned int block); |
| int dm_bht_verify_block(struct dm_bht* bht, |
| unsigned int block, |
| const u8* buffer, |
| unsigned int offset); |
| int dm_bht_zeroread_callback(void* ctx, |
| sector_t start, |
| u8* dst, |
| sector_t count, |
| struct dm_bht_entry* entry); |
| void dm_bht_read_completed(struct dm_bht_entry* entry, int status); |
| |
| /* Functions for converting indices to nodes. */ |
| |
| static inline struct dm_bht_level* dm_bht_get_level(struct dm_bht* bht, |
| int depth) { |
| return &bht->levels[depth]; |
| } |
| |
| static inline unsigned int dm_bht_get_level_shift(struct dm_bht* bht, |
| int depth) { |
| return (bht->depth - depth) * bht->node_count_shift; |
| } |
| |
| /* For the given depth, this is the entry index. At depth+1 it is the node |
| * index for depth. |
| */ |
| static inline unsigned int dm_bht_index_at_level(struct dm_bht* bht, |
| int depth, |
| unsigned int leaf) { |
| return leaf >> dm_bht_get_level_shift(bht, depth); |
| } |
| |
| static inline u8* dm_bht_node(struct dm_bht* bht, |
| struct dm_bht_entry* entry, |
| unsigned int node_index) { |
| return &entry->nodes[node_index * bht->digest_size]; |
| } |
| |
| static inline struct dm_bht_entry* dm_bht_get_entry(struct dm_bht* bht, |
| int depth, |
| unsigned int block) { |
| unsigned int index = dm_bht_index_at_level(bht, depth, block); |
| struct dm_bht_level* level = dm_bht_get_level(bht, depth); |
| |
| return &level->entries[index]; |
| } |
| |
| static inline u8* dm_bht_get_node(struct dm_bht* bht, |
| struct dm_bht_entry* entry, |
| int depth, |
| unsigned int block) { |
| unsigned int index = dm_bht_index_at_level(bht, depth, block); |
| |
| return dm_bht_node(bht, entry, index % bht->node_count); |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif // VERITY_DM_BHT_H_ |