diff options
author | Sami Tolvanen <samitolvanen@google.com> | 2016-06-07 00:05:42 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2016-06-07 00:05:42 +0000 |
commit | 98b6aada664e8f9338cc031f0e51f8fd135ad5e5 (patch) | |
tree | e16b6666d5a8fedec773cb532f0b6ef13deb24bd | |
parent | f6b999e7c8153c7f0615f302b2010c5510efe6f3 (diff) | |
parent | 65cbaeb020b209f3d75d594ebbe49a609dd3c7e7 (diff) | |
download | extras-98b6aada664e8f9338cc031f0e51f8fd135ad5e5.tar.gz |
libfec: return raw and corrected verity metadata signatures
am: 65cbaeb020
* commit '65cbaeb020b209f3d75d594ebbe49a609dd3c7e7':
libfec: return raw and corrected verity metadata signatures
Change-Id: I77bb88a549c2da0ed69f36d80ca6d93ed91a163b
-rw-r--r-- | libfec/fec_open.cpp | 5 | ||||
-rw-r--r-- | libfec/fec_private.h | 1 | ||||
-rw-r--r-- | libfec/fec_verity.cpp | 103 | ||||
-rw-r--r-- | libfec/include/fec/io.h | 1 |
4 files changed, 79 insertions, 31 deletions
diff --git a/libfec/fec_open.cpp b/libfec/fec_open.cpp index c1d4afdb..0e41bf4f 100644 --- a/libfec/fec_open.cpp +++ b/libfec/fec_open.cpp @@ -460,7 +460,10 @@ int fec_verity_get_metadata(struct fec_handle *f, struct fec_verity_metadata *da data->disabled = f->verity.disabled; data->data_size = f->data_size; - memcpy(data->signature, f->verity.header.signature, sizeof(data->signature)); + memcpy(data->signature, f->verity.header.signature, + sizeof(data->signature)); + memcpy(data->ecc_signature, f->verity.ecc_header.signature, + sizeof(data->ecc_signature)); data->table = f->verity.table; data->table_length = f->verity.header.length; diff --git a/libfec/fec_private.h b/libfec/fec_private.h index bde30bd8..238c4e2e 100644 --- a/libfec/fec_private.h +++ b/libfec/fec_private.h @@ -88,6 +88,7 @@ struct verity_info { uint64_t metadata_start; /* offset in file */ uint8_t zero_hash[SHA256_DIGEST_LENGTH]; verity_header header; + verity_header ecc_header; }; struct verity_block_info { diff --git a/libfec/fec_verity.cpp b/libfec/fec_verity.cpp index ca4572c6..393e9624 100644 --- a/libfec/fec_verity.cpp +++ b/libfec/fec_verity.cpp @@ -481,6 +481,45 @@ static int rewrite_metadata(fec_handle *f, uint64_t offset) return raw_pwrite(f, metadata.get(), VERITY_METADATA_SIZE, offset); } +static int validate_header(const fec_handle *f, const verity_header *header, + uint64_t offset) +{ + check(f); + check(header); + + if (header->magic != VERITY_MAGIC && + header->magic != VERITY_MAGIC_DISABLE) { + return -1; + } + + if (header->version != VERITY_VERSION) { + error("unsupported verity version %u", header->version); + return -1; + } + + if (header->length < VERITY_MIN_TABLE_SIZE || + header->length > VERITY_MAX_TABLE_SIZE) { + error("invalid verity table size: %u; expected [" + stringify(VERITY_MIN_TABLE_SIZE) ", " + stringify(VERITY_MAX_TABLE_SIZE) ")", header->length); + return -1; + } + + /* signature is skipped, because for our purposes it won't matter from + where the data originates; the caller of the library is responsible + for signature verification */ + + if (offset > UINT64_MAX - header->length) { + error("invalid verity table length: %u", header->length); + return -1; + } else if (offset + header->length >= f->data_size) { + error("invalid verity table length: %u", header->length); + return -1; + } + + return 0; +} + /* attempts to read verity metadata from `f->fd' position `offset'; if in r/w mode, rewrites the metadata if it had errors */ int verity_parse_header(fec_handle *f, uint64_t offset) @@ -497,55 +536,59 @@ int verity_parse_header(fec_handle *f, uint64_t offset) verity_info *v = &f->verity; uint64_t errors = f->errors; - if (fec_pread(f, &v->header, sizeof(v->header), offset) != - sizeof(v->header)) { + if (!raw_pread(f, &v->header, sizeof(v->header), offset)) { error("failed to read verity header: %s", strerror(errno)); return -1; } - verity_header raw_header; - - if (!raw_pread(f, &raw_header, sizeof(raw_header), offset)) { - error("failed to read verity header: %s", strerror(errno)); - return -1; - } /* use raw data to check for the alternative magic, because it will be error corrected to VERITY_MAGIC otherwise */ - if (raw_header.magic == VERITY_MAGIC_DISABLE) { + if (v->header.magic == VERITY_MAGIC_DISABLE) { /* this value is not used by us, but can be used by a caller to decide whether dm-verity should be enabled */ v->disabled = true; - } else if (v->header.magic != VERITY_MAGIC) { - return -1; } - if (v->header.version != VERITY_VERSION) { - error("unsupported verity version %u", v->header.version); + if (fec_pread(f, &v->ecc_header, sizeof(v->ecc_header), offset) != + sizeof(v->ecc_header)) { + warn("failed to read verity header: %s", strerror(errno)); return -1; } - if (v->header.length < VERITY_MIN_TABLE_SIZE || - v->header.length > VERITY_MAX_TABLE_SIZE) { - error("invalid verity table size: %u; expected [" - stringify(VERITY_MIN_TABLE_SIZE) ", " - stringify(VERITY_MAX_TABLE_SIZE) ")", v->header.length); - return -1; - } + if (validate_header(f, &v->header, offset)) { + /* raw verity header is invalid; this could be due to corruption, or + due to missing verity metadata */ - v->metadata_start = offset; + if (validate_header(f, &v->ecc_header, offset)) { + return -1; /* either way, we cannot recover */ + } - /* signature is skipped, because for our purposes it won't matter from - where the data originates; the caller of the library is responsible - for signature verification */ + /* report mismatching fields */ + if (!v->disabled && v->header.magic != v->ecc_header.magic) { + warn("corrected verity header magic"); + v->header.magic = v->ecc_header.magic; + } - if (offset > UINT64_MAX - v->header.length) { - error("invalid verity table length: %u", v->header.length); - return -1; - } else if (offset + v->header.length >= f->data_size) { - error("invalid verity table length: %u", v->header.length); - return -1; + if (v->header.version != v->ecc_header.version) { + warn("corrected verity header version"); + v->header.version = v->ecc_header.version; + } + + if (v->header.length != v->ecc_header.length) { + warn("corrected verity header length"); + v->header.length = v->ecc_header.length; + } + + if (memcmp(v->header.signature, v->ecc_header.signature, + sizeof(v->header.signature))) { + warn("corrected verity header signature"); + /* we have no way of knowing which signature is correct, if either + of them is */ + } } + v->metadata_start = offset; + if (parse_table(f, offset + sizeof(v->header), v->header.length) == -1) { return -1; } diff --git a/libfec/include/fec/io.h b/libfec/include/fec/io.h index 1a077f32..3b5dac06 100644 --- a/libfec/include/fec/io.h +++ b/libfec/include/fec/io.h @@ -71,6 +71,7 @@ struct fec_verity_metadata { bool disabled; uint64_t data_size; uint8_t signature[RSANUMBYTES]; + uint8_t ecc_signature[RSANUMBYTES]; const char *table; uint32_t table_length; }; |