@@ -481,6 +481,45 @@ static int rewrite_metadata(fec_handle *f, uint64_t offset)
481
481
return raw_pwrite (f, metadata.get (), VERITY_METADATA_SIZE, offset);
482
482
}
483
483
484
+ static int validate_header (const fec_handle *f, const verity_header *header,
485
+ uint64_t offset)
486
+ {
487
+ check (f);
488
+ check (header);
489
+
490
+ if (header->magic != VERITY_MAGIC &&
491
+ header->magic != VERITY_MAGIC_DISABLE) {
492
+ return -1 ;
493
+ }
494
+
495
+ if (header->version != VERITY_VERSION) {
496
+ error (" unsupported verity version %u" , header->version );
497
+ return -1 ;
498
+ }
499
+
500
+ if (header->length < VERITY_MIN_TABLE_SIZE ||
501
+ header->length > VERITY_MAX_TABLE_SIZE) {
502
+ error (" invalid verity table size: %u; expected ["
503
+ stringify (VERITY_MIN_TABLE_SIZE) " , "
504
+ stringify (VERITY_MAX_TABLE_SIZE) " )" , header->length );
505
+ return -1 ;
506
+ }
507
+
508
+ /* signature is skipped, because for our purposes it won't matter from
509
+ where the data originates; the caller of the library is responsible
510
+ for signature verification */
511
+
512
+ if (offset > UINT64_MAX - header->length ) {
513
+ error (" invalid verity table length: %u" , header->length );
514
+ return -1 ;
515
+ } else if (offset + header->length >= f->data_size ) {
516
+ error (" invalid verity table length: %u" , header->length );
517
+ return -1 ;
518
+ }
519
+
520
+ return 0 ;
521
+ }
522
+
484
523
/* attempts to read verity metadata from `f->fd' position `offset'; if in r/w
485
524
mode, rewrites the metadata if it had errors */
486
525
int verity_parse_header (fec_handle *f, uint64_t offset)
@@ -497,55 +536,59 @@ int verity_parse_header(fec_handle *f, uint64_t offset)
497
536
verity_info *v = &f->verity ;
498
537
uint64_t errors = f->errors ;
499
538
500
- if (fec_pread (f, &v->header , sizeof (v->header ), offset) !=
501
- sizeof (v->header )) {
539
+ if (!raw_pread (f, &v->header , sizeof (v->header ), offset)) {
502
540
error (" failed to read verity header: %s" , strerror (errno));
503
541
return -1 ;
504
542
}
505
543
506
- verity_header raw_header;
507
-
508
- if (!raw_pread (f, &raw_header, sizeof (raw_header), offset)) {
509
- error (" failed to read verity header: %s" , strerror (errno));
510
- return -1 ;
511
- }
512
544
/* use raw data to check for the alternative magic, because it will
513
545
be error corrected to VERITY_MAGIC otherwise */
514
- if (raw_header .magic == VERITY_MAGIC_DISABLE) {
546
+ if (v-> header .magic == VERITY_MAGIC_DISABLE) {
515
547
/* this value is not used by us, but can be used by a caller to
516
548
decide whether dm-verity should be enabled */
517
549
v->disabled = true ;
518
- } else if (v->header .magic != VERITY_MAGIC) {
519
- return -1 ;
520
550
}
521
551
522
- if (v->header .version != VERITY_VERSION) {
523
- error (" unsupported verity version %u" , v->header .version );
552
+ if (fec_pread (f, &v->ecc_header , sizeof (v->ecc_header ), offset) !=
553
+ sizeof (v->ecc_header )) {
554
+ warn (" failed to read verity header: %s" , strerror (errno));
524
555
return -1 ;
525
556
}
526
557
527
- if (v->header .length < VERITY_MIN_TABLE_SIZE ||
528
- v->header .length > VERITY_MAX_TABLE_SIZE) {
529
- error (" invalid verity table size: %u; expected ["
530
- stringify (VERITY_MIN_TABLE_SIZE) " , "
531
- stringify (VERITY_MAX_TABLE_SIZE) " )" , v->header .length );
532
- return -1 ;
533
- }
558
+ if (validate_header (f, &v->header , offset)) {
559
+ /* raw verity header is invalid; this could be due to corruption, or
560
+ due to missing verity metadata */
534
561
535
- v->metadata_start = offset;
562
+ if (validate_header (f, &v->ecc_header , offset)) {
563
+ return -1 ; /* either way, we cannot recover */
564
+ }
536
565
537
- /* signature is skipped, because for our purposes it won't matter from
538
- where the data originates; the caller of the library is responsible
539
- for signature verification */
566
+ /* report mismatching fields */
567
+ if (!v->disabled && v->header .magic != v->ecc_header .magic ) {
568
+ warn (" corrected verity header magic" );
569
+ v->header .magic = v->ecc_header .magic ;
570
+ }
540
571
541
- if (offset > UINT64_MAX - v->header .length ) {
542
- error (" invalid verity table length: %u" , v->header .length );
543
- return -1 ;
544
- } else if (offset + v->header .length >= f->data_size ) {
545
- error (" invalid verity table length: %u" , v->header .length );
546
- return -1 ;
572
+ if (v->header .version != v->ecc_header .version ) {
573
+ warn (" corrected verity header version" );
574
+ v->header .version = v->ecc_header .version ;
575
+ }
576
+
577
+ if (v->header .length != v->ecc_header .length ) {
578
+ warn (" corrected verity header length" );
579
+ v->header .length = v->ecc_header .length ;
580
+ }
581
+
582
+ if (memcmp (v->header .signature , v->ecc_header .signature ,
583
+ sizeof (v->header .signature ))) {
584
+ warn (" corrected verity header signature" );
585
+ /* we have no way of knowing which signature is correct, if either
586
+ of them is */
587
+ }
547
588
}
548
589
590
+ v->metadata_start = offset;
591
+
549
592
if (parse_table (f, offset + sizeof (v->header ), v->header .length ) == -1 ) {
550
593
return -1 ;
551
594
}
0 commit comments