Skip to content

Commit 65cbaeb

Browse files
committed
libfec: return raw and corrected verity metadata signatures
Since it's not possible for libfec to identify whether the signature field was successfully corrected, return both and allow the caller to validate either signature. Bug: 28943429 Change-Id: Ie913c21ba1d07d6df4c6feeb7226b2ec963f4d19
1 parent 871e63d commit 65cbaeb

File tree

4 files changed

+79
-31
lines changed

4 files changed

+79
-31
lines changed

libfec/fec_open.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,10 @@ int fec_verity_get_metadata(struct fec_handle *f, struct fec_verity_metadata *da
460460

461461
data->disabled = f->verity.disabled;
462462
data->data_size = f->data_size;
463-
memcpy(data->signature, f->verity.header.signature, sizeof(data->signature));
463+
memcpy(data->signature, f->verity.header.signature,
464+
sizeof(data->signature));
465+
memcpy(data->ecc_signature, f->verity.ecc_header.signature,
466+
sizeof(data->ecc_signature));
464467
data->table = f->verity.table;
465468
data->table_length = f->verity.header.length;
466469

libfec/fec_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ struct verity_info {
8888
uint64_t metadata_start; /* offset in file */
8989
uint8_t zero_hash[SHA256_DIGEST_LENGTH];
9090
verity_header header;
91+
verity_header ecc_header;
9192
};
9293

9394
struct verity_block_info {

libfec/fec_verity.cpp

Lines changed: 73 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,45 @@ static int rewrite_metadata(fec_handle *f, uint64_t offset)
481481
return raw_pwrite(f, metadata.get(), VERITY_METADATA_SIZE, offset);
482482
}
483483

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+
484523
/* attempts to read verity metadata from `f->fd' position `offset'; if in r/w
485524
mode, rewrites the metadata if it had errors */
486525
int verity_parse_header(fec_handle *f, uint64_t offset)
@@ -497,55 +536,59 @@ int verity_parse_header(fec_handle *f, uint64_t offset)
497536
verity_info *v = &f->verity;
498537
uint64_t errors = f->errors;
499538

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)) {
502540
error("failed to read verity header: %s", strerror(errno));
503541
return -1;
504542
}
505543

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-
}
512544
/* use raw data to check for the alternative magic, because it will
513545
be error corrected to VERITY_MAGIC otherwise */
514-
if (raw_header.magic == VERITY_MAGIC_DISABLE) {
546+
if (v->header.magic == VERITY_MAGIC_DISABLE) {
515547
/* this value is not used by us, but can be used by a caller to
516548
decide whether dm-verity should be enabled */
517549
v->disabled = true;
518-
} else if (v->header.magic != VERITY_MAGIC) {
519-
return -1;
520550
}
521551

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));
524555
return -1;
525556
}
526557

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 */
534561

535-
v->metadata_start = offset;
562+
if (validate_header(f, &v->ecc_header, offset)) {
563+
return -1; /* either way, we cannot recover */
564+
}
536565

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+
}
540571

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+
}
547588
}
548589

590+
v->metadata_start = offset;
591+
549592
if (parse_table(f, offset + sizeof(v->header), v->header.length) == -1) {
550593
return -1;
551594
}

libfec/include/fec/io.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ struct fec_verity_metadata {
7171
bool disabled;
7272
uint64_t data_size;
7373
uint8_t signature[RSANUMBYTES];
74+
uint8_t ecc_signature[RSANUMBYTES];
7475
const char *table;
7576
uint32_t table_length;
7677
};

0 commit comments

Comments
 (0)