Remove VLAs from FEC verity code.

This commit is contained in:
Milan Broz
2021-02-13 21:46:05 +01:00
parent 030d50f6ba
commit 6483fb027a
3 changed files with 63 additions and 24 deletions

View File

@@ -25,15 +25,19 @@
#include "rs.h" #include "rs.h"
#define MAX_NR_BUF 256
int decode_rs_char(struct rs* rs, data_t* data) int decode_rs_char(struct rs* rs, data_t* data)
{ {
int deg_lambda, el, deg_omega, syn_error, count; int deg_lambda, el, deg_omega, syn_error, count;
int i, j, r, k; int i, j, r, k;
data_t q, tmp, num1, num2, den, discr_r; data_t q, tmp, num1, num2, den, discr_r;
/* FIXME: remove VLAs here */ data_t lambda[MAX_NR_BUF], s[MAX_NR_BUF]; /* Err+Eras Locator poly and syndrome poly */
data_t lambda[rs->nroots + 1], s[rs->nroots]; /* Err+Eras Locator poly and syndrome poly */ data_t b[MAX_NR_BUF], t[MAX_NR_BUF], omega[MAX_NR_BUF];
data_t b[rs->nroots + 1], t[rs->nroots + 1], omega[rs->nroots + 1]; data_t root[MAX_NR_BUF], reg[MAX_NR_BUF], loc[MAX_NR_BUF];
data_t root[rs->nroots], reg[rs->nroots + 1], loc[rs->nroots];
if (rs->nroots >= MAX_NR_BUF)
return -1;
memset(s, 0, rs->nroots * sizeof(data_t)); memset(s, 0, rs->nroots * sizeof(data_t));
memset(b, 0, (rs->nroots + 1) * sizeof(data_t)); memset(b, 0, (rs->nroots + 1) * sizeof(data_t));

View File

@@ -178,6 +178,7 @@ static int FEC_process_inputs(struct crypt_device *cd,
r = decode_rs_char(rs, rs_block); r = decode_rs_char(rs, rs_block);
if (r < 0) { if (r < 0) {
log_err(cd, _("Failed to repair parity for block %" PRIu64 "."), n); log_err(cd, _("Failed to repair parity for block %" PRIu64 "."), n);
r = -EPERM;
goto out; goto out;
} }
/* return number of detected errors */ /* return number of detected errors */

View File

@@ -28,6 +28,7 @@
#include "internal.h" #include "internal.h"
#define VERITY_MAX_LEVELS 63 #define VERITY_MAX_LEVELS 63
#define VERITY_MAX_DIGEST_SIZE 1024
static unsigned get_bits_up(size_t u) static unsigned get_bits_up(size_t u)
{ {
@@ -47,20 +48,30 @@ static unsigned get_bits_down(size_t u)
static int verify_zero(struct crypt_device *cd, FILE *wr, size_t bytes) static int verify_zero(struct crypt_device *cd, FILE *wr, size_t bytes)
{ {
char block[bytes]; char *block = NULL;
size_t i; size_t i;
int r;
block = malloc(bytes);
if (!block)
return -ENOMEM;
if (fread(block, bytes, 1, wr) != 1) { if (fread(block, bytes, 1, wr) != 1) {
log_dbg(cd, "EIO while reading spare area."); log_dbg(cd, "EIO while reading spare area.");
return -EIO; r = -EIO;
goto out;
} }
for (i = 0; i < bytes; i++) for (i = 0; i < bytes; i++)
if (block[i]) { if (block[i]) {
log_err(cd, _("Spare area is not zeroed at position %" PRIu64 "."), log_err(cd, _("Spare area is not zeroed at position %" PRIu64 "."),
ftello(wr) - bytes); ftello(wr) - bytes);
return -EPERM; r = -EPERM;
goto out;
} }
return 0; r = 0;
out:
free(block);
return r;
} }
static int verify_hash_block(const char *hash_name, int version, static int verify_hash_block(const char *hash_name, int version,
@@ -138,9 +149,8 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
char *calculated_digest, size_t digest_size, char *calculated_digest, size_t digest_size,
const char *salt, size_t salt_size) const char *salt, size_t salt_size)
{ {
char left_block[hash_block_size]; char *left_block, *data_buffer;
char data_buffer[data_block_size]; char read_digest[VERITY_MAX_DIGEST_SIZE];
char read_digest[digest_size];
size_t hash_per_block = 1 << get_bits_down(hash_block_size / digest_size); size_t hash_per_block = 1 << get_bits_down(hash_block_size / digest_size);
size_t digest_size_full = 1 << get_bits_up(digest_size); size_t digest_size_full = 1 << get_bits_up(digest_size);
uint64_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block; uint64_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block;
@@ -149,6 +159,9 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
unsigned i; unsigned i;
int r; int r;
if (digest_size > sizeof(read_digest))
return -EINVAL;
if (uint64_mult_overflow(&seek_rd, data_block, data_block_size) || if (uint64_mult_overflow(&seek_rd, data_block, data_block_size) ||
uint64_mult_overflow(&seek_wr, hash_block, hash_block_size)) { uint64_mult_overflow(&seek_wr, hash_block, hash_block_size)) {
log_err(cd, _("Device offset overflow.")); log_err(cd, _("Device offset overflow."));
@@ -165,6 +178,13 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
return -EIO; return -EIO;
} }
left_block = malloc(hash_block_size);
data_buffer = malloc(data_block_size);
if (!left_block || !data_buffer) {
r = -ENOMEM;
goto out;
}
memset(left_block, 0, hash_block_size); memset(left_block, 0, hash_block_size);
while (blocks_to_write--) { while (blocks_to_write--) {
left_bytes = hash_block_size; left_bytes = hash_block_size;
@@ -174,31 +194,37 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
blocks--; blocks--;
if (fread(data_buffer, data_block_size, 1, rd) != 1) { if (fread(data_buffer, data_block_size, 1, rd) != 1) {
log_dbg(cd, "Cannot read data device block."); log_dbg(cd, "Cannot read data device block.");
return -EIO; r = -EIO;
goto out;
} }
if (verify_hash_block(hash_name, version, if (verify_hash_block(hash_name, version,
calculated_digest, digest_size, calculated_digest, digest_size,
data_buffer, data_block_size, data_buffer, data_block_size,
salt, salt_size)) salt, salt_size)) {
return -EINVAL; r = -EINVAL;
goto out;
}
if (!wr) if (!wr)
break; break;
if (verify) { if (verify) {
if (fread(read_digest, digest_size, 1, wr) != 1) { if (fread(read_digest, digest_size, 1, wr) != 1) {
log_dbg(cd, "Cannot read digest form hash device."); log_dbg(cd, "Cannot read digest form hash device.");
return -EIO; r = -EIO;
goto out;
} }
if (memcmp(read_digest, calculated_digest, digest_size)) { if (memcmp(read_digest, calculated_digest, digest_size)) {
log_err(cd, _("Verification failed at position %" PRIu64 "."), log_err(cd, _("Verification failed at position %" PRIu64 "."),
ftello(rd) - data_block_size); ftello(rd) - data_block_size);
return -EPERM; r = -EPERM;
goto out;
} }
} else { } else {
if (fwrite(calculated_digest, digest_size, 1, wr) != 1) { if (fwrite(calculated_digest, digest_size, 1, wr) != 1) {
log_dbg(cd, "Cannot write digest to hash device."); log_dbg(cd, "Cannot write digest to hash device.");
return -EIO; r = -EIO;
goto out;
} }
} }
if (version == 0) { if (version == 0) {
@@ -208,10 +234,11 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
if (verify) { if (verify) {
r = verify_zero(cd, wr, digest_size_full - digest_size); r = verify_zero(cd, wr, digest_size_full - digest_size);
if (r) if (r)
return r; goto out;
} else if (fwrite(left_block, digest_size_full - digest_size, 1, wr) != 1) { } else if (fwrite(left_block, digest_size_full - digest_size, 1, wr) != 1) {
log_dbg(cd, "Cannot write spare area to hash device."); log_dbg(cd, "Cannot write spare area to hash device.");
return -EIO; r = -EIO;
goto out;
} }
} }
left_bytes -= digest_size_full; left_bytes -= digest_size_full;
@@ -221,22 +248,26 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
if (verify) { if (verify) {
r = verify_zero(cd , wr, left_bytes); r = verify_zero(cd , wr, left_bytes);
if (r) if (r)
return r; goto out;
} else if (fwrite(left_block, left_bytes, 1, wr) != 1) { } else if (fwrite(left_block, left_bytes, 1, wr) != 1) {
log_dbg(cd, "Cannot write remaining spare area to hash device."); log_dbg(cd, "Cannot write remaining spare area to hash device.");
return -EIO; r = -EIO;
goto out;
} }
} }
} }
r = 0;
return 0; out:
free(left_block);
free(data_buffer);
return r;
} }
static int VERITY_create_or_verify_hash(struct crypt_device *cd, bool verify, static int VERITY_create_or_verify_hash(struct crypt_device *cd, bool verify,
struct crypt_params_verity *params, struct crypt_params_verity *params,
char *root_hash, size_t digest_size) char *root_hash, size_t digest_size)
{ {
char calculated_digest[digest_size]; char calculated_digest[VERITY_MAX_DIGEST_SIZE];
FILE *data_file = NULL; FILE *data_file = NULL;
FILE *hash_file = NULL, *hash_file_2; FILE *hash_file = NULL, *hash_file_2;
uint64_t hash_level_block[VERITY_MAX_LEVELS]; uint64_t hash_level_block[VERITY_MAX_LEVELS];
@@ -253,6 +284,9 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd, bool verify,
device_path(crypt_data_device(cd)), params->data_size, device_path(crypt_data_device(cd)), params->data_size,
device_path(crypt_metadata_device(cd)), hash_position); device_path(crypt_metadata_device(cd)), hash_position);
if (digest_size > sizeof(calculated_digest))
return -EINVAL;
if (!params->data_size) { if (!params->data_size) {
r = device_size(crypt_data_device(cd), &dev_size); r = device_size(crypt_data_device(cd), &dev_size);
if (r < 0) if (r < 0)