dm-verity-avb.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * Copyright (C) 2017 Google.
  3. *
  4. * This file is released under the GPLv2.
  5. *
  6. * Based on drivers/md/dm-verity-chromeos.c
  7. */
  8. #include <linux/device-mapper.h>
  9. #include <linux/module.h>
  10. #include <linux/mount.h>
  11. #define DM_MSG_PREFIX "verity-avb"
  12. /* Set via module parameters. */
  13. static char avb_vbmeta_device[64];
  14. static char avb_invalidate_on_error[4];
  15. static void invalidate_vbmeta_endio(struct bio *bio)
  16. {
  17. if (bio->bi_status)
  18. DMERR("invalidate_vbmeta_endio: error %d", bio->bi_status);
  19. complete(bio->bi_private);
  20. }
  21. static int invalidate_vbmeta_submit(struct bio *bio,
  22. struct block_device *bdev,
  23. int op, int access_last_sector,
  24. struct page *page)
  25. {
  26. DECLARE_COMPLETION_ONSTACK(wait);
  27. bio->bi_private = &wait;
  28. bio->bi_end_io = invalidate_vbmeta_endio;
  29. bio_set_dev(bio, bdev);
  30. bio_set_op_attrs(bio, op, REQ_SYNC);
  31. bio->bi_iter.bi_sector = 0;
  32. if (access_last_sector) {
  33. sector_t last_sector;
  34. last_sector = (i_size_read(bdev->bd_inode)>>SECTOR_SHIFT) - 1;
  35. bio->bi_iter.bi_sector = last_sector;
  36. }
  37. if (!bio_add_page(bio, page, PAGE_SIZE, 0)) {
  38. DMERR("invalidate_vbmeta_submit: bio_add_page error");
  39. return -EIO;
  40. }
  41. submit_bio(bio);
  42. /* Wait up to 2 seconds for completion or fail. */
  43. if (!wait_for_completion_timeout(&wait, msecs_to_jiffies(2000)))
  44. return -EIO;
  45. return 0;
  46. }
  47. static int invalidate_vbmeta(dev_t vbmeta_devt)
  48. {
  49. int ret = 0;
  50. struct block_device *bdev;
  51. struct bio *bio;
  52. struct page *page;
  53. fmode_t dev_mode;
  54. /* Ensure we do synchronous unblocked I/O. We may also need
  55. * sync_bdev() on completion, but it really shouldn't.
  56. */
  57. int access_last_sector = 0;
  58. DMINFO("invalidate_vbmeta: acting on device %d:%d",
  59. MAJOR(vbmeta_devt), MINOR(vbmeta_devt));
  60. /* First we open the device for reading. */
  61. dev_mode = FMODE_READ | FMODE_EXCL;
  62. bdev = blkdev_get_by_dev(vbmeta_devt, dev_mode,
  63. invalidate_vbmeta);
  64. if (IS_ERR(bdev)) {
  65. DMERR("invalidate_kernel: could not open device for reading");
  66. dev_mode = 0;
  67. ret = -ENOENT;
  68. goto failed_to_read;
  69. }
  70. bio = bio_alloc(GFP_NOIO, 1);
  71. if (!bio) {
  72. ret = -ENOMEM;
  73. goto failed_bio_alloc;
  74. }
  75. page = alloc_page(GFP_NOIO);
  76. if (!page) {
  77. ret = -ENOMEM;
  78. goto failed_to_alloc_page;
  79. }
  80. access_last_sector = 0;
  81. ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_READ,
  82. access_last_sector, page);
  83. if (ret) {
  84. DMERR("invalidate_vbmeta: error reading");
  85. goto failed_to_submit_read;
  86. }
  87. /* We have a page. Let's make sure it looks right. */
  88. if (memcmp("AVB0", page_address(page), 4) == 0) {
  89. /* Stamp it. */
  90. memcpy(page_address(page), "AVE0", 4);
  91. DMINFO("invalidate_vbmeta: found vbmeta partition");
  92. } else {
  93. /* Could be this is on a AVB footer, check. Also, since the
  94. * AVB footer is in the last 64 bytes, adjust for the fact that
  95. * we're dealing with 512-byte sectors.
  96. */
  97. size_t offset = (1<<SECTOR_SHIFT) - 64;
  98. access_last_sector = 1;
  99. ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_READ,
  100. access_last_sector, page);
  101. if (ret) {
  102. DMERR("invalidate_vbmeta: error reading");
  103. goto failed_to_submit_read;
  104. }
  105. if (memcmp("AVBf", page_address(page) + offset, 4) != 0) {
  106. DMERR("invalidate_vbmeta on non-vbmeta partition");
  107. ret = -EINVAL;
  108. goto invalid_header;
  109. }
  110. /* Stamp it. */
  111. memcpy(page_address(page) + offset, "AVE0", 4);
  112. DMINFO("invalidate_vbmeta: found vbmeta footer partition");
  113. }
  114. /* Now rewrite the changed page - the block dev was being
  115. * changed on read. Let's reopen here.
  116. */
  117. blkdev_put(bdev, dev_mode);
  118. dev_mode = FMODE_WRITE | FMODE_EXCL;
  119. bdev = blkdev_get_by_dev(vbmeta_devt, dev_mode,
  120. invalidate_vbmeta);
  121. if (IS_ERR(bdev)) {
  122. DMERR("invalidate_vbmeta: could not open device for writing");
  123. dev_mode = 0;
  124. ret = -ENOENT;
  125. goto failed_to_write;
  126. }
  127. /* We re-use the same bio to do the write after the read. Need to reset
  128. * it to initialize bio->bi_remaining.
  129. */
  130. bio_reset(bio);
  131. ret = invalidate_vbmeta_submit(bio, bdev, REQ_OP_WRITE,
  132. access_last_sector, page);
  133. if (ret) {
  134. DMERR("invalidate_vbmeta: error writing");
  135. goto failed_to_submit_write;
  136. }
  137. DMERR("invalidate_vbmeta: completed.");
  138. ret = 0;
  139. failed_to_submit_write:
  140. failed_to_write:
  141. invalid_header:
  142. __free_page(page);
  143. failed_to_submit_read:
  144. /* Technically, we'll leak a page with the pending bio, but
  145. * we're about to reboot anyway.
  146. */
  147. failed_to_alloc_page:
  148. bio_put(bio);
  149. failed_bio_alloc:
  150. if (dev_mode)
  151. blkdev_put(bdev, dev_mode);
  152. failed_to_read:
  153. return ret;
  154. }
  155. void dm_verity_avb_error_handler(void)
  156. {
  157. dev_t dev;
  158. DMINFO("AVB error handler called for %s", avb_vbmeta_device);
  159. if (strcmp(avb_invalidate_on_error, "yes") != 0) {
  160. DMINFO("Not configured to invalidate");
  161. return;
  162. }
  163. if (avb_vbmeta_device[0] == '\0') {
  164. DMERR("avb_vbmeta_device parameter not set");
  165. goto fail_no_dev;
  166. }
  167. dev = name_to_dev_t(avb_vbmeta_device);
  168. if (!dev) {
  169. DMERR("No matching partition for device: %s",
  170. avb_vbmeta_device);
  171. goto fail_no_dev;
  172. }
  173. invalidate_vbmeta(dev);
  174. fail_no_dev:
  175. ;
  176. }
  177. static int __init dm_verity_avb_init(void)
  178. {
  179. DMINFO("AVB error handler initialized with vbmeta device: %s",
  180. avb_vbmeta_device);
  181. return 0;
  182. }
  183. static void __exit dm_verity_avb_exit(void)
  184. {
  185. }
  186. module_init(dm_verity_avb_init);
  187. module_exit(dm_verity_avb_exit);
  188. MODULE_AUTHOR("David Zeuthen <zeuthen@google.com>");
  189. MODULE_DESCRIPTION("AVB-specific error handler for dm-verity");
  190. MODULE_LICENSE("GPL");
  191. /* Declare parameter with no module prefix */
  192. #undef MODULE_PARAM_PREFIX
  193. #define MODULE_PARAM_PREFIX "androidboot.vbmeta."
  194. module_param_string(device, avb_vbmeta_device, sizeof(avb_vbmeta_device), 0);
  195. module_param_string(invalidate_on_error, avb_invalidate_on_error,
  196. sizeof(avb_invalidate_on_error), 0);