summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami Tolvanen <samitolvanen@google.com>2016-06-03 13:56:07 -0700
committerSami Tolvanen <samitolvanen@google.com>2016-06-06 13:51:23 -0700
commit65cbaeb020b209f3d75d594ebbe49a609dd3c7e7 (patch)
tree664130c5b953ecc77ec6f612c440d128873665a0
parent871e63d9b7e584bc398dd4aa983cf561a5e8394e (diff)
downloadextras-65cbaeb020b209f3d75d594ebbe49a609dd3c7e7.tar.gz
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
-rw-r--r--libfec/fec_open.cpp5
-rw-r--r--libfec/fec_private.h1
-rw-r--r--libfec/fec_verity.cpp103
-rw-r--r--libfec/include/fec/io.h1
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;
};