aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSami Tolvanen <samitolvanen@google.com>2015-12-03 09:26:31 -0500
committerMike Snitzer <snitzer@redhat.com>2015-12-10 10:39:03 -0500
commit0cc37c2df4fa0aa702f9662edce4b7ce12c86b7a (patch)
treece34d33da52e65c3907034f294af01f7dd96ad0b
parenta739ff3f543afbb4a041c16cd0182c8e8d366e70 (diff)
dm verity: add ignore_zero_blocks feature
If ignore_zero_blocks is enabled dm-verity will return zeroes for blocks matching a zero hash without validating the content. Signed-off-by: Sami Tolvanen <samitolvanen@google.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
-rw-r--r--Documentation/device-mapper/verity.txt5
-rw-r--r--drivers/md/dm-verity-fec.c8
-rw-r--r--drivers/md/dm-verity-target.c87
-rw-r--r--drivers/md/dm-verity.h3
4 files changed, 93 insertions, 10 deletions
diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
index d602c801ff59..89fd8f9a259f 100644
--- a/Documentation/device-mapper/verity.txt
+++ b/Documentation/device-mapper/verity.txt
@@ -79,6 +79,11 @@ restart_on_corruption
79 not compatible with ignore_corruption and requires user space support to 79 not compatible with ignore_corruption and requires user space support to
80 avoid restart loops. 80 avoid restart loops.
81 81
82ignore_zero_blocks
83 Do not verify blocks that are expected to contain zeroes and always return
84 zeroes instead. This may be useful if the partition contains unused blocks
85 that are not guaranteed to contain zeroes.
86
82use_fec_from_device <fec_dev> 87use_fec_from_device <fec_dev>
83 Use forward error correction (FEC) to recover from corruption if hash 88 Use forward error correction (FEC) to recover from corruption if hash
84 verification fails. Use encoding data from the specified device. This 89 verification fails. Use encoding data from the specified device. This
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
index 88143d36a1d2..1cc10c4de701 100644
--- a/drivers/md/dm-verity-fec.c
+++ b/drivers/md/dm-verity-fec.c
@@ -205,6 +205,7 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
205 u64 rsb, u64 target, unsigned block_offset, 205 u64 rsb, u64 target, unsigned block_offset,
206 int *neras) 206 int *neras)
207{ 207{
208 bool is_zero;
208 int i, j, target_index = -1; 209 int i, j, target_index = -1;
209 struct dm_buffer *buf; 210 struct dm_buffer *buf;
210 struct dm_bufio_client *bufio; 211 struct dm_bufio_client *bufio;
@@ -264,7 +265,12 @@ static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
264 265
265 /* locate erasures if the block is on the data device */ 266 /* locate erasures if the block is on the data device */
266 if (bufio == v->fec->data_bufio && 267 if (bufio == v->fec->data_bufio &&
267 verity_hash_for_block(v, io, block, want_digest) == 0) { 268 verity_hash_for_block(v, io, block, want_digest,
269 &is_zero) == 0) {
270 /* skip known zero blocks entirely */
271 if (is_zero)
272 continue;
273
268 /* 274 /*
269 * skip if we have already found the theoretical 275 * skip if we have already found the theoretical
270 * maximum number (i.e. fec->roots) of erasures 276 * maximum number (i.e. fec->roots) of erasures
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 4f90ec2c6b7a..5c5d30cb6ec5 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -31,8 +31,9 @@
31 31
32#define DM_VERITY_OPT_LOGGING "ignore_corruption" 32#define DM_VERITY_OPT_LOGGING "ignore_corruption"
33#define DM_VERITY_OPT_RESTART "restart_on_corruption" 33#define DM_VERITY_OPT_RESTART "restart_on_corruption"
34#define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
34 35
35#define DM_VERITY_OPTS_MAX (1 + DM_VERITY_OPTS_FEC) 36#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC)
36 37
37static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE; 38static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
38 39
@@ -309,10 +310,9 @@ release_ret_r:
309 * of the hash tree if necessary. 310 * of the hash tree if necessary.
310 */ 311 */
311int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, 312int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
312 sector_t block, u8 *digest) 313 sector_t block, u8 *digest, bool *is_zero)
313{ 314{
314 int i; 315 int r = 0, i;
315 int r;
316 316
317 if (likely(v->levels)) { 317 if (likely(v->levels)) {
318 /* 318 /*
@@ -324,7 +324,7 @@ int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
324 */ 324 */
325 r = verity_verify_level(v, io, block, 0, true, digest); 325 r = verity_verify_level(v, io, block, 0, true, digest);
326 if (likely(r <= 0)) 326 if (likely(r <= 0))
327 return r; 327 goto out;
328 } 328 }
329 329
330 memcpy(digest, v->root_digest, v->digest_size); 330 memcpy(digest, v->root_digest, v->digest_size);
@@ -332,10 +332,15 @@ int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
332 for (i = v->levels - 1; i >= 0; i--) { 332 for (i = v->levels - 1; i >= 0; i--) {
333 r = verity_verify_level(v, io, block, i, false, digest); 333 r = verity_verify_level(v, io, block, i, false, digest);
334 if (unlikely(r)) 334 if (unlikely(r))
335 return r; 335 goto out;
336 } 336 }
337out:
338 if (!r && v->zero_digest)
339 *is_zero = !memcmp(v->zero_digest, digest, v->digest_size);
340 else
341 *is_zero = false;
337 342
338 return 0; 343 return r;
339} 344}
340 345
341/* 346/*
@@ -382,11 +387,19 @@ static int verity_bv_hash_update(struct dm_verity *v, struct dm_verity_io *io,
382 return verity_hash_update(v, verity_io_hash_desc(v, io), data, len); 387 return verity_hash_update(v, verity_io_hash_desc(v, io), data, len);
383} 388}
384 389
390static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io,
391 u8 *data, size_t len)
392{
393 memset(data, 0, len);
394 return 0;
395}
396
385/* 397/*
386 * Verify one "dm_verity_io" structure. 398 * Verify one "dm_verity_io" structure.
387 */ 399 */
388static int verity_verify_io(struct dm_verity_io *io) 400static int verity_verify_io(struct dm_verity_io *io)
389{ 401{
402 bool is_zero;
390 struct dm_verity *v = io->v; 403 struct dm_verity *v = io->v;
391 struct bvec_iter start; 404 struct bvec_iter start;
392 unsigned b; 405 unsigned b;
@@ -396,10 +409,24 @@ static int verity_verify_io(struct dm_verity_io *io)
396 struct shash_desc *desc = verity_io_hash_desc(v, io); 409 struct shash_desc *desc = verity_io_hash_desc(v, io);
397 410
398 r = verity_hash_for_block(v, io, io->block + b, 411 r = verity_hash_for_block(v, io, io->block + b,
399 verity_io_want_digest(v, io)); 412 verity_io_want_digest(v, io),
413 &is_zero);
400 if (unlikely(r < 0)) 414 if (unlikely(r < 0))
401 return r; 415 return r;
402 416
417 if (is_zero) {
418 /*
419 * If we expect a zero block, don't validate, just
420 * return zeros.
421 */
422 r = verity_for_bv_block(v, io, &io->iter,
423 verity_bv_zero);
424 if (unlikely(r < 0))
425 return r;
426
427 continue;
428 }
429
403 r = verity_hash_init(v, desc); 430 r = verity_hash_init(v, desc);
404 if (unlikely(r < 0)) 431 if (unlikely(r < 0))
405 return r; 432 return r;
@@ -604,6 +631,8 @@ static void verity_status(struct dm_target *ti, status_type_t type,
604 args++; 631 args++;
605 if (verity_fec_is_enabled(v)) 632 if (verity_fec_is_enabled(v))
606 args += DM_VERITY_OPTS_FEC; 633 args += DM_VERITY_OPTS_FEC;
634 if (v->zero_digest)
635 args++;
607 if (!args) 636 if (!args)
608 return; 637 return;
609 DMEMIT(" %u", args); 638 DMEMIT(" %u", args);
@@ -620,6 +649,8 @@ static void verity_status(struct dm_target *ti, status_type_t type,
620 BUG(); 649 BUG();
621 } 650 }
622 } 651 }
652 if (v->zero_digest)
653 DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
623 sz = verity_fec_status_table(v, sz, result, maxlen); 654 sz = verity_fec_status_table(v, sz, result, maxlen);
624 break; 655 break;
625 } 656 }
@@ -671,6 +702,7 @@ static void verity_dtr(struct dm_target *ti)
671 702
672 kfree(v->salt); 703 kfree(v->salt);
673 kfree(v->root_digest); 704 kfree(v->root_digest);
705 kfree(v->zero_digest);
674 706
675 if (v->tfm) 707 if (v->tfm)
676 crypto_free_shash(v->tfm); 708 crypto_free_shash(v->tfm);
@@ -688,6 +720,37 @@ static void verity_dtr(struct dm_target *ti)
688 kfree(v); 720 kfree(v);
689} 721}
690 722
723static int verity_alloc_zero_digest(struct dm_verity *v)
724{
725 int r = -ENOMEM;
726 struct shash_desc *desc;
727 u8 *zero_data;
728
729 v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL);
730
731 if (!v->zero_digest)
732 return r;
733
734 desc = kmalloc(v->shash_descsize, GFP_KERNEL);
735
736 if (!desc)
737 return r; /* verity_dtr will free zero_digest */
738
739 zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL);
740
741 if (!zero_data)
742 goto out;
743
744 r = verity_hash(v, desc, zero_data, 1 << v->data_dev_block_bits,
745 v->zero_digest);
746
747out:
748 kfree(desc);
749 kfree(zero_data);
750
751 return r;
752}
753
691static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v) 754static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
692{ 755{
693 int r; 756 int r;
@@ -718,6 +781,14 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
718 v->mode = DM_VERITY_MODE_RESTART; 781 v->mode = DM_VERITY_MODE_RESTART;
719 continue; 782 continue;
720 783
784 } else if (!strcasecmp(arg_name, DM_VERITY_OPT_IGN_ZEROES)) {
785 r = verity_alloc_zero_digest(v);
786 if (r) {
787 ti->error = "Cannot allocate zero digest";
788 return r;
789 }
790 continue;
791
721 } else if (verity_is_fec_opt_arg(arg_name)) { 792 } else if (verity_is_fec_opt_arg(arg_name)) {
722 r = verity_fec_parse_opt_args(as, v, &argc, arg_name); 793 r = verity_fec_parse_opt_args(as, v, &argc, arg_name);
723 if (r) 794 if (r)
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index 8e853722f6c6..fb419f422d73 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -40,6 +40,7 @@ struct dm_verity {
40 struct crypto_shash *tfm; 40 struct crypto_shash *tfm;
41 u8 *root_digest; /* digest of the root block */ 41 u8 *root_digest; /* digest of the root block */
42 u8 *salt; /* salt: its size is salt_size */ 42 u8 *salt; /* salt: its size is salt_size */
43 u8 *zero_digest; /* digest for a zero block */
43 unsigned salt_size; 44 unsigned salt_size;
44 sector_t data_start; /* data offset in 512-byte sectors */ 45 sector_t data_start; /* data offset in 512-byte sectors */
45 sector_t hash_start; /* hash start in blocks */ 46 sector_t hash_start; /* hash start in blocks */
@@ -123,6 +124,6 @@ extern int verity_hash(struct dm_verity *v, struct shash_desc *desc,
123 const u8 *data, size_t len, u8 *digest); 124 const u8 *data, size_t len, u8 *digest);
124 125
125extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io, 126extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
126 sector_t block, u8 *digest); 127 sector_t block, u8 *digest, bool *is_zero);
127 128
128#endif /* DM_VERITY_H */ 129#endif /* DM_VERITY_H */