Skip to content

Commit

Permalink
Suspend and resume also dm-integrity device with AEAD.
Browse files Browse the repository at this point in the history
Currently we suspend top-level device only.

With OPAL, the underlying device will start to return errors
once OPAL LR is locked.

If the dm-integrity device is not suspended, regular journal
flush corrupts the device (journal write failure),
corrupting data above it.

Suspending the whole stack should fix the issue.
  • Loading branch information
mbroz committed Nov 22, 2023
1 parent 0f51b5b commit 6b2cf68
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 7 deletions.
12 changes: 12 additions & 0 deletions lib/libdevmapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -3041,6 +3041,18 @@ const char *dm_get_dir(void)
return dm_dir();
}

int dm_get_iname(const char *name, char **iname, bool with_path)
{
int r;

if (with_path)
r = asprintf(iname, "%s/%s_dif", dm_get_dir(), name);
else
r = asprintf(iname, "%s_dif", name);

return r < 0 ? -ENOMEM : 0;
}

int dm_is_dm_device(int major)
{
return dm_is_dm_major((uint32_t)major);
Expand Down
92 changes: 85 additions & 7 deletions lib/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,41 @@ int crypt_uuid_cmp(const char *dm_uuid, const char *hdr_uuid)
return 0;
}

/*
* 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 i;
char *str, *stri;

if (!dm_uuid || !dmi_uuid)
return -EINVAL;

/* skip beyond LUKS2_HW_OPAL prefix */
if (!strncmp(dm_uuid, CRYPT_LUKS2_HW_OPAL, strlen(CRYPT_LUKS2_HW_OPAL)))
dm_uuid = dm_uuid + strlen(CRYPT_LUKS2_HW_OPAL);

str = strchr(dm_uuid, '-');
if (!str)
return -EINVAL;

stri = strchr(dmi_uuid, '-');
if (!stri)
return -EINVAL;

for (i = 1; str[i] && str[i] != '-'; i++) {
if (!stri[i])
return -EINVAL;

if (str[i] != stri[i])
return -EINVAL;
}

return 0;
}

/*
* compares type of active device to provided string
*/
Expand Down Expand Up @@ -3891,10 +3926,10 @@ int crypt_suspend(struct crypt_device *cd,
bool dm_opal_uuid;
crypt_status_info ci;
int r;
struct crypt_dm_active_device dmd;
struct crypt_dm_active_device dmd, dmdi = {};
uint32_t opal_segment_number = 1, dmflags = DM_SUSPEND_WIPE_KEY;
struct dm_target *tgt = &dmd.segment;
char *key_desc = NULL;
char *key_desc = NULL, *iname = NULL;

if (!cd || !name)
return -EINVAL;
Expand Down Expand Up @@ -3950,6 +3985,23 @@ int crypt_suspend(struct crypt_device *cd,
goto out;
}

/* 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;
}
}

r = dm_status_suspended(cd, name);
if (r < 0)
goto out;
Expand Down Expand Up @@ -3989,14 +4041,24 @@ int crypt_suspend(struct crypt_device *cd,
goto out;
}

/* Suspend integrity device underneath; keep crypt suspended if it fails */
if (crypt_get_integrity_tag_size(cd)) {
r = dm_suspend_device(cd, iname, 0);
if (r)
log_err(cd, _("Error during suspending device %s."), iname);
}

crypt_drop_keyring_key_by_description(cd, key_desc, cd->keyring_key_type);

if (dm_opal_uuid && (!crypt_data_device(cd) || opal_lock(cd, crypt_data_device(cd), opal_segment_number)))
log_err(cd, _("Device %s was suspended but hardware OPAL device cannot be locked."), name);
out:
free(key_desc);
free(iname);
dm_targets_free(cd, &dmd);
dm_targets_free(cd, &dmdi);
free(CONST_CAST(void*)dmd.uuid);
free(CONST_CAST(void*)dmdi.uuid);
return r;
}

Expand Down Expand Up @@ -4077,6 +4139,7 @@ static int resume_luks2_by_volume_key(struct crypt_device *cd,
uint32_t opal_segment_number;
key_serial_t user_vk_kid = 0;
struct volume_key *p_crypt = vk, *p_opal = NULL, *zerokey = NULL, *crypt_key = NULL, *opal_key = NULL;
char *iname = NULL;

assert(digest >= 0);
assert(vk && crypt_volume_key_get_id(vk) == digest);
Expand Down Expand Up @@ -4140,6 +4203,16 @@ 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;

r = dm_resume_device(cd, iname, 0);
if (r)
log_err(cd, _("Error during resuming device %s."), iname);
}

if (enc_type == CRYPT_OPAL_HW_ONLY)
r = dm_resume_device(cd, name, 0);
else
Expand All @@ -4163,6 +4236,7 @@ static int resume_luks2_by_volume_key(struct crypt_device *cd,
crypt_free_volume_key(zerokey);
crypt_free_volume_key(opal_key);
crypt_free_volume_key(crypt_key);
free(iname);

return r;
}
Expand Down Expand Up @@ -4743,15 +4817,18 @@ int create_or_reload_device_with_integrity(struct crypt_device *cd, const char *
struct crypt_dm_active_device *dmdi)
{
int r;
const char *iname = NULL;
char *ipath = NULL;
char *iname = NULL, *ipath = NULL;

if (!type || !name || !dmd || !dmdi)
return -EINVAL;

if (asprintf(&ipath, "%s/%s_dif", dm_get_dir(), name) < 0)
return -ENOMEM;
iname = ipath + strlen(dm_get_dir()) + 1;
r = dm_get_iname(name, &iname, false);
if (r)
goto out;

r = dm_get_iname(name, &ipath, true);
if (r)
goto out;

/* drop CRYPT_ACTIVATE_REFRESH flag if any device is inactive */
r = check_devices(cd, name, iname, &dmd->flags);
Expand All @@ -4764,6 +4841,7 @@ int create_or_reload_device_with_integrity(struct crypt_device *cd, const char *
r = _create_device_with_integrity(cd, type, name, iname, ipath, dmd, dmdi);
out:
free(ipath);
free(iname);

return r;
}
Expand Down
1 change: 1 addition & 0 deletions lib/utils_dm.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ int dm_clear_device(struct crypt_device *cd, const char *name);
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);

int lookup_dm_dev_by_uuid(struct crypt_device *cd, const char *uuid, const char *type);

Expand Down

0 comments on commit 6b2cf68

Please sign in to comment.