hc
2024-10-12 a5969cabbb4660eab42b6ef0412cbbd1200cf14d
kernel/drivers/md/dm-verity-target.c
....@@ -1,11 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2012 Red Hat, Inc.
34 *
45 * Author: Mikulas Patocka <mpatocka@redhat.com>
56 *
67 * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
7
- *
8
- * This file is released under the GPLv2.
98 *
109 * In the file "/sys/module/dm_verity/parameters/prefetch_cluster" you can set
1110 * default prefetch value. Data are read in "prefetch_cluster" chunks from the
....@@ -16,7 +15,7 @@
1615
1716 #include "dm-verity.h"
1817 #include "dm-verity-fec.h"
19
-
18
+#include "dm-verity-verify-sig.h"
2019 #include <linux/module.h>
2120 #include <linux/reboot.h>
2221
....@@ -31,10 +30,12 @@
3130
3231 #define DM_VERITY_OPT_LOGGING "ignore_corruption"
3332 #define DM_VERITY_OPT_RESTART "restart_on_corruption"
33
+#define DM_VERITY_OPT_PANIC "panic_on_corruption"
3434 #define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
3535 #define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once"
3636
37
-#define DM_VERITY_OPTS_MAX (3 + DM_VERITY_OPTS_FEC)
37
+#define DM_VERITY_OPTS_MAX (3 + DM_VERITY_OPTS_FEC + \
38
+ DM_VERITY_ROOT_HASH_VERIFICATION_OPTS)
3839
3940 static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
4041
....@@ -251,12 +252,11 @@
251252 if (v->mode == DM_VERITY_MODE_LOGGING)
252253 return 0;
253254
254
- if (v->mode == DM_VERITY_MODE_RESTART) {
255
-#ifdef CONFIG_DM_VERITY_AVB
256
- dm_verity_avb_error_handler();
257
-#endif
255
+ if (v->mode == DM_VERITY_MODE_RESTART)
258256 kernel_restart("dm-verity device corrupted");
259
- }
257
+
258
+ if (v->mode == DM_VERITY_MODE_PANIC)
259
+ panic("dm-verity device corrupted");
260260
261261 return 1;
262262 }
....@@ -482,7 +482,7 @@
482482 sector_t cur_block = io->block + b;
483483 struct ahash_request *req = verity_io_hash_req(v, io);
484484
485
- if (v->validated_blocks &&
485
+ if (v->validated_blocks && bio->bi_status == BLK_STS_OK &&
486486 likely(test_bit(cur_block, v->validated_blocks))) {
487487 verity_bv_skip_block(v, io, &io->iter);
488488 continue;
....@@ -538,7 +538,7 @@
538538 return -EIO;
539539 }
540540 if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
541
- cur_block))
541
+ cur_block))
542542 return -EIO;
543543 }
544544 }
....@@ -634,7 +634,21 @@
634634
635635 static void verity_submit_prefetch(struct dm_verity *v, struct dm_verity_io *io)
636636 {
637
+ sector_t block = io->block;
638
+ unsigned int n_blocks = io->n_blocks;
637639 struct dm_verity_prefetch_work *pw;
640
+
641
+ if (v->validated_blocks) {
642
+ while (n_blocks && test_bit(block, v->validated_blocks)) {
643
+ block++;
644
+ n_blocks--;
645
+ }
646
+ while (n_blocks && test_bit(block + n_blocks - 1,
647
+ v->validated_blocks))
648
+ n_blocks--;
649
+ if (!n_blocks)
650
+ return;
651
+ }
638652
639653 pw = kmalloc(sizeof(struct dm_verity_prefetch_work),
640654 GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
....@@ -644,8 +658,8 @@
644658
645659 INIT_WORK(&pw->work, verity_prefetch_io);
646660 pw->v = v;
647
- pw->block = io->block;
648
- pw->n_blocks = io->n_blocks;
661
+ pw->block = block;
662
+ pw->n_blocks = n_blocks;
649663 queue_work(v->verify_wq, &pw->work);
650664 }
651665
....@@ -690,7 +704,7 @@
690704
691705 verity_submit_prefetch(v, io);
692706
693
- generic_make_request(bio);
707
+ submit_bio_noacct(bio);
694708
695709 return DM_MAPIO_SUBMITTED;
696710 }
....@@ -737,6 +751,8 @@
737751 args++;
738752 if (v->validated_blocks)
739753 args++;
754
+ if (v->signature_key_desc)
755
+ args += DM_VERITY_ROOT_HASH_VERIFICATION_OPTS;
740756 if (!args)
741757 return;
742758 DMEMIT(" %u", args);
....@@ -749,6 +765,9 @@
749765 case DM_VERITY_MODE_RESTART:
750766 DMEMIT(DM_VERITY_OPT_RESTART);
751767 break;
768
+ case DM_VERITY_MODE_PANIC:
769
+ DMEMIT(DM_VERITY_OPT_PANIC);
770
+ break;
752771 default:
753772 BUG();
754773 }
....@@ -758,6 +777,9 @@
758777 if (v->validated_blocks)
759778 DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE);
760779 sz = verity_fec_status_table(v, sz, result, maxlen);
780
+ if (v->signature_key_desc)
781
+ DMEMIT(" " DM_VERITY_ROOT_HASH_VERIFICATION_OPT_SIG_KEY
782
+ " %s", v->signature_key_desc);
761783 break;
762784 }
763785 }
....@@ -823,6 +845,8 @@
823845
824846 verity_fec_dtr(v);
825847
848
+ kfree(v->signature_key_desc);
849
+
826850 kfree(v);
827851 }
828852
....@@ -878,7 +902,8 @@
878902 return r;
879903 }
880904
881
-static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
905
+static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
906
+ struct dm_verity_sig_opts *verify_args)
882907 {
883908 int r;
884909 unsigned argc;
....@@ -908,6 +933,10 @@
908933 v->mode = DM_VERITY_MODE_RESTART;
909934 continue;
910935
936
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_PANIC)) {
937
+ v->mode = DM_VERITY_MODE_PANIC;
938
+ continue;
939
+
911940 } else if (!strcasecmp(arg_name, DM_VERITY_OPT_IGN_ZEROES)) {
912941 r = verity_alloc_zero_digest(v);
913942 if (r) {
....@@ -927,6 +956,14 @@
927956 if (r)
928957 return r;
929958 continue;
959
+ } else if (verity_verify_is_sig_opt_arg(arg_name)) {
960
+ r = verity_verify_sig_parse_opt_args(as, v,
961
+ verify_args,
962
+ &argc, arg_name);
963
+ if (r)
964
+ return r;
965
+ continue;
966
+
930967 }
931968
932969 ti->error = "Unrecognized verity feature request";
....@@ -953,6 +990,7 @@
953990 static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
954991 {
955992 struct dm_verity *v;
993
+ struct dm_verity_sig_opts verify_args = {0};
956994 struct dm_arg_set as;
957995 unsigned int num;
958996 unsigned long long num_ll;
....@@ -960,6 +998,7 @@
960998 int i;
961999 sector_t hash_position;
9621000 char dummy;
1001
+ char *root_hash_digest_to_validate;
9631002
9641003 v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
9651004 if (!v) {
....@@ -1093,6 +1132,7 @@
10931132 r = -EINVAL;
10941133 goto bad;
10951134 }
1135
+ root_hash_digest_to_validate = argv[8];
10961136
10971137 if (strcmp(argv[9], "-")) {
10981138 v->salt_size = strlen(argv[9]) / 2;
....@@ -1118,19 +1158,20 @@
11181158 as.argc = argc;
11191159 as.argv = argv;
11201160
1121
- r = verity_parse_opt_args(&as, v);
1161
+ r = verity_parse_opt_args(&as, v, &verify_args);
11221162 if (r < 0)
11231163 goto bad;
11241164 }
11251165
1126
-#ifdef CONFIG_DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED
1127
- if (!v->validated_blocks) {
1128
- r = verity_alloc_most_once(v);
1129
- if (r)
1130
- goto bad;
1166
+ /* Root hash signature is a optional parameter*/
1167
+ r = verity_verify_root_hash(root_hash_digest_to_validate,
1168
+ strlen(root_hash_digest_to_validate),
1169
+ verify_args.sig,
1170
+ verify_args.sig_size);
1171
+ if (r < 0) {
1172
+ ti->error = "Root hash verification failed";
1173
+ goto bad;
11311174 }
1132
-#endif
1133
-
11341175 v->hash_per_block_bits =
11351176 __fls((1 << v->hash_dev_block_bits) / v->digest_size);
11361177
....@@ -1178,8 +1219,16 @@
11781219 goto bad;
11791220 }
11801221
1181
- /* WQ_UNBOUND greatly improves performance when running on ramdisk */
1182
- v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
1222
+ /*
1223
+ * Using WQ_HIGHPRI improves throughput and completion latency by
1224
+ * reducing wait times when reading from a dm-verity device.
1225
+ *
1226
+ * Also as required for the "try_verify_in_tasklet" feature: WQ_HIGHPRI
1227
+ * allows verify_wq to preempt softirq since verification in tasklet
1228
+ * will fall-back to using it for error handling (or if the bufio cache
1229
+ * doesn't have required hashes).
1230
+ */
1231
+ v->verify_wq = alloc_workqueue("kverityd", WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
11831232 if (!v->verify_wq) {
11841233 ti->error = "Cannot allocate workqueue";
11851234 r = -ENOMEM;
....@@ -1196,9 +1245,13 @@
11961245 ti->per_io_data_size = roundup(ti->per_io_data_size,
11971246 __alignof__(struct dm_verity_io));
11981247
1248
+ verity_verify_sig_opts_cleanup(&verify_args);
1249
+
11991250 return 0;
12001251
12011252 bad:
1253
+
1254
+ verity_verify_sig_opts_cleanup(&verify_args);
12021255 verity_dtr(ti);
12031256
12041257 return r;
....@@ -1206,7 +1259,9 @@
12061259
12071260 static struct target_type verity_target = {
12081261 .name = "verity",
1209
- .version = {1, 4, 0},
1262
+ .features = DM_TARGET_IMMUTABLE,
1263
+ .version = {1, 7, 0},
1264
+ .features = DM_TARGET_IMMUTABLE,
12101265 .module = THIS_MODULE,
12111266 .ctr = verity_ctr,
12121267 .dtr = verity_dtr,