diff options
author | Tianjie Xu <xunchang@google.com> | 2019-11-20 12:18:40 -0800 |
---|---|---|
committer | Tianjie Xu <xunchang@google.com> | 2019-11-27 13:10:11 -0800 |
commit | ef9dc36236a1b77fa0d01c3a2a9e5a4f1ddc6b15 (patch) | |
tree | 2d218708106fa69a3eed53ade2587c8094db4381 /libfec | |
parent | cf9b34eccd9c35571f204caca8b1e0e95bb05256 (diff) | |
download | extras-ef9dc36236a1b77fa0d01c3a2a9e5a4f1ddc6b15.tar.gz |
Factor out the hashtree info from the verity_info
Even though the format for the VB2.0(AVB) image is different from the VB1.0
image, the majority of the content is the same. In specific, they both
have a hashtree and ecc data. By factoring the hashtree info, fec_read
can later use only the hashtree for error correction and doesn't need to
have the knowledge of verity format.
VB 1.0:
Filesystem
hash_tree
metadata <- assume 8 blocks
ecc_data
VB 2.0:
Filesystem
hash_tree
ecc_data
vbmeta
avb footer
Also switch the internal struct to use std containers so that we don't
need to worry about the memory management.
Bug: 144388532
Test: load a verity image, unit tests pass
Change-Id: I83c55464c3ac75ac41be9f507b674886ad298350
Diffstat (limited to 'libfec')
-rw-r--r-- | libfec/fec_open.cpp | 30 | ||||
-rw-r--r-- | libfec/fec_private.h | 38 | ||||
-rw-r--r-- | libfec/fec_read.cpp | 70 | ||||
-rw-r--r-- | libfec/fec_verity.cpp | 232 |
4 files changed, 168 insertions, 202 deletions
diff --git a/libfec/fec_open.cpp b/libfec/fec_open.cpp index a49e02f4..c8ae9804 100644 --- a/libfec/fec_open.cpp +++ b/libfec/fec_open.cpp @@ -110,7 +110,7 @@ static int parse_ecc_header(fec_handle *f, uint64_t offset) /* there's obviously no ecc data at this point, so there is no need to call fec_pread to access this data */ - if (!raw_pread(f, &header, sizeof(fec_header), offset)) { + if (!raw_pread(f->fd, &header, sizeof(fec_header), offset)) { error("failed to read: %s", strerror(errno)); return -1; } @@ -170,7 +170,7 @@ static int parse_ecc_header(fec_handle *f, uint64_t offset) len = f->ecc.size - n; } - if (!raw_pread(f, buf, len, f->ecc.start + n)) { + if (!raw_pread(f->fd, buf, len, f->ecc.start + n)) { error("failed to read ecc: %s", strerror(errno)); return -1; } @@ -309,7 +309,7 @@ static int load_verity(fec_handle *f) /* verity header is at the end of the data area */ if (verity_parse_header(f, offset) == 0) { debug("found at %" PRIu64 " (start %" PRIu64 ")", offset, - f->verity.hash_start); + f->verity.hashtree.hash_start); return 0; } @@ -319,7 +319,7 @@ static int load_verity(fec_handle *f) if (find_verity_offset(f, &offset) == 0 && verity_parse_header(f, offset) == 0) { debug("found at %" PRIu64 " (start %" PRIu64 ")", offset, - f->verity.hash_start); + f->verity.hashtree.hash_start); return 0; } @@ -333,7 +333,7 @@ static int load_verity(fec_handle *f) if (rc == 0) { debug("found at %" PRIu64 " (start %" PRIu64 ")", offset, - f->verity.hash_start); + f->verity.hashtree.hash_start); } } @@ -399,8 +399,8 @@ static void reset_handle(fec_handle *f) f->pos = 0; f->size = 0; - memset(&f->ecc, 0, sizeof(f->ecc)); - memset(&f->verity, 0, sizeof(f->verity)); + f->ecc = {}; + f->verity = {}; } /* closes and flushes `f->fd' and releases any memory allocated for `f' */ @@ -416,16 +416,6 @@ int fec_close(struct fec_handle *f) close(f->fd); } - if (f->verity.hash) { - delete[] f->verity.hash; - } - if (f->verity.salt) { - delete[] f->verity.salt; - } - if (f->verity.table) { - delete[] f->verity.table; - } - pthread_mutex_destroy(&f->mutex); reset_handle(f); @@ -446,9 +436,9 @@ int fec_verity_get_metadata(struct fec_handle *f, struct fec_verity_metadata *da } check(f->data_size < f->size); - check(f->data_size <= f->verity.hash_start); + check(f->data_size <= f->verity.hashtree.hash_start); check(f->data_size <= f->verity.metadata_start); - check(f->verity.table); + check(!f->verity.table.empty()); data->disabled = f->verity.disabled; data->data_size = f->data_size; @@ -456,7 +446,7 @@ int fec_verity_get_metadata(struct fec_handle *f, struct fec_verity_metadata *da sizeof(data->signature)); memcpy(data->ecc_signature, f->verity.ecc_header.signature, sizeof(data->ecc_signature)); - data->table = f->verity.table; + data->table = f->verity.table.c_str(); data->table_length = f->verity.header.length; return 0; diff --git a/libfec/fec_private.h b/libfec/fec_private.h index 0d94228e..81f34d59 100644 --- a/libfec/fec_private.h +++ b/libfec/fec_private.h @@ -74,28 +74,26 @@ struct ecc_info { uint64_t start; /* offset in file */ }; -struct verity_info { - bool disabled; - char *table; +struct hashtree_info { + uint64_t data_blocks; uint32_t hash_data_blocks; uint32_t hash_size; uint64_t hash_data_offset; uint64_t hash_start; - uint8_t *hash; - uint32_t salt_size; - uint8_t *salt; - uint64_t data_blocks; + std::vector<uint8_t> hash; + std::vector<uint8_t> salt; + std::vector<uint8_t> zero_hash; +}; + +struct verity_info { + bool disabled; + std::string table; uint64_t metadata_start; /* offset in file */ - uint8_t zero_hash[SHA256_DIGEST_LENGTH]; + hashtree_info hashtree; verity_header header; verity_header ecc_header; }; -struct verity_block_info { - uint64_t index; - bool valid; -}; - struct fec_handle { ecc_info ecc; int fd; @@ -107,13 +105,15 @@ struct fec_handle { uint64_t pos; uint64_t size; verity_info verity; + + hashtree_info hashtree() const { + return verity.hashtree; + } }; /* I/O helpers */ -extern bool raw_pread(fec_handle *f, void *buf, size_t count, - uint64_t offset); -extern bool raw_pwrite(fec_handle *f, const void *buf, size_t count, - uint64_t offset); +extern bool raw_pread(int fd, void *buf, size_t count, uint64_t offset); +extern bool raw_pwrite(int fd, const void *buf, size_t count, uint64_t offset); /* processing functions */ typedef ssize_t (*read_func)(fec_handle *f, uint8_t *dest, size_t count, @@ -128,8 +128,8 @@ extern uint64_t verity_get_size(uint64_t file_size, uint32_t *verity_levels, extern int verity_parse_header(fec_handle *f, uint64_t offset); -extern bool verity_check_block(fec_handle *f, const uint8_t *expected, - const uint8_t *block); +extern bool check_block_hash(const uint8_t *expected, const uint8_t *block, + const std::vector<uint8_t> &salt); /* helper macros */ #ifndef unlikely diff --git a/libfec/fec_read.cpp b/libfec/fec_read.cpp index ec2750e7..9ea6430b 100644 --- a/libfec/fec_read.cpp +++ b/libfec/fec_read.cpp @@ -79,27 +79,28 @@ static inline bool is_erasure(fec_handle *f, uint64_t offset, uint64_t n = offset / FEC_BLOCKSIZE; - return !verity_check_block(f, &f->verity.hash[n * SHA256_DIGEST_LENGTH], - data); + return !check_block_hash(&f->hashtree().hash[n * SHA256_DIGEST_LENGTH], + data, f->hashtree().salt); } /* check if `offset' is within a block expected to contain zeros */ static inline bool is_zero(fec_handle *f, uint64_t offset) { - verity_info *v = &f->verity; + auto hashtree = f->hashtree(); - if (!v->hash || unlikely(offset >= f->data_size)) { + if (hashtree.hash.empty() || unlikely(offset >= f->data_size)) { return false; } uint64_t hash_offset = (offset / FEC_BLOCKSIZE) * SHA256_DIGEST_LENGTH; - if (unlikely(hash_offset > - v->hash_data_blocks * FEC_BLOCKSIZE - SHA256_DIGEST_LENGTH)) { + if (unlikely(hash_offset > hashtree.hash_data_blocks * FEC_BLOCKSIZE - + SHA256_DIGEST_LENGTH)) { return false; } - return !memcmp(v->zero_hash, &v->hash[hash_offset], SHA256_DIGEST_LENGTH); + return !memcmp(hashtree.zero_hash.data(), &hashtree.hash[hash_offset], + SHA256_DIGEST_LENGTH); } /* reads and decodes a single block starting from `offset', returns the number @@ -119,7 +120,7 @@ static int __ecc_read(fec_handle *f, void *rs, uint8_t *dest, uint64_t offset, int neras = 0; /* verity is required to check for erasures */ - check(!use_erasures || f->verity.hash); + check(!use_erasures || !f->hashtree().hash.empty()); for (int i = 0; i < e->rsn; ++i) { uint64_t interleaved = fec_ecc_interleave(rsb * e->rsn + i, e->rsn, @@ -135,7 +136,7 @@ static int __ecc_read(fec_handle *f, void *rs, uint8_t *dest, uint64_t offset, if (likely(interleaved < e->start) && !is_zero(f, interleaved)) { /* copy raw data to reconstruct the RS block */ - if (!raw_pread(f, bbuf, FEC_BLOCKSIZE, interleaved)) { + if (!raw_pread(f->fd, bbuf, FEC_BLOCKSIZE, interleaved)) { warn("failed to read: %s", strerror(errno)); /* treat errors as corruption */ @@ -143,7 +144,7 @@ static int __ecc_read(fec_handle *f, void *rs, uint8_t *dest, uint64_t offset, erasures[neras++] = i; } } else if (use_erasures && neras <= e->roots && - is_erasure(f, interleaved, bbuf)) { + is_erasure(f, interleaved, bbuf)) { erasures[neras++] = i; } } @@ -160,8 +161,8 @@ static int __ecc_read(fec_handle *f, void *rs, uint8_t *dest, uint64_t offset, for (int i = 0; i < FEC_BLOCKSIZE; ++i) { /* copy parity data */ - if (!raw_pread(f, &ecc_data[i * FEC_RSM + e->rsn], e->roots, - e->start + (i + rsb) * e->roots)) { + if (!raw_pread(f->fd, &ecc_data[i * FEC_RSM + e->rsn], e->roots, + e->start + (i + rsb) * e->roots)) { error("failed to read ecc data: %s", strerror(errno)); return -1; } @@ -180,7 +181,7 @@ static int __ecc_read(fec_handle *f, void *rs, uint8_t *dest, uint64_t offset, error("RS block %" PRIu64 ": decoding failed (%d erasures)", rsb, neras); dump("raw RS block", rsb, copy, FEC_RSM); - } else if (!f->verity.hash) { + } else if (f->hashtree().hash.empty()) { warn("RS block %" PRIu64 ": decoding failed", rsb); } else { debug("RS block %" PRIu64 ": decoding failed", rsb); @@ -289,7 +290,7 @@ static ssize_t verity_read(fec_handle *f, uint8_t *dest, size_t count, check(dest); check(offset < f->data_size); check(offset + count <= f->data_size); - check(f->verity.hash); + check(!f->hashtree().hash.empty()); check(errors); debug("[%" PRIu64 ", %" PRIu64 ")", offset, offset + count); @@ -306,13 +307,14 @@ static ssize_t verity_read(fec_handle *f, uint8_t *dest, size_t count, size_t left = count; uint8_t data[FEC_BLOCKSIZE]; - uint64_t max_hash_block = (f->verity.hash_data_blocks * FEC_BLOCKSIZE - - SHA256_DIGEST_LENGTH) / SHA256_DIGEST_LENGTH; + uint64_t max_hash_block = (f->hashtree().hash_data_blocks * FEC_BLOCKSIZE - + SHA256_DIGEST_LENGTH) / + SHA256_DIGEST_LENGTH; while (left > 0) { check(curr <= max_hash_block); - uint8_t *hash = &f->verity.hash[curr * SHA256_DIGEST_LENGTH]; + uint8_t *hash = &f->hashtree().hash[curr * SHA256_DIGEST_LENGTH]; uint64_t curr_offset = curr * FEC_BLOCKSIZE; bool expect_zeros = is_zero(f, curr_offset); @@ -325,12 +327,12 @@ static ssize_t verity_read(fec_handle *f, uint8_t *dest, size_t count, } /* copy raw data without error correction */ - if (!raw_pread(f, data, FEC_BLOCKSIZE, curr_offset)) { + if (!raw_pread(f->fd, data, FEC_BLOCKSIZE, curr_offset)) { error("failed to read: %s", strerror(errno)); return -1; } - if (likely(verity_check_block(f, hash, data))) { + if (likely(check_block_hash(hash, data, f->hashtree().salt))) { goto valid; } @@ -354,15 +356,15 @@ static ssize_t verity_read(fec_handle *f, uint8_t *dest, size_t count, /* try to correct without erasures first, because checking for erasure locations is slower */ if (__ecc_read(f, rs.get(), data, curr_offset, false, ecc_data.get(), - errors) == FEC_BLOCKSIZE && - verity_check_block(f, hash, data)) { + errors) == FEC_BLOCKSIZE && + check_block_hash(hash, data, f->hashtree().salt)) { goto corrected; } /* try to correct with erasures */ if (__ecc_read(f, rs.get(), data, curr_offset, true, ecc_data.get(), - errors) == FEC_BLOCKSIZE && - verity_check_block(f, hash, data)) { + errors) == FEC_BLOCKSIZE && + check_block_hash(hash, data, f->hashtree().salt)) { goto corrected; } @@ -377,7 +379,7 @@ static ssize_t verity_read(fec_handle *f, uint8_t *dest, size_t count, corrected: /* update the corrected block to the file if we are in r/w mode */ if (f->mode & O_RDWR && - !raw_pwrite(f, data, FEC_BLOCKSIZE, curr_offset)) { + !raw_pwrite(f->fd, data, FEC_BLOCKSIZE, curr_offset)) { error("failed to write: %s", strerror(errno)); return -1; } @@ -469,16 +471,14 @@ static inline size_t get_max_count(uint64_t offset, size_t count, uint64_t max) /* reads `count' bytes from `f->fd' starting from `offset', and copies the data to `buf' */ -bool raw_pread(fec_handle *f, void *buf, size_t count, uint64_t offset) -{ - check(f); +bool raw_pread(int fd, void *buf, size_t count, uint64_t offset) { check(buf); uint8_t *p = (uint8_t *)buf; size_t remaining = count; while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(pread64(f->fd, p, remaining, offset)); + ssize_t n = TEMP_FAILURE_RETRY(pread64(fd, p, remaining, offset)); if (n <= 0) { return false; @@ -493,16 +493,14 @@ bool raw_pread(fec_handle *f, void *buf, size_t count, uint64_t offset) } /* writes `count' bytes from `buf' to `f->fd' to a file position `offset' */ -bool raw_pwrite(fec_handle *f, const void *buf, size_t count, uint64_t offset) -{ - check(f); +bool raw_pwrite(int fd, const void *buf, size_t count, uint64_t offset) { check(buf); const uint8_t *p = (const uint8_t *)buf; size_t remaining = count; while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(pwrite64(f->fd, p, remaining, offset)); + ssize_t n = TEMP_FAILURE_RETRY(pwrite64(fd, p, remaining, offset)); if (n <= 0) { return false; @@ -529,10 +527,10 @@ ssize_t fec_pread(struct fec_handle *f, void *buf, size_t count, return -1; } - if (f->verity.hash) { + if (!f->hashtree().hash.empty()) { return process(f, (uint8_t *)buf, - get_max_count(offset, count, f->data_size), offset, - verity_read); + get_max_count(offset, count, f->data_size), offset, + verity_read); } else if (f->ecc.start) { check(f->ecc.start < f->size); @@ -549,7 +547,7 @@ ssize_t fec_pread(struct fec_handle *f, void *buf, size_t count, count = get_max_count(offset, count, f->size); } - if (raw_pread(f, buf, count, offset)) { + if (raw_pread(f->fd, buf, count, offset)) { return count; } diff --git a/libfec/fec_verity.cpp b/libfec/fec_verity.cpp index 3f636dd0..25b6ce48 100644 --- a/libfec/fec_verity.cpp +++ b/libfec/fec_verity.cpp @@ -16,7 +16,13 @@ #include <ctype.h> #include <stdlib.h> + +#include <algorithm> +#include <string> +#include <vector> + #include <android-base/strings.h> + #include "fec_private.h" /* converts a hex nibble into an int */ @@ -115,17 +121,15 @@ uint64_t verity_get_size(uint64_t file_size, uint32_t *verity_levels, return total * FEC_BLOCKSIZE; } -/* computes a SHA-256 salted with `f->verity.salt' from a FEC_BLOCKSIZE byte - buffer `block', and copies the hash to `hash' */ -static inline int verity_hash(fec_handle *f, const uint8_t *block, - uint8_t *hash) -{ +// Computes a SHA-256 salted with 'salt' from a FEC_BLOCKSIZE byte buffer +// 'block', and copies the hash to 'hash'. +static inline int get_hash(const uint8_t *block, uint8_t *hash, + const std::vector<uint8_t> &salt) { SHA256_CTX ctx; SHA256_Init(&ctx); - check(f); - check(f->verity.salt); - SHA256_Update(&ctx, f->verity.salt, f->verity.salt_size); + check(!salt.empty()); + SHA256_Update(&ctx, salt.data(), salt.size()); check(block); SHA256_Update(&ctx, block, FEC_BLOCKSIZE); @@ -137,15 +141,13 @@ static inline int verity_hash(fec_handle *f, const uint8_t *block, /* computes a verity hash for FEC_BLOCKSIZE bytes from buffer `block' and compares it to the expected value in `expected' */ -bool verity_check_block(fec_handle *f, const uint8_t *expected, - const uint8_t *block) -{ - check(f); +bool check_block_hash(const uint8_t *expected, const uint8_t *block, + const std::vector<uint8_t> &salt) { check(block); uint8_t hash[SHA256_DIGEST_LENGTH]; - if (unlikely(verity_hash(f, block, hash) == -1)) { + if (unlikely(get_hash(block, hash, salt) == -1)) { error("failed to hash"); return false; } @@ -182,39 +184,40 @@ static bool ecc_read_hashes(fec_handle *f, uint64_t hash_offset, /* reads the verity hash tree, validates it against the root hash in `root', corrects errors if necessary, and copies valid data blocks for later use to `f->verity.hash' */ -static int verify_tree(fec_handle *f, const uint8_t *root) -{ +static int verify_tree(hashtree_info *hashtree, const fec_handle *f, + const uint8_t *root) { uint8_t data[FEC_BLOCKSIZE]; uint8_t hash[SHA256_DIGEST_LENGTH]; + check(hashtree); check(f); check(root); - verity_info *v = &f->verity; uint32_t levels = 0; /* calculate the size and the number of levels in the hash tree */ - v->hash_size = - verity_get_size(v->data_blocks * FEC_BLOCKSIZE, &levels, NULL); + hashtree->hash_size = + verity_get_size(hashtree->data_blocks * FEC_BLOCKSIZE, &levels, NULL); - check(v->hash_start < UINT64_MAX - v->hash_size); - check(v->hash_start + v->hash_size <= f->data_size); + check(hashtree->hash_start < UINT64_MAX - hashtree->hash_size); + check(hashtree->hash_start + hashtree->hash_size <= f->data_size); - uint64_t hash_offset = v->hash_start; + uint64_t hash_offset = hashtree->hash_start; uint64_t data_offset = hash_offset + FEC_BLOCKSIZE; - v->hash_data_offset = data_offset; + hashtree->hash_data_offset = data_offset; /* validate the root hash */ - if (!raw_pread(f, data, FEC_BLOCKSIZE, hash_offset) || - !verity_check_block(f, root, data)) { + if (!raw_pread(f->fd, data, FEC_BLOCKSIZE, hash_offset) || + !check_block_hash(root, data, hashtree->salt)) { /* try to correct */ - if (!ecc_read_hashes(f, 0, NULL, hash_offset, data) || - !verity_check_block(f, root, data)) { + if (!ecc_read_hashes(const_cast<fec_handle *>(f), 0, NULL, hash_offset, + data) || + !check_block_hash(root, data, hashtree->salt)) { error("root hash invalid"); return -1; } else if (f->mode & O_RDWR && - !raw_pwrite(f, data, FEC_BLOCKSIZE, hash_offset)) { + !raw_pwrite(f->fd, data, FEC_BLOCKSIZE, hash_offset)) { error("failed to rewrite the root block: %s", strerror(errno)); return -1; } @@ -225,38 +228,34 @@ static int verify_tree(fec_handle *f, const uint8_t *root) /* calculate the number of hashes on each level */ uint32_t hashes[levels]; - verity_get_size(v->data_blocks * FEC_BLOCKSIZE, NULL, hashes); + verity_get_size(hashtree->data_blocks * FEC_BLOCKSIZE, NULL, hashes); /* calculate the size and offset for the data hashes */ for (uint32_t i = 1; i < levels; ++i) { uint32_t blocks = hashes[levels - i]; debug("%u hash blocks on level %u", blocks, levels - i); - v->hash_data_offset = data_offset; - v->hash_data_blocks = blocks; + hashtree->hash_data_offset = data_offset; + hashtree->hash_data_blocks = blocks; data_offset += blocks * FEC_BLOCKSIZE; } - check(v->hash_data_blocks); - check(v->hash_data_blocks <= v->hash_size / FEC_BLOCKSIZE); + check(hashtree->hash_data_blocks); + check(hashtree->hash_data_blocks <= hashtree->hash_size / FEC_BLOCKSIZE); - check(v->hash_data_offset); - check(v->hash_data_offset <= - UINT64_MAX - (v->hash_data_blocks * FEC_BLOCKSIZE)); - check(v->hash_data_offset < f->data_size); - check(v->hash_data_offset + v->hash_data_blocks * FEC_BLOCKSIZE <= - f->data_size); + check(hashtree->hash_data_offset); + check(hashtree->hash_data_offset <= + UINT64_MAX - (hashtree->hash_data_blocks * FEC_BLOCKSIZE)); + check(hashtree->hash_data_offset < f->data_size); + check(hashtree->hash_data_offset + + hashtree->hash_data_blocks * FEC_BLOCKSIZE <= + f->data_size); /* copy data hashes to memory in case they are corrupted, so we don't have to correct them every time they are needed */ - std::unique_ptr<uint8_t[]> data_hashes( - new (std::nothrow) uint8_t[f->verity.hash_data_blocks * FEC_BLOCKSIZE]); - - if (!data_hashes) { - errno = ENOMEM; - return -1; - } + std::vector<uint8_t> data_hashes(hashtree->hash_data_blocks * FEC_BLOCKSIZE, + 0); /* validate the rest of the hash tree */ data_offset = hash_offset + FEC_BLOCKSIZE; @@ -267,42 +266,44 @@ static int verify_tree(fec_handle *f, const uint8_t *root) for (uint32_t j = 0; j < blocks; ++j) { /* ecc reads are very I/O intensive, so read raw hash tree and do error correcting only if it doesn't validate */ - if (!raw_pread(f, hash, SHA256_DIGEST_LENGTH, - hash_offset + j * SHA256_DIGEST_LENGTH) || - !raw_pread(f, data, FEC_BLOCKSIZE, - data_offset + j * FEC_BLOCKSIZE)) { + if (!raw_pread(f->fd, hash, SHA256_DIGEST_LENGTH, + hash_offset + j * SHA256_DIGEST_LENGTH) || + !raw_pread(f->fd, data, FEC_BLOCKSIZE, + data_offset + j * FEC_BLOCKSIZE)) { error("failed to read hashes: %s", strerror(errno)); return -1; } - if (!verity_check_block(f, hash, data)) { + if (!check_block_hash(hash, data, hashtree->salt)) { /* try to correct */ - if (!ecc_read_hashes(f, - hash_offset + j * SHA256_DIGEST_LENGTH, hash, - data_offset + j * FEC_BLOCKSIZE, data) || - !verity_check_block(f, hash, data)) { - error("invalid hash tree: hash_offset %" PRIu64 ", " - "data_offset %" PRIu64 ", block %u", - hash_offset, data_offset, j); + if (!ecc_read_hashes(const_cast<fec_handle *>(f), + hash_offset + j * SHA256_DIGEST_LENGTH, + hash, data_offset + j * FEC_BLOCKSIZE, + data) || + !check_block_hash(hash, data, hashtree->salt)) { + error("invalid hash tree: hash_offset %" PRIu64 + ", " + "data_offset %" PRIu64 ", block %u", + hash_offset, data_offset, j); return -1; } /* update the corrected blocks to the file if we are in r/w mode */ if (f->mode & O_RDWR) { - if (!raw_pwrite(f, hash, SHA256_DIGEST_LENGTH, - hash_offset + j * SHA256_DIGEST_LENGTH) || - !raw_pwrite(f, data, FEC_BLOCKSIZE, - data_offset + j * FEC_BLOCKSIZE)) { + if (!raw_pwrite(f->fd, hash, SHA256_DIGEST_LENGTH, + hash_offset + j * SHA256_DIGEST_LENGTH) || + !raw_pwrite(f->fd, data, FEC_BLOCKSIZE, + data_offset + j * FEC_BLOCKSIZE)) { error("failed to write hashes: %s", strerror(errno)); return -1; } } } - if (blocks == v->hash_data_blocks) { - memcpy(data_hashes.get() + j * FEC_BLOCKSIZE, data, - FEC_BLOCKSIZE); + if (blocks == hashtree->hash_data_blocks) { + std::copy(data, data + FEC_BLOCKSIZE, + data_hashes.begin() + j * FEC_BLOCKSIZE); } } @@ -312,12 +313,7 @@ static int verify_tree(fec_handle *f, const uint8_t *root) debug("valid"); - if (v->hash) { - delete[] v->hash; - v->hash = NULL; - } - - v->hash = data_hashes.release(); + hashtree->hash = std::move(data_hashes); return 0; } @@ -333,31 +329,26 @@ static int parse_table(fec_handle *f, uint64_t offset, uint32_t size, bool useec debug("offset = %" PRIu64 ", size = %u", offset, size); verity_info *v = &f->verity; - std::unique_ptr<char[]> table(new (std::nothrow) char[size + 1]); - - if (!table) { - errno = ENOMEM; - return -1; - } + std::string table(size, 0); if (!useecc) { - if (!raw_pread(f, table.get(), size, offset)) { + if (!raw_pread(f->fd, const_cast<char *>(table.data()), size, offset)) { error("failed to read verity table: %s", strerror(errno)); return -1; } - } else if (fec_pread(f, table.get(), size, offset) != (ssize_t)size) { + } else if (fec_pread(f, const_cast<char *>(table.data()), size, offset) != + (ssize_t)size) { error("failed to ecc read verity table: %s", strerror(errno)); return -1; } - table[size] = '\0'; - debug("verity table: '%s'", table.get()); + debug("verity table: '%s'", table.c_str()); int i = 0; - std::unique_ptr<uint8_t[]> salt; + std::vector<uint8_t> salt; uint8_t root[SHA256_DIGEST_LENGTH]; - auto tokens = android::base::Split(table.get(), " "); + auto tokens = android::base::Split(table, " "); for (const auto& token : tokens) { switch (i++) { @@ -377,7 +368,7 @@ static int parse_table(fec_handle *f, uint64_t offset, uint32_t size, bool useec break; case 5: /* num_data_blocks */ if (parse_uint64(token.c_str(), f->data_size / FEC_BLOCKSIZE, - &v->data_blocks) == -1) { + &v->hashtree.data_blocks) == -1) { error("invalid number of verity data blocks: %s", token.c_str()); return -1; @@ -385,12 +376,12 @@ static int parse_table(fec_handle *f, uint64_t offset, uint32_t size, bool useec break; case 6: /* hash_start_block */ if (parse_uint64(token.c_str(), f->data_size / FEC_BLOCKSIZE, - &v->hash_start) == -1) { + &v->hashtree.hash_start) == -1) { error("invalid verity hash start block: %s", token.c_str()); return -1; } - v->hash_start *= FEC_BLOCKSIZE; + v->hashtree.hash_start *= FEC_BLOCKSIZE; break; case 7: /* algorithm */ if (token != "sha256") { @@ -405,22 +396,19 @@ static int parse_table(fec_handle *f, uint64_t offset, uint32_t size, bool useec } break; case 9: /* salt */ - v->salt_size = token.size(); - check(v->salt_size % 2 == 0); - v->salt_size /= 2; + { + uint32_t salt_size = token.size(); + check(salt_size % 2 == 0); + salt_size /= 2; - salt.reset(new (std::nothrow) uint8_t[v->salt_size]); + salt.resize(salt_size, 0); - if (!salt) { - errno = ENOMEM; - return -1; - } - - if (parse_hex(salt.get(), v->salt_size, token.c_str()) == -1) { + if (parse_hex(salt.data(), salt_size, token.c_str()) == -1) { error("invalid verity salt: %s", token.c_str()); return -1; } break; + } default: break; } @@ -432,39 +420,29 @@ static int parse_table(fec_handle *f, uint64_t offset, uint32_t size, bool useec return -1; } - check(v->hash_start < f->data_size); + check(v->hashtree.hash_start < f->data_size); - if (v->metadata_start < v->hash_start) { - check(v->data_blocks == v->metadata_start / FEC_BLOCKSIZE); + if (v->metadata_start < v->hashtree.hash_start) { + check(v->hashtree.data_blocks == v->metadata_start / FEC_BLOCKSIZE); } else { - check(v->data_blocks == v->hash_start / FEC_BLOCKSIZE); + check(v->hashtree.data_blocks == + v->hashtree.hash_start / FEC_BLOCKSIZE); } - if (v->salt) { - delete[] v->salt; - v->salt = NULL; - } - - v->salt = salt.release(); - - if (v->table) { - delete[] v->table; - v->table = NULL; - } - - v->table = table.release(); + v->hashtree.salt = std::move(salt); + v->table = std::move(table); if (!(f->flags & FEC_VERITY_DISABLE)) { - if (verify_tree(f, root) == -1) { + if (verify_tree(&v->hashtree, f, root) == -1) { return -1; } - check(v->hash); - - uint8_t zero_block[FEC_BLOCKSIZE]; - memset(zero_block, 0, FEC_BLOCKSIZE); + check(!v->hashtree.hash.empty()); - if (verity_hash(f, zero_block, v->zero_hash) == -1) { + std::vector<uint8_t> zero_block(FEC_BLOCKSIZE, 0); + v->hashtree.zero_hash.assign(SHA256_DIGEST_LENGTH, 0); + if (get_hash(zero_block.data(), v->hashtree.zero_hash.data(), + v->hashtree.salt) == -1) { error("failed to hash"); return -1; } @@ -493,13 +471,13 @@ static int rewrite_metadata(fec_handle *f, uint64_t offset) verity_info *v = &f->verity; memcpy(metadata.get(), &v->header, sizeof(v->header)); - check(v->table); - size_t len = strlen(v->table); + check(!v->table.empty()); + size_t len = v->table.size(); check(sizeof(v->header) + len <= VERITY_METADATA_SIZE); - memcpy(metadata.get() + sizeof(v->header), v->table, len); + memcpy(metadata.get() + sizeof(v->header), v->table.data(), len); - return raw_pwrite(f, metadata.get(), VERITY_METADATA_SIZE, offset); + return raw_pwrite(f->fd, metadata.get(), VERITY_METADATA_SIZE, offset); } static int validate_header(const fec_handle *f, const verity_header *header, @@ -557,7 +535,7 @@ int verity_parse_header(fec_handle *f, uint64_t offset) verity_info *v = &f->verity; uint64_t errors = f->errors; - if (!raw_pread(f, &v->header, sizeof(v->header), offset)) { + if (!raw_pread(f->fd, &v->header, sizeof(v->header), offset)) { error("failed to read verity header: %s", strerror(errno)); return -1; } @@ -624,10 +602,10 @@ int verity_parse_header(fec_handle *f, uint64_t offset) warn("failed to rewrite verity metadata: %s", strerror(errno)); } - if (v->metadata_start < v->hash_start) { + if (v->metadata_start < v->hashtree.hash_start) { f->data_size = v->metadata_start; } else { - f->data_size = v->hash_start; + f->data_size = v->hashtree.hash_start; } return 0; @@ -657,9 +635,9 @@ int fec_verity_set_status(struct fec_handle *f, bool enabled) uint32_t magic = enabled ? VERITY_MAGIC : VERITY_MAGIC_DISABLE; - if (!raw_pwrite(f, &magic, sizeof(magic), v->metadata_start)) { + if (!raw_pwrite(f->fd, &magic, sizeof(magic), v->metadata_start)) { error("failed to update verity magic to %08x: %s", magic, - strerror(errno)); + strerror(errno)); return -1; } |