Add strict compare volume key comparison for non-LUKS2 devices.

[Modified by Ondrej Kozina]
This commit is contained in:
Milan Broz
2024-11-20 22:51:20 +01:00
parent f421ec0800
commit 6123ea2e0b

View File

@@ -3173,6 +3173,38 @@ int crypt_repair(struct crypt_device *cd,
/* compare volume keys */
static int _compare_volume_keys(struct volume_key *svk, struct volume_key *tvk)
{
if (svk == tvk)
return 0;
if (!svk || !tvk)
return 1;
if (crypt_volume_key_length(svk) != crypt_volume_key_length(tvk))
return 1;
/* No switch between keyring and direct key specification */
if ((!crypt_volume_key_description(svk) && crypt_volume_key_description(tvk)) ||
(crypt_volume_key_description(svk) && !crypt_volume_key_description(tvk)) ||
(!crypt_volume_key_is_set(svk) && crypt_volume_key_is_set(tvk)) ||
(crypt_volume_key_is_set(svk) && !crypt_volume_key_is_set(tvk)))
return 1;
if (crypt_volume_key_description(svk) &&
(crypt_volume_key_kernel_key_type(svk) != crypt_volume_key_kernel_key_type(tvk) ||
strcmp(crypt_volume_key_description(svk), crypt_volume_key_description(tvk))))
return 1;
if (crypt_volume_key_is_set(svk) &&
crypt_backend_memeq(crypt_volume_key_get_key(svk),
crypt_volume_key_get_key(tvk),
crypt_volume_key_length(svk)))
return 1;
return 0;
}
static int _compare_volume_keys_luks2(struct volume_key *svk, struct volume_key *tvk)
{
if (svk == tvk)
return 0;
@@ -3258,7 +3290,12 @@ static int _compare_crypt_devices(struct crypt_device *cd,
if (crypt_volume_key_length(tgt->u.crypt.vk) == 0 && crypt_is_cipher_null(tgt->u.crypt.cipher))
log_dbg(cd, "Existing device uses cipher null. Skipping key comparison.");
else if (_compare_volume_keys(src->u.crypt.vk, tgt->u.crypt.vk)) {
else if (cd && isLUKS2(cd->type)) {
if (_compare_volume_keys_luks2(src->u.crypt.vk, tgt->u.crypt.vk)) {
log_dbg(cd, "Keys in LUKS2 context and target device do not match.");
goto out;
}
} else if (_compare_volume_keys(src->u.crypt.vk, tgt->u.crypt.vk)) {
log_dbg(cd, "Keys in context and target device do not match.");
goto out;
}
@@ -3392,9 +3429,14 @@ static int _reload_device(struct crypt_device *cd, const char *name,
struct crypt_dm_active_device tdmd;
struct dm_target *src, *tgt = &tdmd.segment;
if (!cd || !cd->type || !name || !(sdmd->flags & CRYPT_ACTIVATE_REFRESH))
assert(cd);
assert(sdmd);
if (!cd->type || !name || !(sdmd->flags & CRYPT_ACTIVATE_REFRESH))
return -EINVAL;
src = &sdmd->segment;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_INTEGRITY_PARAMS |
@@ -3418,28 +3460,24 @@ static int _reload_device(struct crypt_device *cd, const char *name,
goto out;
}
src = &sdmd->segment;
/* Changing read only flag for active device makes no sense */
if (tdmd.flags & CRYPT_ACTIVATE_READONLY)
sdmd->flags |= CRYPT_ACTIVATE_READONLY;
else
sdmd->flags &= ~CRYPT_ACTIVATE_READONLY;
if (tgt->type == DM_CRYPT && sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = crypt_volume_key_set_description(tgt->u.crypt.vk,
crypt_volume_key_description(src->u.crypt.vk),
crypt_volume_key_kernel_key_type(src->u.crypt.vk));
if (r)
goto out;
} else if (tgt->type == DM_CRYPT) {
/*
* Only LUKS2 allows altering between volume key
* passed by hexbyte representation and reference
* to kernel keyring service.
*
* To make it easier pass src key directly after
* it was properly verified in crypt_compare_dm_devices
* call above.
*/
if (isLUKS2(cd->type) && tgt->type == DM_CRYPT && src->u.crypt.vk) {
crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = crypt_alloc_volume_key(crypt_volume_key_length(src->u.crypt.vk),
crypt_volume_key_get_key(src->u.crypt.vk));
if (!tgt->u.crypt.vk) {
r = -ENOMEM;
goto out;
}
tgt->u.crypt.vk = src->u.crypt.vk;
}
if (tgt->type == DM_CRYPT)
@@ -3459,6 +3497,10 @@ static int _reload_device(struct crypt_device *cd, const char *name,
r = dm_reload_device(cd, name, &tdmd, dmflags, 1);
out:
/* otherwise dm_targets_free would free src key */
if (src->u.crypt.vk == tgt->u.crypt.vk)
tgt->u.crypt.vk = NULL;
dm_targets_free(cd, &tdmd);
free(CONST_CAST(void*)tdmd.uuid);
@@ -3478,9 +3520,16 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
struct device *data_device = NULL;
bool clear = false;
if (!cd || !cd->type || !name || !iname || !(sdmd->flags & CRYPT_ACTIVATE_REFRESH))
assert(cd);
assert(sdmd);
assert(sdmdi);
if (!cd->type || !name || !iname || !(sdmd->flags & CRYPT_ACTIVATE_REFRESH))
return -EINVAL;
src = &sdmd->segment;
srci = &sdmdi->segment;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY, &tdmd);
@@ -3520,9 +3569,6 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
goto out;
}
src = &sdmd->segment;
srci = &sdmdi->segment;
r = device_alloc(cd, &data_device, ipath);
if (r < 0)
goto out;
@@ -3551,21 +3597,13 @@ static int _reload_device_with_integrity(struct crypt_device *cd,
else
sdmdi->flags &= ~CRYPT_ACTIVATE_READONLY;
if (sdmd->flags & CRYPT_ACTIVATE_KEYRING_KEY) {
r = crypt_volume_key_set_description(tgt->u.crypt.vk,
crypt_volume_key_description(src->u.crypt.vk),
crypt_volume_key_kernel_key_type(src->u.crypt.vk));
if (r)
goto out;
} else {
crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = crypt_alloc_volume_key(crypt_volume_key_length(src->u.crypt.vk),
crypt_volume_key_get_key(src->u.crypt.vk));
if (!tgt->u.crypt.vk) {
r = -ENOMEM;
goto out;
}
}
/*
* To make it easier pass src key directly after
* it was properly verified in crypt_compare_dm_devices
* call above.
*/
crypt_free_volume_key(tgt->u.crypt.vk);
tgt->u.crypt.vk = src->u.crypt.vk;
r = device_block_adjust(cd, src->data_device, DEV_OK,
src->u.crypt.offset, &sdmd->size, NULL);
@@ -3631,6 +3669,9 @@ out:
dm_resume_device(cd, iname, 0);
}
/* otherwise dm_targets_free would free src key */
if (tgt->u.crypt.vk == src->u.crypt.vk)
tgt->u.crypt.vk = NULL;
dm_targets_free(cd, &tdmd);
dm_targets_free(cd, &tdmdi);
free(CONST_CAST(void*)tdmdi.uuid);