summaryrefslogtreecommitdiff
path: root/libfec
diff options
context:
space:
mode:
authorTianjie Xu <xunchang@google.com>2019-11-20 12:18:40 -0800
committerTianjie Xu <xunchang@google.com>2019-11-27 13:10:11 -0800
commitef9dc36236a1b77fa0d01c3a2a9e5a4f1ddc6b15 (patch)
tree2d218708106fa69a3eed53ade2587c8094db4381 /libfec
parentcf9b34eccd9c35571f204caca8b1e0e95bb05256 (diff)
downloadextras-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.cpp30
-rw-r--r--libfec/fec_private.h38
-rw-r--r--libfec/fec_read.cpp70
-rw-r--r--libfec/fec_verity.cpp232
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;
}