Unify checking for LUKS2 intermediate device.

Use dm_get_active_iname that should be used on all places.

This function return integrioty device name if it shoudl be
maintained by LUKS2 context directly.

Code must not touch other devices that it does not own.
This commit is contained in:
Milan Broz
2025-05-03 21:26:03 +02:00
parent 352cda0302
commit d967c9aaf0
6 changed files with 76 additions and 58 deletions

View File

@@ -98,7 +98,6 @@ int device_alloc_no_check(struct device **device, const char *path);
void device_close(struct crypt_device *cd, struct device *device);
void device_free(struct crypt_device *cd, struct device *device);
const char *device_path(const struct device *device);
const char *device_dm_name(const struct device *device);
const char *device_block_path(const struct device *device);
void device_topology_alignment(struct crypt_device *cd,
struct device *device,
@@ -178,6 +177,7 @@ int lookup_by_disk_id(const char *dm_uuid);
int lookup_by_sysfs_uuid_field(const char *dm_uuid);
int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid);
int crypt_uuid_type_cmp(const char *dm_uuid, const char *type);
int crypt_uuid_integrity_cmp(const char *dm_uuid, const char *dmi_uuid);
size_t crypt_getpagesize(void);
unsigned crypt_cpusonline(void);

View File

@@ -3189,6 +3189,54 @@ int dm_get_iname(const char *name, char **iname, bool with_path)
return r < 0 ? -ENOMEM : 0;
}
char *dm_get_active_iname(struct crypt_device *cd, const char *name)
{
struct crypt_dm_active_device dmd = {}, dmdi = {};
struct dm_target *tgt = &dmd.segment, *tgti = &dmdi.segment;
char *ipath = NULL, *iname = NULL, *ret_iname = NULL;
struct stat st;
if (!name)
return NULL;
if (dm_query_device(cd, name, DM_ACTIVE_UUID, &dmd) < 0)
return NULL;
if (!single_segment(&dmd))
goto out;
if (tgt->type != DM_CRYPT || tgt->u.crypt.tag_size == 0)
goto out;
if (dm_get_iname(name, &iname, false) < 0)
goto out;
if (dm_get_iname(name, &ipath, true) < 0)
goto out;
if (stat(ipath, &st) < 0 || !S_ISBLK(st.st_mode))
goto out;
if (dm_query_device(cd, iname, DM_ACTIVE_UUID, &dmdi) < 0)
goto out;
if (single_segment(&dmdi) &&
tgti->type == DM_INTEGRITY &&
crypt_uuid_integrity_cmp(dmd.uuid, dmdi.uuid) == 0) {
ret_iname = iname;
iname = NULL;
}
out:
dm_targets_free(cd, &dmdi);
dm_targets_free(cd, &dmd);
free(CONST_CAST(void*)dmd.uuid);
free(CONST_CAST(void*)dmdi.uuid);
free(ipath);
free(iname);
return ret_iname;
}
int dm_is_dm_device(int major)
{
return dm_is_dm_major((uint32_t)major);

View File

@@ -2834,7 +2834,7 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
struct crypt_dm_active_device dmdc;
uint32_t opal_segment_number;
char **dep, deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = { 0 };
const char *namei = NULL;
char *iname = NULL;
struct crypt_lock_handle *reencrypt_lock = NULL, *opal_lh = NULL;
if (!dmd || !dmd->uuid || strncmp(CRYPT_LUKS2, dmd->uuid, sizeof(CRYPT_LUKS2)-1))
@@ -2856,8 +2856,8 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
tgt = &dmd->segment;
/* TODO: We have LUKS2 dependencies now */
if (single_segment(dmd) && tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)
namei = device_dm_name(tgt->data_device);
if (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size)
iname = dm_get_active_iname(cd, name);
r = dm_device_deps(cd, name, deps_uuid_prefix, deps, ARRAY_SIZE(deps));
if (r < 0)
@@ -2902,9 +2902,9 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
dm_targets_free(cd, &dmdc);
/* TODO: We have LUKS2 dependencies now */
if (r >= 0 && namei) {
log_dbg(cd, "Deactivating integrity device %s.", namei);
r = dm_remove_device(cd, namei, 0);
if (r >= 0 && iname) {
log_dbg(cd, "Deactivating integrity device %s.", iname);
r = dm_remove_device(cd, iname, 0);
}
if (!r) {
@@ -2972,6 +2972,7 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
out:
opal_exclusive_unlock(cd, opal_lh);
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
free(iname);
dep = deps;
while (*dep)
free(*dep++);

View File

@@ -550,7 +550,7 @@ int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid)
* compares two UUIDs returned by device-mapper (striped by cryptsetup)
* used for stacked LUKS2 & INTEGRITY devices
*/
static int crypt_uuid_integrity_cmp(const char *dm_uuid, const char *dmi_uuid)
int crypt_uuid_integrity_cmp(const char *dm_uuid, const char *dmi_uuid)
{
int i;
char *str, *stri;
@@ -1310,7 +1310,8 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
bool found = false;
char **dep, *cipher_spec = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char deps_uuid_prefix[40], *deps[MAX_DM_DEPS+1] = {};
const char *dev, *namei;
const char *dev;
char *iname = NULL;
int key_nums, r;
struct crypt_dm_active_device dmd, dmdi = {}, dmdep = {};
struct dm_target *tgt = &dmd.segment, *tgti = &dmdi.segment;
@@ -1358,16 +1359,13 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
dep = deps;
if (tgt->type == DM_CRYPT && tgt->u.crypt.integrity && (namei = device_dm_name(tgt->data_device))) {
r = dm_query_device(cd, namei, DM_ACTIVE_DEVICE, &dmdi);
if (tgt->type == DM_CRYPT && tgt->u.crypt.tag_size &&
(iname = dm_get_active_iname(cd, name))) {
r = dm_query_device(cd, iname, DM_ACTIVE_DEVICE, &dmdi);
free(iname);
if (r < 0)
goto out;
if (!single_segment(&dmdi) || tgti->type != DM_INTEGRITY) {
log_dbg(cd, "Unsupported device table detected in %s.", namei);
r = -EINVAL;
goto out;
}
/*
* Data device for crypt with integrity is not dm-integrity device,
* but always the device underlying dm-integrity.
@@ -4215,21 +4213,8 @@ int crypt_suspend(struct crypt_device *cd,
}
/* check UUID of integrity device underneath crypt device */
if (crypt_get_integrity_tag_size(cd)) {
r = dm_get_iname(name, &iname, false);
if (r)
goto out;
r = dm_query_device(cd, iname, DM_ACTIVE_UUID, &dmdi);
if (r < 0)
goto out;
r = crypt_uuid_integrity_cmp(dmd.uuid, dmdi.uuid);
if (r < 0) {
log_dbg(cd, "Integrity device uuid: %s mismatches crypt device uuid %s", dmdi.uuid, dmd.uuid);
goto out;
}
}
if (crypt_get_integrity_tag_size(cd))
iname = dm_get_active_iname(cd, name);
r = dm_status_suspended(cd, name);
if (r < 0)
@@ -4269,7 +4254,7 @@ int crypt_suspend(struct crypt_device *cd,
}
/* Suspend integrity device underneath; keep crypt suspended if it fails */
if (crypt_get_integrity_tag_size(cd)) {
if (iname) {
r = dm_suspend_device(cd, iname, 0);
if (r)
log_err(cd, _("Error during suspending device %s."), iname);
@@ -4481,14 +4466,12 @@ static int resume_luks2_by_volume_key(struct crypt_device *cd,
}
}
if (crypt_get_integrity_tag_size(cd)) {
r = dm_get_iname(name, &iname, false);
if (r)
goto out;
if (crypt_get_integrity_tag_size(cd) &&
(iname = dm_get_active_iname(cd, name))) {
r = dm_resume_device(cd, iname, 0);
if (r)
log_err(cd, _("Error during resuming device %s."), iname);
free(iname);
}
if (enc_type == CRYPT_OPAL_HW_ONLY)
@@ -4517,7 +4500,6 @@ out:
crypt_free_volume_key(zerokey);
crypt_free_volume_key(opal_key);
crypt_free_volume_key(crypt_key);
free(iname);
return r;
}
@@ -5868,7 +5850,7 @@ int crypt_get_active_device(struct crypt_device *cd, const char *name,
{
int r;
struct crypt_dm_active_device dmd, dmdi = {};
const char *namei = NULL;
char *iname = NULL;
struct dm_target *tgt = &dmd.segment;
uint64_t min_offset = UINT64_MAX;
@@ -5880,10 +5862,11 @@ int crypt_get_active_device(struct crypt_device *cd, const char *name,
return r;
/* For LUKS2 with integrity we need flags from underlying dm-integrity */
if (isLUKS2(cd->type) && crypt_get_integrity_tag_size(cd) && single_segment(&dmd)) {
namei = device_dm_name(tgt->data_device);
if (namei && dm_query_device(cd, namei, 0, &dmdi) >= 0)
if (isLUKS2(cd->type) && crypt_get_integrity_tag_size(cd) &&
(iname = dm_get_active_iname(cd, name))) {
if (dm_query_device(cd, iname, 0, &dmdi) >= 0)
dmd.flags |= dmdi.flags;
free(iname);
}
if (cd && isTCRYPT(cd->type)) {

View File

@@ -476,21 +476,6 @@ const char *device_block_path(const struct device *device)
return device->path;
}
/* Get device-mapper name of device (if possible) */
const char *device_dm_name(const struct device *device)
{
const char *dmdir = dm_get_dir();
size_t dmdir_len = strlen(dmdir);
if (!device)
return NULL;
if (strncmp(device->path, dmdir, dmdir_len))
return NULL;
return &device->path[dmdir_len+1];
}
/* Get path to device / file */
const char *device_path(const struct device *device)
{

View File

@@ -223,6 +223,7 @@ int dm_cancel_deferred_removal(const char *name);
const char *dm_get_dir(void);
int dm_get_iname(const char *name, char **iname, bool with_path);
char *dm_get_active_iname(struct crypt_device *cd, const char *name);
int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type);