verity: don't call page_address on unmapped highmem pages

This fixes a bug that is preventing ARM systems from booting with verity.

We were calling page_address on what could potentially have been an
unmapped highmem page. Fix is to pass the struct page to the crypto code
and let crypto handle the kmap/kunmap.

BUG=chromium-os:14089,chrome-os-partner:3287
TEST=Ran dm-verity.git unit tests. Ran platform_DMVerityCorruption on H/W.
Verified that ARM now boots.

kernel-next.git Review URL: http://codereview.chromium.org/6835032

TBRing. Code has already been reviewed and committed to kernel-next.git
There are some trivial changes here to the unittest to match the new
list of parameters.

Change-Id: Id9e025552aee323e95d50aa9798a964510710fdd

Review URL: http://codereview.chromium.org/6851023
diff --git a/dm-bht.c b/dm-bht.c
index e3da9c5..72af2a7 100644
--- a/dm-bht.c
+++ b/dm-bht.c
@@ -20,6 +20,7 @@
 #include <linux/dm-bht.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/mm_types.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>  /* k*alloc */
 #include <linux/string.h>  /* memset */
@@ -95,24 +96,14 @@
 /**
  * dm_bht_compute_hash: hashes a page of data
  */
-static int dm_bht_compute_hash(struct dm_bht *bht, const void *block,
-			       u8 *digest)
+static int dm_bht_compute_hash(struct dm_bht *bht, struct page *pg,
+			       unsigned int offset, u8 *digest)
 {
 	struct hash_desc *hash_desc = &bht->hash_desc[smp_processor_id()];
 	struct scatterlist sg;
 
-	/* TODO(msb): Once we supporting block_size < PAGE_SIZE, change this to:
-	 *            offset_into_page + length < page_size
-	 * For now just check that block is page-aligned.
-	 */
-	/*
-	 * TODO(msb): Re-enable once user-space code is modified to use
-	 *            aligned buffers.
-	 * BUG_ON(!IS_ALIGNED((uintptr_t)block, PAGE_SIZE));
-	 */
-
 	sg_init_table(&sg, 1);
-	sg_set_buf(&sg, block, PAGE_SIZE);
+	sg_set_page(&sg, pg, PAGE_SIZE, offset);
 	/* Note, this is synchronous. */
 	if (crypto_hash_init(hash_desc)) {
 		DMCRIT("failed to reinitialize crypto hash (proc:%d)",
@@ -653,7 +644,7 @@
  * Verifies the path. Returns 0 on ok.
  */
 static int dm_bht_verify_path(struct dm_bht *bht, unsigned int block_index,
-			      const void *block)
+			      struct page *pg, unsigned int offset)
 {
 	unsigned int depth = bht->depth;
 	struct dm_bht_entry *entry;
@@ -674,14 +665,15 @@
 		BUG_ON(state < DM_BHT_ENTRY_READY);
 		node = dm_bht_get_node(bht, entry, depth, block_index);
 
-		if (dm_bht_compute_hash(bht, block, digest) ||
+		if (dm_bht_compute_hash(bht, pg, offset, digest) ||
 		    dm_bht_compare_hash(bht, digest, node))
 			goto mismatch;
 
 		/* Keep the containing block of hashes to be verified in the
 		 * next pass.
 		 */
-		block = entry->nodes;
+		pg = virt_to_page(entry->nodes);
+		offset = 0;
 	} while (--depth > 0 && state != DM_BHT_ENTRY_VERIFIED);
 
 	/* Mark path to leaf as verified. */
@@ -776,7 +768,7 @@
 		return 1;
 	}
 
-	dm_bht_compute_hash(bht, block_data,
+	dm_bht_compute_hash(bht, virt_to_page(block_data), 0,
 			    dm_bht_node(bht, entry, node_index));
 	return 0;
 }
@@ -846,10 +838,10 @@
 			if (count == 0)
 				count = bht->node_count;
 			for (j = 0; j < count; j++, child++) {
-				u8 *block = child->nodes;
+				struct page *pg = virt_to_page(child->nodes);
 				u8 *digest = dm_bht_node(bht, entry, j);
 
-				r = dm_bht_compute_hash(bht, block, digest);
+				r = dm_bht_compute_hash(bht, pg, 0, digest);
 				if (r) {
 					DMERR("Failed to update (d=%u,i=%u)",
 					      depth, i);
@@ -1026,10 +1018,12 @@
  * should return similarly.
  */
 int dm_bht_verify_block(struct dm_bht *bht, unsigned int block_index,
-			const void *block)
+			struct page *pg, unsigned int offset)
 {
 	int r = 0;
 
+	BUG_ON(offset != 0);
+
 	/* Make sure that the root has been verified */
 	if (atomic_read(&bht->root_state) != DM_BHT_ENTRY_VERIFIED) {
 		r = dm_bht_verify_root(bht, dm_bht_compare_hash);
@@ -1040,7 +1034,7 @@
 	}
 
 	/* Now check levels in between */
-	r = dm_bht_verify_path(bht, block_index, block);
+	r = dm_bht_verify_path(bht, block_index, pg, offset);
 	if (r)
 		DMERR_LIMIT("Failed to verify block: %u (%d)", block_index, r);
 
diff --git a/dm-bht.h b/dm-bht.h
index e7269f6..73809d2 100644
--- a/dm-bht.h
+++ b/dm-bht.h
@@ -127,7 +127,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,
-			const void *buf);
+			struct page *pg, unsigned int offset);
 
 /* 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 f0c090c..d7cf61a 100644
--- a/dm-bht_unittest.cc
+++ b/dm-bht_unittest.cc
@@ -172,7 +172,8 @@
 
   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_verify_block(bht_.get(), blocks,
+                                     virt_to_page(zero_page), 0));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
@@ -195,7 +196,8 @@
 
   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_verify_block(bht_.get(), blocks,
+                                     virt_to_page(zero_page), 0));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
@@ -218,7 +220,8 @@
 
   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_verify_block(bht_.get(), blocks,
+                                     virt_to_page(zero_page), 0));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
@@ -241,7 +244,8 @@
 
   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_verify_block(bht_.get(), blocks,
+                                     virt_to_page(zero_page), 0));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
@@ -264,7 +268,8 @@
 
   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_verify_block(bht_.get(), blocks,
+                                     virt_to_page(zero_page), 0));
   }
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
@@ -295,23 +300,25 @@
   EXPECT_EQ(dm_bht_store_block(bht_.get(), kBadBlock, bad_hash_block), 0);
 
   // Attempt to verify both the bad block and all the neighbors.
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 1, zero_page), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 1,
+                                virt_to_page(zero_page), 0), 0);
 
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 2, zero_page), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + 2,
+                                virt_to_page(zero_page), 0), 0);
 
   EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock + (bht_->node_count / 2),
-                                zero_page),
-            0);
+                                virt_to_page(zero_page), 0), 0);
 
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock, zero_page), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), kBadBlock,
+                                virt_to_page(zero_page), 0), 0);
 
   // Verify that the prior entry is untouched and still safe
-  EXPECT_EQ(dm_bht_verify_block(bht_.get(), kBadBlock - 1, zero_page), 0);
+  EXPECT_EQ(dm_bht_verify_block(bht_.get(), kBadBlock - 1,
+                                virt_to_page(zero_page), 0), 0);
 
   // Same for the next entry
   EXPECT_EQ(dm_bht_verify_block(bht_.get(), kBadBlock + bht_->node_count,
-                                zero_page),
-            0);
+                                virt_to_page(zero_page), 0), 0);
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
   free(bad_hash_block);
@@ -332,12 +339,12 @@
   memset(bad_page, 'A', PAGE_SIZE);
 
 
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), 0, bad_page), 0);
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), 127, bad_page), 0);
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), 128, bad_page), 0);
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), 255, bad_page), 0);
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), 256, bad_page), 0);
-  EXPECT_LT(dm_bht_verify_block(bht_.get(), 383, bad_page), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 0, virt_to_page(bad_page), 0), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 127, virt_to_page(bad_page), 0), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 128, virt_to_page(bad_page), 0), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 255, virt_to_page(bad_page), 0), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 256, virt_to_page(bad_page), 0), 0);
+  EXPECT_LT(dm_bht_verify_block(bht_.get(), 383, virt_to_page(bad_page), 0), 0);
 
   EXPECT_EQ(0, dm_bht_destroy(bht_.get()));
   free(bad_page);
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/include/linux/mm_types.h