diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 4dd68e59..d3c534f8 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -312,6 +312,7 @@ struct crypt_params_verity { uint32_t hash_block_size; /**< hash block size (in bytes) */ uint64_t data_size; /**< data area size (in data blocks) */ uint64_t hash_area_offset; /**< hash/header offset (in bytes) */ + uint64_t fec_area_offset; /**< FEC/header offset (in bytes) */ uint32_t fec_roots; /**< Reed-Solomon FEC roots */ uint32_t flags; /**< CRYPT_VERITY* flags */ }; diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index 50996fa7..be4a6923 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -390,8 +390,8 @@ static char *get_dm_verity_params(struct crypt_params_verity *vp, if (dmd->u.verity.fec_device) { num_options += 8; snprintf(fec_features, sizeof(fec_features)-1, - " use_fec_from_device %s fec_start 0 fec_blocks %" PRIu64 " fec_roots %" PRIu32, - device_block_path(dmd->u.verity.fec_device), + " use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 " fec_roots %" PRIu32, + device_block_path(dmd->u.verity.fec_device), dmd->u.verity.fec_offset, vp->data_size + dmd->u.verity.hash_blocks, vp->fec_roots); } else *fec_features = '\0'; diff --git a/lib/setup.c b/lib/setup.c index fa87503d..464f747a 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -730,6 +730,7 @@ static int _init_by_name_verity(struct crypt_device *cd, const char *name) cd->u.verity.hdr.data_block_size = params.data_block_size; cd->u.verity.hdr.hash_block_size = params.hash_block_size; cd->u.verity.hdr.hash_area_offset = dmd.u.verity.hash_offset; + cd->u.verity.hdr.fec_area_offset = dmd.u.verity.fec_offset; cd->u.verity.hdr.hash_type = params.hash_type; cd->u.verity.hdr.flags = params.flags; cd->u.verity.hdr.salt_size = params.salt_size; @@ -1023,6 +1024,11 @@ static int _crypt_format_verity(struct crypt_device *cd, return -EINVAL; } + if (params->fec_area_offset % 512) { + log_err(cd, _("Unsupported VERITY FEC offset.\n")); + return -EINVAL; + } + if (!(cd->type = strdup(CRYPT_VERITY))) return -ENOMEM; @@ -1069,6 +1075,7 @@ static int _crypt_format_verity(struct crypt_device *cd, cd->u.verity.hdr.data_block_size = params->data_block_size; cd->u.verity.hdr.hash_block_size = params->hash_block_size; cd->u.verity.hdr.hash_area_offset = params->hash_area_offset; + cd->u.verity.hdr.fec_area_offset = params->fec_area_offset; cd->u.verity.hdr.hash_type = params->hash_type; cd->u.verity.hdr.flags = params->flags; cd->u.verity.hdr.salt_size = params->salt_size; diff --git a/lib/utils_dm.h b/lib/utils_dm.h index bdab5915..6fa3868c 100644 --- a/lib/utils_dm.h +++ b/lib/utils_dm.h @@ -83,6 +83,7 @@ struct crypt_dm_active_device { uint64_t hash_offset; /* hash offset in blocks (not header) */ uint64_t hash_blocks; /* size of hash device (in hash blocks) */ + uint64_t fec_offset; /* FEC offset in blocks (not header) */ struct crypt_params_verity *vp; } verity; } u; diff --git a/lib/verity/fec.c b/lib/verity/fec.c index e8f8622c..9bb8c70d 100644 --- a/lib/verity/fec.c +++ b/lib/verity/fec.c @@ -67,6 +67,21 @@ struct fec_context { size_t ninputs; }; +/* Calculate FEC offset in hash blocks */ +uint64_t VERITY_FEC_offset_block(struct crypt_params_verity *params) +{ + uint64_t fec_offset = params->fec_area_offset; + + if (params->flags & CRYPT_VERITY_NO_HEADER) + return fec_offset / params->hash_block_size; + + fec_offset += sizeof(struct fec_sb); + //hash_offset += params->hash_block_size - 1; + + return fec_offset / params->hash_block_size; +} + + /* computes ceil(x / y) */ static inline uint64_t FEC_div_round_up(uint64_t x, uint64_t y) { @@ -302,6 +317,12 @@ int VERITY_FEC_create(struct crypt_device *cd, return -errno; } + if (lseek(fd, params->fec_area_offset, SEEK_SET) != params->fec_area_offset) { + log_dbg("Cannot seek to requested position in FEC device."); + TEMP_FAILURE_RETRY(close(fd)); + return -EIO; + } + /* input devices */ memset(inputs, 0, sizeof(inputs)); diff --git a/lib/verity/verity.c b/lib/verity/verity.c index 5120fd6e..93a6981a 100644 --- a/lib/verity/verity.c +++ b/lib/verity/verity.c @@ -261,6 +261,7 @@ int VERITY_activate(struct crypt_device *cd, dmd.u.verity.root_hash = root_hash; dmd.u.verity.root_hash_size = root_hash_size; dmd.u.verity.hash_offset = VERITY_hash_offset_block(verity_hdr); + dmd.u.verity.fec_offset = VERITY_FEC_offset_block(verity_hdr); dmd.u.verity.hash_blocks = VERITY_hash_blocks(cd, verity_hdr); dmd.flags = activation_flags; dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512; diff --git a/lib/verity/verity.h b/lib/verity/verity.h index a73c428b..2f94d2c2 100644 --- a/lib/verity/verity.h +++ b/lib/verity/verity.h @@ -60,6 +60,7 @@ int VERITY_create(struct crypt_device *cd, size_t root_hash_size); uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params); +uint64_t VERITY_FEC_offset_block(struct crypt_params_verity *params); uint64_t VERITY_hash_blocks(struct crypt_device *cd, struct crypt_params_verity *params); diff --git a/lib/verity/verity_hash.c b/lib/verity/verity_hash.c index f7d84e68..80a108a4 100644 --- a/lib/verity/verity_hash.c +++ b/lib/verity/verity_hash.c @@ -444,8 +444,8 @@ int VERITY_create(struct crypt_device *cd, uint64_t VERITY_hash_blocks(struct crypt_device *cd, struct crypt_params_verity *params) { - off_t hash_position = (off_t)params->hash_area_offset; - int levels; + off_t hash_position = 0; + int levels = 0; if (hash_levels(params->hash_block_size, crypt_get_volume_key_size(cd), params->data_size, &hash_position, &levels, NULL, NULL)) diff --git a/src/veritysetup.c b/src/veritysetup.c index 10706444..4fa83a3b 100644 --- a/src/veritysetup.c +++ b/src/veritysetup.c @@ -34,6 +34,7 @@ static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK; static uint64_t data_blocks = 0; static const char *salt_string = NULL; static uint64_t hash_offset = 0; +static uint64_t fec_offset = 0; static const char *opt_uuid = NULL; static int opt_restart_on_corruption = 0; static int opt_ignore_corruption = 0; @@ -76,6 +77,7 @@ static int _prepare_format(struct crypt_params_verity *params, params->hash_block_size = hash_block_size; params->data_size = data_blocks; params->hash_area_offset = hash_offset; + params->fec_area_offset = fec_offset; params->hash_type = hash_type; params->flags = flags; @@ -155,6 +157,7 @@ static int _activate(const char *dm_device, if (use_superblock) { params.flags = flags; params.hash_area_offset = hash_offset; + params.fec_area_offset = fec_offset; params.fec_device = fec_device; params.fec_roots = fec_roots; r = crypt_load(cd, CRYPT_VERITY, ¶ms); @@ -326,6 +329,7 @@ static int action_dump(int arg) return r; params.hash_area_offset = hash_offset; + params.fec_area_offset = fec_offset; r = crypt_load(cd, CRYPT_VERITY, ¶ms); if (!r) crypt_dump(cd); @@ -417,6 +421,7 @@ int main(int argc, const char **argv) { "data-blocks", 0, POPT_ARG_STRING, &popt_tmp, 1, N_("The number of blocks in the data file"), N_("blocks") }, { "fec-device", 0, POPT_ARG_STRING, &fec_device, 0, N_("Path to device with error correction data"), N_("path") }, { "hash-offset", 0, POPT_ARG_STRING, &popt_tmp, 2, N_("Starting offset on the hash device"), N_("bytes") }, + { "fec-offset", 0, POPT_ARG_STRING, &popt_tmp, 3, N_("Starting offset on the FEC device"), N_("bytes") }, { "hash", 'h', POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") }, { "salt", 's', POPT_ARG_STRING, &salt_string, 0, N_("Salt"), N_("hex string") }, { "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use."), NULL }, @@ -459,6 +464,9 @@ int main(int argc, const char **argv) case 2: hash_offset = ull_value; break; + case 3: + fec_offset = ull_value; + break; } if (r < 0)