summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSami Tolvanen <samitolvanen@google.com>2016-06-07 00:05:42 +0000
committerandroid-build-merger <android-build-merger@google.com>2016-06-07 00:05:42 +0000
commit98b6aada664e8f9338cc031f0e51f8fd135ad5e5 (patch)
treee16b6666d5a8fedec773cb532f0b6ef13deb24bd
parentf6b999e7c8153c7f0615f302b2010c5510efe6f3 (diff)
parent65cbaeb020b209f3d75d594ebbe49a609dd3c7e7 (diff)
downloadextras-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.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;
};