Verity: dump device sizes.

Calculating device sizes for verity devices is a little bit tricky,
Data, hash and FEC can share devices or it can be a separate devices.

This patch prints used device sizes in veritysetup dump command,
but it requires that user specifies all values that are not stored
in superblock (like a FEC device and FEC roots).
This commit is contained in:
Milan Broz
2022-05-09 13:47:24 +02:00
parent 0c80ee6c28
commit 9e7894081f
5 changed files with 70 additions and 13 deletions

View File

@@ -5116,7 +5116,8 @@ int crypt_dump(struct crypt_device *cd)
return LUKS2_hdr_dump(cd, &cd->u.luks2.hdr);
else if (isVERITY(cd->type))
return VERITY_dump(cd, &cd->u.verity.hdr,
cd->u.verity.root_hash, cd->u.verity.root_hash_size);
cd->u.verity.root_hash, cd->u.verity.root_hash_size,
cd->u.verity.fec_device);
else if (isTCRYPT(cd->type))
return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
else if (isINTEGRITY(cd->type))

View File

@@ -355,15 +355,40 @@ out:
int VERITY_dump(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *root_hash,
unsigned int root_hash_size)
unsigned int root_hash_size,
struct device *fec_device)
{
uint64_t hash_blocks, verity_blocks, fec_blocks = 0, rs_blocks = 0;
bool fec_on_hash_device = false;
hash_blocks = VERITY_hash_blocks(cd, verity_hdr);
verity_blocks = VERITY_hash_offset_block(verity_hdr) + hash_blocks;
if (fec_device && verity_hdr->fec_roots) {
fec_blocks = VERITY_FEC_blocks(cd, fec_device, verity_hdr);
rs_blocks = VERITY_FEC_RS_blocks(fec_blocks, verity_hdr->fec_roots);
fec_on_hash_device = device_is_identical(crypt_metadata_device(cd), fec_device) > 0;
/*
* No way to access fec_area_offset directly.
* Assume FEC area starts directly after hash blocks.
*/
if (fec_on_hash_device)
verity_blocks += rs_blocks;
}
log_std(cd, "VERITY header information for %s\n", device_path(crypt_metadata_device(cd)));
log_std(cd, "UUID: \t%s\n", crypt_get_uuid(cd) ?: "");
log_std(cd, "Hash type: \t%u\n", verity_hdr->hash_type);
log_std(cd, "Data blocks: \t%" PRIu64 "\n", verity_hdr->data_size);
log_std(cd, "Data block size: \t%u\n", verity_hdr->data_block_size);
log_std(cd, "Hash blocks: \t%" PRIu64 "\n", hash_blocks);
log_std(cd, "Hash block size: \t%u\n", verity_hdr->hash_block_size);
log_std(cd, "Hash algorithm: \t%s\n", verity_hdr->hash_name);
if (fec_device && fec_blocks) {
log_std(cd, "FEC RS roots: \t%" PRIu32 "\n", verity_hdr->fec_roots);
log_std(cd, "FEC blocks: \t%" PRIu64 "\n", rs_blocks);
}
log_std(cd, "Salt: \t");
if (verity_hdr->salt_size)
crypt_log_hex(cd, verity_hdr->salt, verity_hdr->salt_size, "", 0, NULL);
@@ -377,5 +402,12 @@ int VERITY_dump(struct crypt_device *cd,
log_std(cd, "\n");
}
/* As dump can take only hash device, we have no idea about offsets here. */
if (verity_hdr->hash_area_offset == 0)
log_std(cd, "Hash device size: \t%" PRIu64 " [bytes]\n", verity_blocks * verity_hdr->hash_block_size);
if (fec_device && verity_hdr->fec_area_offset == 0 && fec_blocks && !fec_on_hash_device)
log_std(cd, "FEC device size: \t%" PRIu64 " [bytes]\n", rs_blocks * verity_hdr->data_block_size);
return 0;
}

View File

@@ -74,12 +74,14 @@ uint64_t VERITY_hash_blocks(struct crypt_device *cd, struct crypt_params_verity
uint64_t VERITY_FEC_blocks(struct crypt_device *cd,
struct device *fec_device,
struct crypt_params_verity *params);
uint64_t VERITY_FEC_RS_blocks(uint64_t blocks, uint32_t roots);
int VERITY_UUID_generate(char **uuid_string);
int VERITY_dump(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr,
const char *root_hash,
unsigned int root_hash_size);
unsigned int root_hash_size,
struct device *fec_device);
#endif

View File

@@ -202,6 +202,22 @@ out:
return r;
}
static int VERITY_FEC_validate(struct crypt_device *cd, struct crypt_params_verity *params)
{
if (params->data_block_size != params->hash_block_size) {
log_err(cd, _("Block sizes must match for FEC."));
return -EINVAL;
}
if (params->fec_roots > FEC_RSM - FEC_MIN_RSN ||
params->fec_roots < FEC_RSM - FEC_MAX_RSN) {
log_err(cd, _("Invalid number of parity bytes."));
return -EINVAL;
}
return 0;
}
int VERITY_FEC_process(struct crypt_device *cd,
struct crypt_params_verity *params,
struct device *fec_device, int check_fec,
@@ -224,16 +240,9 @@ int VERITY_FEC_process(struct crypt_device *cd,
};
/* validate parameters */
if (params->data_block_size != params->hash_block_size) {
log_err(cd, _("Block sizes must match for FEC."));
return -EINVAL;
}
if (params->fec_roots > FEC_RSM - FEC_MIN_RSN ||
params->fec_roots < FEC_RSM - FEC_MAX_RSN) {
log_err(cd, _("Invalid number of parity bytes."));
return -EINVAL;
}
r = VERITY_FEC_validate(cd, params);
if (r < 0)
return r;
if (!inputs[0].count) {
log_err(cd, _("Invalid FEC segment length."));
@@ -281,12 +290,16 @@ out:
return r;
}
/* All blocks that are covered by FEC */
uint64_t VERITY_FEC_blocks(struct crypt_device *cd,
struct device *fec_device,
struct crypt_params_verity *params)
{
uint64_t blocks = 0;
if (!fec_device || VERITY_FEC_validate(cd, params) < 0)
return 0;
/*
* FEC covers this data:
* | protected data | hash area | padding (optional foreign metadata) |
@@ -315,3 +328,9 @@ uint64_t VERITY_FEC_blocks(struct crypt_device *cd,
return blocks;
}
/* Blocks needed to store FEC data, blocks must be validated/calculated by VERITY_FEC_blocks() */
uint64_t VERITY_FEC_RS_blocks(uint64_t blocks, uint32_t roots)
{
return FEC_div_round_up(blocks, FEC_RSM - roots) * roots;
}

View File

@@ -459,6 +459,9 @@ static int action_dump(void)
params.hash_area_offset = ARG_UINT64(OPT_HASH_OFFSET_ID);
params.fec_area_offset = ARG_UINT64(OPT_FEC_OFFSET_ID);
params.fec_device = ARG_STR(OPT_FEC_DEVICE_ID);
params.fec_roots = ARG_UINT32(OPT_FEC_ROOTS_ID);
r = crypt_load(cd, CRYPT_VERITY, &params);
if (!r)
crypt_dump(cd);