18
18
19
19
#include <linux/module.h>
20
20
#include <linux/device-mapper.h>
21
+ #include <linux/reboot.h>
21
22
#include <crypto/hash.h>
22
23
23
24
#define DM_MSG_PREFIX "verity"
24
25
26
+ #define DM_VERITY_ENV_LENGTH 42
27
+ #define DM_VERITY_ENV_VAR_NAME "DM_VERITY_ERR_BLOCK_NR"
28
+
25
29
#define DM_VERITY_IO_VEC_INLINE 16
26
30
#define DM_VERITY_MEMPOOL_SIZE 4
27
31
#define DM_VERITY_DEFAULT_PREFETCH_SIZE 262144
28
32
29
33
#define DM_VERITY_MAX_LEVELS 63
34
+ #define DM_VERITY_MAX_CORRUPTED_ERRS 100
35
+
36
+ #define DM_VERITY_OPT_LOGGING "ignore_corruption"
37
+ #define DM_VERITY_OPT_RESTART "restart_on_corruption"
30
38
31
39
static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE ;
32
40
33
41
module_param_named (prefetch_cluster , dm_verity_prefetch_cluster , uint , S_IRUGO | S_IWUSR );
34
42
43
+ enum verity_mode {
44
+ DM_VERITY_MODE_EIO ,
45
+ DM_VERITY_MODE_LOGGING ,
46
+ DM_VERITY_MODE_RESTART
47
+ };
48
+
49
+ enum verity_block_type {
50
+ DM_VERITY_BLOCK_TYPE_DATA ,
51
+ DM_VERITY_BLOCK_TYPE_METADATA
52
+ };
53
+
35
54
struct dm_verity {
36
55
struct dm_dev * data_dev ;
37
56
struct dm_dev * hash_dev ;
@@ -54,6 +73,8 @@ struct dm_verity {
54
73
unsigned digest_size ; /* digest size for the current hash algorithm */
55
74
unsigned shash_descsize ;/* the size of temporary space for crypto */
56
75
int hash_failed ; /* set to 1 if hash of any block failed */
76
+ enum verity_mode mode ; /* mode for handling verification errors */
77
+ unsigned corrupted_errs ;/* Number of errors for corrupted blocks */
57
78
58
79
mempool_t * vec_mempool ; /* mempool of bio vector */
59
80
@@ -174,6 +195,57 @@ static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
174
195
* offset = idx << (v -> hash_dev_block_bits - v -> hash_per_block_bits );
175
196
}
176
197
198
+ /*
199
+ * Handle verification errors.
200
+ */
201
+ static int verity_handle_err (struct dm_verity * v , enum verity_block_type type ,
202
+ unsigned long long block )
203
+ {
204
+ char verity_env [DM_VERITY_ENV_LENGTH ];
205
+ char * envp [] = { verity_env , NULL };
206
+ const char * type_str = "" ;
207
+ struct mapped_device * md = dm_table_get_md (v -> ti -> table );
208
+
209
+ /* Corruption should be visible in device status in all modes */
210
+ v -> hash_failed = 1 ;
211
+
212
+ if (v -> corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS )
213
+ goto out ;
214
+
215
+ v -> corrupted_errs ++ ;
216
+
217
+ switch (type ) {
218
+ case DM_VERITY_BLOCK_TYPE_DATA :
219
+ type_str = "data" ;
220
+ break ;
221
+ case DM_VERITY_BLOCK_TYPE_METADATA :
222
+ type_str = "metadata" ;
223
+ break ;
224
+ default :
225
+ BUG ();
226
+ }
227
+
228
+ DMERR ("%s: %s block %llu is corrupted" , v -> data_dev -> name , type_str ,
229
+ block );
230
+
231
+ if (v -> corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS )
232
+ DMERR ("%s: reached maximum errors" , v -> data_dev -> name );
233
+
234
+ snprintf (verity_env , DM_VERITY_ENV_LENGTH , "%s=%d,%llu" ,
235
+ DM_VERITY_ENV_VAR_NAME , type , block );
236
+
237
+ kobject_uevent_env (& disk_to_dev (dm_disk (md ))-> kobj , KOBJ_CHANGE , envp );
238
+
239
+ out :
240
+ if (v -> mode == DM_VERITY_MODE_LOGGING )
241
+ return 0 ;
242
+
243
+ if (v -> mode == DM_VERITY_MODE_RESTART )
244
+ kernel_restart ("dm-verity device corrupted" );
245
+
246
+ return 1 ;
247
+ }
248
+
177
249
/*
178
250
* Verify hash of a metadata block pertaining to the specified data block
179
251
* ("block" argument) at a specified level ("level" argument).
@@ -251,11 +323,11 @@ static int verity_verify_level(struct dm_verity_io *io, sector_t block,
251
323
goto release_ret_r ;
252
324
}
253
325
if (unlikely (memcmp (result , io_want_digest (v , io ), v -> digest_size ))) {
254
- DMERR_LIMIT ( "metadata block %llu is corrupted" ,
255
- ( unsigned long long ) hash_block );
256
- v -> hash_failed = 1 ;
257
- r = - EIO ;
258
- goto release_ret_r ;
326
+ if ( verity_handle_err ( v , DM_VERITY_BLOCK_TYPE_METADATA ,
327
+ hash_block )) {
328
+ r = - EIO ;
329
+ goto release_ret_r ;
330
+ }
259
331
} else
260
332
aux -> hash_verified = 1 ;
261
333
}
@@ -367,10 +439,9 @@ static int verity_verify_io(struct dm_verity_io *io)
367
439
return r ;
368
440
}
369
441
if (unlikely (memcmp (result , io_want_digest (v , io ), v -> digest_size ))) {
370
- DMERR_LIMIT ("data block %llu is corrupted" ,
371
- (unsigned long long )(io -> block + b ));
372
- v -> hash_failed = 1 ;
373
- return - EIO ;
442
+ if (verity_handle_err (v , DM_VERITY_BLOCK_TYPE_DATA ,
443
+ io -> block + b ))
444
+ return - EIO ;
374
445
}
375
446
}
376
447
@@ -546,6 +617,19 @@ static void verity_status(struct dm_target *ti, status_type_t type,
546
617
else
547
618
for (x = 0 ; x < v -> salt_size ; x ++ )
548
619
DMEMIT ("%02x" , v -> salt [x ]);
620
+ if (v -> mode != DM_VERITY_MODE_EIO ) {
621
+ DMEMIT (" 1 " );
622
+ switch (v -> mode ) {
623
+ case DM_VERITY_MODE_LOGGING :
624
+ DMEMIT (DM_VERITY_OPT_LOGGING );
625
+ break ;
626
+ case DM_VERITY_MODE_RESTART :
627
+ DMEMIT (DM_VERITY_OPT_RESTART );
628
+ break ;
629
+ default :
630
+ BUG ();
631
+ }
632
+ }
549
633
break ;
550
634
}
551
635
}
@@ -647,13 +731,19 @@ static void verity_dtr(struct dm_target *ti)
647
731
static int verity_ctr (struct dm_target * ti , unsigned argc , char * * argv )
648
732
{
649
733
struct dm_verity * v ;
650
- unsigned num ;
734
+ struct dm_arg_set as ;
735
+ const char * opt_string ;
736
+ unsigned int num , opt_params ;
651
737
unsigned long long num_ll ;
652
738
int r ;
653
739
int i ;
654
740
sector_t hash_position ;
655
741
char dummy ;
656
742
743
+ static struct dm_arg _args [] = {
744
+ {0 , 1 , "Invalid number of feature args" },
745
+ };
746
+
657
747
v = kzalloc (sizeof (struct dm_verity ), GFP_KERNEL );
658
748
if (!v ) {
659
749
ti -> error = "Cannot allocate verity structure" ;
@@ -668,8 +758,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
668
758
goto bad ;
669
759
}
670
760
671
- if (argc != 10 ) {
672
- ti -> error = "Invalid argument count: exactly 10 arguments required " ;
761
+ if (argc < 10 ) {
762
+ ti -> error = "Not enough arguments" ;
673
763
r = - EINVAL ;
674
764
goto bad ;
675
765
}
@@ -790,6 +880,39 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
790
880
}
791
881
}
792
882
883
+ argv += 10 ;
884
+ argc -= 10 ;
885
+
886
+ /* Optional parameters */
887
+ if (argc ) {
888
+ as .argc = argc ;
889
+ as .argv = argv ;
890
+
891
+ r = dm_read_arg_group (_args , & as , & opt_params , & ti -> error );
892
+ if (r )
893
+ goto bad ;
894
+
895
+ while (opt_params ) {
896
+ opt_params -- ;
897
+ opt_string = dm_shift_arg (& as );
898
+ if (!opt_string ) {
899
+ ti -> error = "Not enough feature arguments" ;
900
+ r = - EINVAL ;
901
+ goto bad ;
902
+ }
903
+
904
+ if (!strcasecmp (opt_string , DM_VERITY_OPT_LOGGING ))
905
+ v -> mode = DM_VERITY_MODE_LOGGING ;
906
+ else if (!strcasecmp (opt_string , DM_VERITY_OPT_RESTART ))
907
+ v -> mode = DM_VERITY_MODE_RESTART ;
908
+ else {
909
+ ti -> error = "Invalid feature arguments" ;
910
+ r = - EINVAL ;
911
+ goto bad ;
912
+ }
913
+ }
914
+ }
915
+
793
916
v -> hash_per_block_bits =
794
917
__fls ((1 << v -> hash_dev_block_bits ) / v -> digest_size );
795
918
0 commit comments