verity: do all hashing in dm-bht.c

We were doing the hashing of the disk blocks in dm-verity.c and hashing
hash blocks in dm-bht.c. We can simplifiy the code by doing all the
hashing in dm-bht.c. We couldn't do this earlier because we had
to handle unaligned reads (no longer an issue).

I also removed the BUG_ON in dm_bht_get_node because I wanted to use it
in dm_bht_check_block with depth == bht->depth.

The kernel piece has already been reviewed and submitted. What is different
in this CL are the modifications to the tests.

BUG=9752
TEST=Ran dm-verity.git unit tests. Ran platform_DMVerityCorruption on H/W.
kernel.git Review URL: http://codereview.chromium.org/6626037

Change-Id: Ic817a53f383f7727742c77c2064cdb0afe595c43

R=wad@chromium.org,taysom@chromium.org,ups@chromium.org

Review URL: http://codereview.chromium.org/6695038
diff --git a/dm-bht.c b/dm-bht.c
index 35713de..c9d1fca 100644
--- a/dm-bht.c
+++ b/dm-bht.c
@@ -163,9 +163,6 @@
 				  unsigned int block_index)
 {
 	unsigned int index = dm_bht_index_at_level(bht, depth, block_index);
-	struct dm_bht_level *level = dm_bht_get_level(bht, depth);
-
-	BUG_ON(index >= level->count);
 
 	return dm_bht_node(bht, entry, index % bht->node_count);
 }
@@ -588,34 +585,28 @@
 	return 0;
 }
 
-/* digest length and bht must be checked already */
+/* Check the disk block against the leaf hash. */
 static int dm_bht_check_block(struct dm_bht *bht, unsigned int block_index,
-			      u8 *digest, int *entry_state)
+			      const void *block, int *entry_state)
 {
-	int depth;
-	unsigned int index;
-	struct dm_bht_entry *entry;
-
-	/* The leaves contain the block hashes */
-	depth = bht->depth - 1;
-
-	/* Index into the bottom level.  Each entry in this level contains
-	 * nodes whose hashes are the direct hashes of one block of data on
-	 * disk.
-	 */
-	index = block_index >> bht->node_count_shift;
-	entry = &bht->levels[depth].entries[index];
+	unsigned int depth = bht->depth;
+	struct dm_bht_entry *parent = dm_bht_get_entry(bht, depth - 1,
+						       block_index);
+	struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()];
+	u8 digest[DM_BHT_MAX_DIGEST_SIZE];
+	u8 *node;
 
 	/* This call is only safe if all nodes along the path
 	 * are already populated (i.e. READY) via dm_bht_populate.
 	 */
-	BUG_ON(atomic_read(&entry->state) < DM_BHT_ENTRY_READY);
+	*entry_state = atomic_read(&parent->state);
+	BUG_ON(*entry_state < DM_BHT_ENTRY_READY);
 
-	/* Index into the entry data */
-	index = (block_index % bht->node_count) * bht->digest_size;
-	if (memcmp(&entry->nodes[index], digest, bht->digest_size)) {
-		DMCRIT("digest mismatch for block %u", block_index);
-		dm_bht_log_mismatch(bht, &entry->nodes[index], digest);
+	node = dm_bht_get_node(bht, parent, depth, block_index);
+	if (dm_bht_compute_hash(bht, hash_desc, virt_to_page(block), digest) ||
+	    dm_bht_compare_hash(bht, digest, node)) {
+		DMERR("failed to verify entry's hash against parent "
+		      "(d=%u,bi=%u)", depth, block_index);
 		return DM_BHT_ENTRY_ERROR_MISMATCH;
 	}
 	return 0;
@@ -1061,25 +1052,18 @@
  * dm_bht_verify_block - checks that all nodes in the path for @block are valid
  * @bht:	pointer to a dm_bht_create()d bht
  * @block_index:specific block data is expected from
- * @digest:	computed digest for the given block to be checked
- * @digest_len:	length of @digest
+ * @block:	virtual address of the block data in memory
  *
  * Returns 0 on success, 1 on missing data, and a negative error
  * code on verification failure. All supporting functions called
  * should return similarly.
  */
 int dm_bht_verify_block(struct dm_bht *bht, unsigned int block_index,
-				u8 *digest, unsigned int digest_len)
+			const void *block)
 {
 	int unverified = 0;
 	int entry_state = 0;
 
-	/* TODO(wad) do we really need this? */
-	if (digest_len != bht->digest_size) {
-		DMERR("invalid digest_len passed to verify_block");
-		return -EINVAL;
-	}
-
 	/* Make sure that the root has been verified */
 	if (atomic_read(&bht->root_state) != DM_BHT_ENTRY_VERIFIED) {
 		unverified = dm_bht_verify_root(bht, dm_bht_compare_hash);
@@ -1090,7 +1074,7 @@
 	}
 
 	/* Now check that the digest supplied matches the leaf hash */
-	unverified = dm_bht_check_block(bht, block_index, digest, &entry_state);
+	unverified = dm_bht_check_block(bht, block_index, block, &entry_state);
 	if (unverified) {
 		DMERR_LIMIT("Block check failed for %u: %d", block_index,
 				unverified);
diff --git a/dm-bht.h b/dm-bht.h
index 37c501d..25c20b5 100644
--- a/dm-bht.h
+++ b/dm-bht.h
@@ -135,7 +135,7 @@
 int dm_bht_populate(struct dm_bht *bht, void *read_cb_ctx,
 		    unsigned int block_index);
 int dm_bht_verify_block(struct dm_bht *bht, unsigned int block_index,
-			u8 *digest, unsigned int digest_len);
+			const void *buf);
 
 /* Functions for creating struct dm_bhts on disk.  A newly created dm_bht
  * should not be directly used for verification. (It should be repopulated.)
diff --git a/dm-bht_unittest.cc b/dm-bht_unittest.cc
index bf8c74c..96323b4 100644
--- a/dm-bht_unittest.cc
+++ b/dm-bht_unittest.cc
@@ -107,9 +107,7 @@
                 const char *digest_algorithm) {
     NewBht(depth, total_blocks, digest_algorithm);
 
-    u8 data[PAGE_SIZE];
-    // Store all the block hashes of blocks of 0.
-    memset(reinterpret_cast<void *>(data), 0, sizeof(data));
+    u8 data[PAGE_SIZE] = { 0 };
     unsigned int blocks = total_blocks;
     do {
       EXPECT_EQ(dm_bht_store_block(bht_.get(), blocks - 1, data), 0);
@@ -151,16 +149,8 @@
   // Set the root hash for a 0-filled image
   static const char kRootDigest[] =
     "45d65d6f9e5a962f4d80b5f1bd7a918152251c27bdad8c5f52b590c129833372";
-  // This should match what dm_bht_store_block computed earlier.
-  static const char kZeroDigest[] =
-    "ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7";
-  u8 digest[(sizeof(kZeroDigest) - 1) >> 1];
-  // TODO(wad) write a test for hex_to_bin and bin_to_hex
-  unsigned int digest_size = strlen(kZeroDigest) >> 1;
-
-  dm_bht_hex_to_bin(digest,
-                    reinterpret_cast<const u8 *>(kZeroDigest),
-                    digest_size);
+  // A page of all zeros
+  static const char kZeroPage[PAGE_SIZE] = { 0 };
 
   SetupBht(2, total_blocks, "sha256");
   dm_bht_set_root_hexdigest(bht_.get(),
@@ -168,7 +158,7 @@
 
   for (unsigned int blocks = 0; blocks < total_blocks; ++blocks) {
     DLOG(INFO) << "verifying block: " << blocks;
-    EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, digest, digest_size));
+    EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, kZeroPage));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
@@ -179,16 +169,8 @@
   // Set the root hash for a 0-filled image
   static const char kRootDigest[] =
     "c86619624d3456f711dbb94d4ad79a4b029f6fd3b5a4a90b155c856bf5b3409b";
-  // This should match what dm_bht_store_block computed earlier.
-  static const char kZeroDigest[] =
-    "ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7";
-  u8 digest[(sizeof(kZeroDigest) - 1) >> 1];
-  // TODO(wad) write a test for hex_to_bin and bin_to_hex
-  unsigned int digest_size = strlen(kZeroDigest) >> 1;
-
-  dm_bht_hex_to_bin(digest,
-                    reinterpret_cast<const u8 *>(kZeroDigest),
-                    digest_size);
+  // A page of all zeros
+  static const char kZeroPage[PAGE_SIZE] = { 0 };
 
   SetupBht(4, total_blocks, "sha256");
   dm_bht_set_root_hexdigest(bht_.get(),
@@ -196,7 +178,7 @@
 
   for (unsigned int blocks = 0; blocks < total_blocks; ++blocks) {
     DLOG(INFO) << "verifying block: " << blocks;
-    EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, digest, digest_size));
+    EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, kZeroPage));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
@@ -207,16 +189,8 @@
   // Set the root hash for a 0-filled image
   static const char kRootDigest[] =
     "c78d187c430465bd7831fe4908247b6ab5107e3a826d933b71e85aa9a932e03c";
-  // This should match what dm_bht_store_block computed earlier.
-  static const char kZeroDigest[] =
-    "ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7";
-  u8 digest[(sizeof(kZeroDigest) - 1) >> 1];
-  // TODO(wad) write a test for hex_to_bin and bin_to_hex
-  unsigned int digest_size = strlen(kZeroDigest) >> 1;
-
-  dm_bht_hex_to_bin(digest,
-                    reinterpret_cast<const u8 *>(kZeroDigest),
-                    digest_size);
+  // A page of all zeros
+  static const char kZeroPage[PAGE_SIZE] = { 0 };
 
   SetupBht(4, total_blocks, "sha256");
   dm_bht_set_root_hexdigest(bht_.get(),
@@ -224,15 +198,17 @@
 
   for (unsigned int blocks = 0; blocks < total_blocks; ++blocks) {
     DLOG(INFO) << "verifying block: " << blocks;
-    EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, digest, digest_size));
+    EXPECT_EQ(0, dm_bht_verify_block(bht_.get(), blocks, kZeroPage));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
 }
 
-TEST_F(MemoryBhtTest, CreateThenVerifyBad) {
+TEST_F(MemoryBhtTest, CreateThenVerifyBadHashBlock) {
   static const unsigned int total_blocks = 16384;
   SetupBht(2, total_blocks, "sha256");
+  // A page of all zeros
+  static const char kZeroPage[PAGE_SIZE] = { 0 };
   // Set the root hash for a 0-filled image
   static const char kRootDigest[] =
     "45d65d6f9e5a962f4d80b5f1bd7a918152251c27bdad8c5f52b590c129833372";
@@ -241,43 +217,51 @@
 
   // TODO(wad) add tests for partial tree validity/verification
 
-  // Corrupt one block value
+  // Corrupt one has hblock
   static const unsigned int kBadBlock = 256;
   u8 data[PAGE_SIZE];
   memset(reinterpret_cast<void *>(data), 'A', sizeof(data));
   EXPECT_EQ(dm_bht_store_block(bht_.get(), kBadBlock, data), 0);
 
-  // This should match what dm_bht_store_block computed earlier.
-  static const char kZeroDigest[] =
-    "ad7facb2586fc6e966c004d7d1d16b024f5805ff7cb47c7a85dabd8b48892ca7";
-  u8 digest[(sizeof(kZeroDigest) - 1) >> 1];
-  // TODO(wad) write a test for hex_to_bin and bin_to_hex
-  unsigned int digest_size = strlen(kZeroDigest) >> 1;
-  dm_bht_hex_to_bin(digest,
-                    reinterpret_cast<const u8 *>(kZeroDigest),
-                    digest_size);
-
   // Attempt to verify both the bad block and all the neighbors.
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 1, digest, digest_size),
-            0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 1, kZeroPage), 0);
 
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 2, digest, digest_size),
-            0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 2, kZeroPage), 0);
 
   EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + (bht_->node_count / 2),
-                                digest, digest_size),
+                                kZeroPage),
             0);
 
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock, digest, digest_size), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock, kZeroPage), 0);
 
   // Verify that the prior entry is untouched and still safe
-  EXPECT_EQ(dm_bht_verify_block(bht_.get(), kBadBlock - 1, digest, digest_size),
-            0);
+  EXPECT_EQ(dm_bht_verify_block(bht_.get(), kBadBlock - 1, kZeroPage), 0);
 
   // Same for the next entry
   EXPECT_EQ(dm_bht_verify_block(bht_.get(), kBadBlock + bht_->node_count,
-                                digest, digest_size),
+                                kZeroPage),
             0);
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
 }
+
+TEST_F(MemoryBhtTest, CreateThenVerifyBadDataBlock) {
+  static const unsigned int total_blocks = 384;
+  SetupBht(2, total_blocks, "sha256");
+  // Set the root hash for a 0-filled image
+  static const char kRootDigest[] =
+    "45d65d6f9e5a962f4d80b5f1bd7a918152251c27bdad8c5f52b590c129833372";
+  dm_bht_set_root_hexdigest(bht_.get(),
+                            reinterpret_cast<const u8 *>(kRootDigest));
+  // A corrupt page
+  static const u8 kBadPage[PAGE_SIZE] = { 'A' };
+
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 0, kBadPage), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 127, kBadPage), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 128, kBadPage), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 255, kBadPage), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 256, kBadPage), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 383, kBadPage), 0);
+
+  EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
+}