Add support for resizing raw integrity devices.

This commit is contained in:
daniel.zatovic
2022-02-16 13:20:09 +01:00
parent 45b808c186
commit 9b8a872006

View File

@@ -2434,7 +2434,7 @@ static int _compare_device_types(struct crypt_device *cd,
log_dbg(cd, "Unexpected uuid prefix %s in target device.", tgt->uuid); log_dbg(cd, "Unexpected uuid prefix %s in target device.", tgt->uuid);
return -EINVAL; return -EINVAL;
} }
} else { } else if (!isINTEGRITY(cd->type)) {
log_dbg(cd, "Unsupported device type %s for reload.", cd->type ?: "<empty>"); log_dbg(cd, "Unsupported device type %s for reload.", cd->type ?: "<empty>");
return -ENOTSUP; return -ENOTSUP;
} }
@@ -2595,13 +2595,13 @@ static int _reload_device(struct crypt_device *cd, const char *name,
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER | r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY, &tdmd); DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_INTEGRITY_PARAMS | DM_ACTIVE_JOURNAL_CRYPT_KEY | DM_ACTIVE_JOURNAL_MAC_KEY, &tdmd);
if (r < 0) { if (r < 0) {
log_err(cd, _("Device %s is not active."), name); log_err(cd, _("Device %s is not active."), name);
return -EINVAL; return -EINVAL;
} }
if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || tgt->u.crypt.tag_size) { if (!single_segment(&tdmd) || (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY) || (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)) {
r = -ENOTSUP; r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), name); log_err(cd, _("Unsupported parameters on device %s."), name);
goto out; goto out;
@@ -2625,13 +2625,46 @@ static int _reload_device(struct crypt_device *cd, const char *name,
r = crypt_volume_key_set_description(tgt->u.crypt.vk, src->u.crypt.vk->key_description); r = crypt_volume_key_set_description(tgt->u.crypt.vk, src->u.crypt.vk->key_description);
if (r) if (r)
goto out; goto out;
} else { } else if (tgt->type == DM_CRYPT) {
crypt_free_volume_key(tgt->u.crypt.vk); crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = crypt_alloc_volume_key(src->u.crypt.vk->keylength, src->u.crypt.vk->key); tgt->u.crypt.vk = crypt_alloc_volume_key(src->u.crypt.vk->keylength, src->u.crypt.vk->key);
if (!tgt->u.crypt.vk) { if (!tgt->u.crypt.vk) {
r = -ENOMEM; r = -ENOMEM;
goto out; goto out;
} }
} else if (tgt->type == DM_INTEGRITY) {
crypt_free_volume_key(tgt->u.integrity.vk);
tgt->u.integrity.vk = NULL;
if (src->u.integrity.vk) {
tgt->u.integrity.vk = crypt_alloc_volume_key(src->u.integrity.vk->keylength, src->u.integrity.vk->key);
if (!tgt->u.integrity.vk) {
r = -ENOMEM;
goto out;
}
}
crypt_free_volume_key(tgt->u.integrity.journal_integrity_key);
tgt->u.integrity.journal_integrity_key = NULL;
if (src->u.integrity.journal_integrity_key) {
tgt->u.integrity.journal_integrity_key = crypt_alloc_volume_key(src->u.integrity.journal_integrity_key->keylength, src->u.integrity.journal_integrity_key->key);
if (!tgt->u.integrity.journal_integrity_key) {
r = -ENOMEM;
goto out;
}
}
crypt_free_volume_key(tgt->u.integrity.journal_crypt_key);
tgt->u.integrity.journal_crypt_key = NULL;
if (src->u.integrity.journal_crypt_key) {
tgt->u.integrity.journal_crypt_key = crypt_alloc_volume_key(src->u.integrity.journal_crypt_key->keylength, src->u.integrity.journal_crypt_key->key);
if (!tgt->u.integrity.journal_crypt_key) {
r = -ENOMEM;
goto out;
}
}
} }
r = device_block_adjust(cd, src->data_device, DEV_OK, r = device_block_adjust(cd, src->data_device, DEV_OK,
@@ -2824,6 +2857,7 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
{ {
struct crypt_dm_active_device dmdq, dmd = {}; struct crypt_dm_active_device dmdq, dmd = {};
struct dm_target *tgt = &dmdq.segment; struct dm_target *tgt = &dmdq.segment;
struct crypt_params_integrity params = {};
int r; int r;
/* /*
@@ -2842,12 +2876,12 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
log_dbg(cd, "Resizing device %s to %" PRIu64 " sectors.", name, new_size); log_dbg(cd, "Resizing device %s to %" PRIu64 " sectors.", name, new_size);
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY, &dmdq); r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_INTEGRITY_PARAMS | DM_ACTIVE_JOURNAL_CRYPT_KEY | DM_ACTIVE_JOURNAL_MAC_KEY, &dmdq);
if (r < 0) { if (r < 0) {
log_err(cd, _("Device %s is not active."), name); log_err(cd, _("Device %s is not active."), name);
return -EINVAL; return -EINVAL;
} }
if (!single_segment(&dmdq) || tgt->type != DM_CRYPT) { if (!single_segment(&dmdq) || (tgt->type != DM_CRYPT && tgt->type != DM_INTEGRITY)) {
log_dbg(cd, "Unsupported device table detected in %s.", name); log_dbg(cd, "Unsupported device table detected in %s.", name);
r = -EINVAL; r = -EINVAL;
goto out; goto out;
@@ -2879,12 +2913,44 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
log_err(cd, _("Cannot resize loop device.")); log_err(cd, _("Cannot resize loop device."));
} }
/*
* Integrity device metadata are maintained by the kernel. We need to
* reload the device (with the same parameters) and let the kernel
* calculate the maximum size of integrity device and store it in the
* superblock.
*/
if (!new_size && tgt->type == DM_INTEGRITY) {
dmd.size = dmdq.size;
dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH | CRYPT_ACTIVATE_PRIVATE;
r = crypt_get_integrity_info(cd, &params);
if (r)
goto out;
r = dm_integrity_target_set(cd, &dmd.segment, 0, dmdq.segment.size,
crypt_metadata_device(cd), crypt_data_device(cd),
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
crypt_get_sector_size(cd), tgt->u.integrity.vk, tgt->u.integrity.journal_crypt_key, tgt->u.integrity.journal_integrity_key, &params);
if (r)
goto out;
r = _reload_device(cd, name, &dmd);
if (r)
goto out;
r = INTEGRITY_data_sectors(cd, crypt_metadata_device(cd),
crypt_get_data_offset(cd) * SECTOR_SIZE, &new_size);
if (r < 0)
return r;
log_dbg(cd, "Maximum integrity device size from kernel %lu", new_size);
}
r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK, r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK,
crypt_get_data_offset(cd), &new_size, &dmdq.flags); crypt_get_data_offset(cd), &new_size, &dmdq.flags);
if (r) if (r)
goto out; goto out;
if (MISALIGNED(new_size, tgt->u.crypt.sector_size >> SECTOR_SHIFT)) { if (MISALIGNED(new_size, (tgt->type == DM_CRYPT ? tgt->u.crypt.sector_size : tgt->u.integrity.sector_size) >> SECTOR_SHIFT)) {
log_err(cd, _("Device size is not aligned to requested sector size.")); log_err(cd, _("Device size is not aligned to requested sector size."));
r = -EINVAL; r = -EINVAL;
goto out; goto out;
@@ -2899,13 +2965,27 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
dmd.uuid = crypt_get_uuid(cd); dmd.uuid = crypt_get_uuid(cd);
dmd.size = new_size; dmd.size = new_size;
dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH; dmd.flags = dmdq.flags | CRYPT_ACTIVATE_REFRESH;
r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd),
tgt->u.crypt.vk, crypt_get_cipher_spec(cd), if (tgt->type == DM_CRYPT) {
crypt_get_iv_offset(cd), crypt_get_data_offset(cd), r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd),
crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd), tgt->u.crypt.vk, crypt_get_cipher_spec(cd),
crypt_get_sector_size(cd)); crypt_get_iv_offset(cd), crypt_get_data_offset(cd),
if (r < 0) crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd),
goto out; crypt_get_sector_size(cd));
if (r < 0)
goto out;
} else if (tgt->type == DM_INTEGRITY) {
r = crypt_get_integrity_info(cd, &params);
if (r)
goto out;
r = dm_integrity_target_set(cd, &dmd.segment, 0, new_size,
crypt_metadata_device(cd), crypt_data_device(cd),
crypt_get_integrity_tag_size(cd), crypt_get_data_offset(cd),
crypt_get_sector_size(cd), tgt->u.integrity.vk, tgt->u.integrity.journal_crypt_key, tgt->u.integrity.journal_integrity_key, &params);
if (r)
goto out;
}
if (new_size == dmdq.size) { if (new_size == dmdq.size) {
log_dbg(cd, "Device has already requested size %" PRIu64 log_dbg(cd, "Device has already requested size %" PRIu64