verity: create a regular trie when depth=0 We want to eventually remove support for the depth constructor parameter only create trees where level[0]->count = 1. BUG=9752 TEST=Ran dm-verity.git unit tests. Ran platform_DMVerityCorruption on H/W. Change-Id: Ie05ebc93a9c52055b4573ccd8811acbbb114adf3 R=wad@chromium.org,taysom@chromium.org,ups@chromium.org Review URL: http://codereview.chromium.org/6670096
diff --git a/dm-bht.c b/dm-bht.c index 5957cb7..1665c74 100644 --- a/dm-bht.c +++ b/dm-bht.c
@@ -265,27 +265,6 @@ goto bad_block_count; } - bht->depth = depth; /* assignment below */ - DMDEBUG("Setting depth %u", depth); - if (!depth || depth > UINT_MAX / sizeof(struct dm_bht_level)) { - DMERR("bht depth is invalid: %u", depth); - status = -EINVAL; - goto bad_depth; - } - - /* Allocate levels. Each level of the tree may have an arbitrary number - * of dm_bht_entry structs. Each entry contains node_count nodes. - * Each node in the tree is a cryptographic digest of either node_count - * nodes on the subsequent level or of a specific block on disk. - */ - bht->levels = (struct dm_bht_level *) - kcalloc(depth, sizeof(struct dm_bht_level), GFP_KERNEL); - if (!bht->levels) { - DMERR("failed to allocate tree levels"); - status = -ENOMEM; - goto bad_level_alloc; - } - /* Each dm_bht_entry->nodes is one page. The node code tracks * how many nodes fit into one entry where a node is a single * hash (message digest). @@ -302,6 +281,19 @@ status = -EINVAL; goto bad_node_count; } + + /* if depth == 0, create a "regular" trie with a single root block */ + if (depth == 0) + depth = DIV_ROUND_UP(fls(block_count - 1), + bht->node_count_shift); + if (depth > UINT_MAX / sizeof(struct dm_bht_level)) { + DMERR("bht depth is invalid: %u", depth); + status = -EINVAL; + goto bad_depth; + } + DMDEBUG("Setting depth to %u.", depth); + bht->depth = depth; + /* Ensure that we can safely shift by this value. */ if (depth * bht->node_count_shift >= sizeof(unsigned int) * 8) { DMERR("specified depth and node_count_shift is too large"); @@ -309,6 +301,19 @@ goto bad_node_count; } + /* Allocate levels. Each level of the tree may have an arbitrary number + * of dm_bht_entry structs. Each entry contains node_count nodes. + * Each node in the tree is a cryptographic digest of either node_count + * nodes on the subsequent level or of a specific block on disk. + */ + bht->levels = (struct dm_bht_level *) + kcalloc(depth, sizeof(struct dm_bht_level), GFP_KERNEL); + if (!bht->levels) { + DMERR("failed to allocate tree levels"); + status = -ENOMEM; + goto bad_level_alloc; + } + /* Setup callback stubs */ bht->read_cb = &dm_bht_read_callback_stub; bht->write_cb = &dm_bht_write_callback_stub; @@ -322,8 +327,8 @@ bad_entries_alloc: while (bht->depth-- > 0) kfree(bht->levels[bht->depth].entries); -bad_node_count: kfree(bht->levels); +bad_node_count: bad_level_alloc: bad_block_count: bad_depth:
diff --git a/dm-bht_unittest.cc b/dm-bht_unittest.cc index 2eb2297..8976418 100644 --- a/dm-bht_unittest.cc +++ b/dm-bht_unittest.cc
@@ -206,6 +206,29 @@ free(zero_page); } +TEST_F(MemoryBhtTest, CreateThenVerifyZeroDepth) { + static const unsigned int total_blocks = 16384; + // Set the root hash for a 0-filled image + static const char kRootDigest[] = + "45d65d6f9e5a962f4d80b5f1bd7a918152251c27bdad8c5f52b590c129833372"; + // A page of all zeros + u8 *zero_page = (u8 *)my_memalign(PAGE_SIZE, PAGE_SIZE); + + memset(zero_page, 0, PAGE_SIZE); + + SetupBht(0, total_blocks, "sha256"); + dm_bht_set_root_hexdigest(bht_.get(), + reinterpret_cast<const u8 *>(kRootDigest)); + + for (unsigned int blocks = 0; blocks < total_blocks; ++blocks) { + DLOG(INFO) << "verifying block: " << blocks; + EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, zero_page)); + } + + EXPECT_EQ(0, dm_bht_destroy(bht_.get())); + free(zero_page); +} + TEST_F(MemoryBhtTest, CreateThenVerifyRealParameters) { static const unsigned int total_blocks = 217600; // Set the root hash for a 0-filled image
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index dd617bd..0a7e322 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h
@@ -15,6 +15,8 @@ #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) +#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) + #define sector_div(n, b) ({ \ int _res; \ _res = (n) % (b); \