opal: do not always re-lock range on failed activation.

If activation fails due to already active dm mapping
we must not automatically re-lock the OPAL range since
it would break the original active device.
This commit is contained in:
Ondrej Kozina
2023-12-05 16:31:39 +01:00
committed by Milan Broz
parent 31027b9240
commit 2e978c8776
3 changed files with 56 additions and 39 deletions

View File

@@ -279,7 +279,9 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
const uint64_t *check_offset_sectors,
const uint64_t *check_length_sectors,
bool *check_read_locked,
bool *check_write_locked)
bool *check_write_locked,
bool *ret_read_locked,
bool *ret_write_locked)
{
int r;
struct opal_lr_status *lrs;
@@ -291,15 +293,15 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
assert(cd);
assert(vk);
r = opal_geometry_fd(cd, fd, NULL, &opal_block_bytes, NULL, NULL);
if (r != OPAL_STATUS_SUCCESS)
return -EINVAL;
if (check_offset_sectors || check_length_sectors) {
r = opal_geometry_fd(cd, fd, NULL, &opal_block_bytes, NULL, NULL);
if (r != OPAL_STATUS_SUCCESS)
return -EINVAL;
}
lrs = crypt_safe_alloc(sizeof(*lrs));
if (!lrs) {
r = -ENOMEM;
goto out;
}
if (!lrs)
return -ENOMEM;
*lrs = (struct opal_lr_status) {
.session = {
@@ -322,18 +324,22 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
r = 0;
offset = lrs->range_start * opal_block_bytes / SECTOR_SIZE;
if (check_offset_sectors && (offset != *check_offset_sectors)) {
log_err(cd, _("OPAL range %d offset %" PRIu64 " does not match expected values %" PRIu64 "."),
segment_number, offset, *check_offset_sectors);
r = -EINVAL;
if (check_offset_sectors) {
offset = lrs->range_start * opal_block_bytes / SECTOR_SIZE;
if (offset != *check_offset_sectors) {
log_err(cd, _("OPAL range %d offset %" PRIu64 " does not match expected values %" PRIu64 "."),
segment_number, offset, *check_offset_sectors);
r = -EINVAL;
}
}
length = lrs->range_length * opal_block_bytes / SECTOR_SIZE;
if (check_length_sectors && (length != *check_length_sectors)) {
log_err(cd, _("OPAL range %d length %" PRIu64" does not match device length %" PRIu64 "."),
segment_number, length, *check_length_sectors);
r = -EINVAL;
if (check_length_sectors) {
length = lrs->range_length * opal_block_bytes / SECTOR_SIZE;
if (length != *check_length_sectors) {
log_err(cd, _("OPAL range %d length %" PRIu64" does not match device length %" PRIu64 "."),
segment_number, length, *check_length_sectors);
r = -EINVAL;
}
}
if (!lrs->RLE || !lrs->WLE) {
@@ -357,6 +363,11 @@ static int opal_range_check_attributes_fd(struct crypt_device *cd,
log_err(cd, _("Unexpected OPAL range %d lock state."), segment_number);
r = -EINVAL;
}
if (ret_read_locked)
*ret_read_locked = read_locked;
if (ret_write_locked)
*ret_write_locked = write_locked;
out:
crypt_safe_free(lrs);
@@ -642,7 +653,8 @@ int opal_setup_ranges(struct crypt_device *cd,
/* Double check the locking range is locked and the ranges are set up as configured */
r = opal_range_check_attributes_fd(cd, fd, segment_number, vk, &range_start,
&range_length, &(bool) {true}, &(bool){true});
&range_length, &(bool) {true}, &(bool){true},
NULL, NULL);
out:
crypt_safe_free(activate);
crypt_safe_free(user_session);
@@ -902,14 +914,14 @@ int opal_geometry(struct crypt_device *cd,
ret_alignment_granularity_blocks, ret_lowest_lba_blocks);
}
int opal_range_check_attributes(struct crypt_device *cd,
int opal_range_check_attributes_and_get_lock_state(struct crypt_device *cd,
struct device *dev,
uint32_t segment_number,
const struct volume_key *vk,
const uint64_t *check_offset_sectors,
const uint64_t *check_length_sectors,
bool *check_read_locked,
bool *check_write_locked)
bool *ret_read_locked,
bool *ret_write_locked)
{
int fd;
@@ -922,8 +934,8 @@ int opal_range_check_attributes(struct crypt_device *cd,
return -EIO;
return opal_range_check_attributes_fd(cd, fd, segment_number, vk,
check_offset_sectors, check_length_sectors, check_read_locked,
check_write_locked);
check_offset_sectors, check_length_sectors, NULL,
NULL, ret_read_locked, ret_write_locked);
}
#else
@@ -986,14 +998,14 @@ int opal_geometry(struct crypt_device *cd,
return -ENOTSUP;
}
int opal_range_check_attributes(struct crypt_device *cd,
struct device *dev,
uint32_t segment_number,
const struct volume_key *vk,
const uint64_t *check_offset_sectors,
const uint64_t *check_length_sectors,
bool *check_read_locked,
bool *check_write_locked)
int opal_range_check_attributes_and_get_lock_state(struct crypt_device *cd,
struct device *dev,
uint32_t segment_number,
const struct volume_key *vk,
const uint64_t *check_offset_sectors,
const uint64_t *check_length_sectors,
bool *ret_read_locked,
bool *ret_write_locked)
{
return -ENOTSUP;
}

View File

@@ -53,13 +53,13 @@ int opal_geometry(struct crypt_device *cd,
uint32_t *ret_block_size,
uint64_t *ret_alignment_granularity_blocks,
uint64_t *ret_lowest_lba_blocks);
int opal_range_check_attributes(struct crypt_device *cd,
int opal_range_check_attributes_and_get_lock_state(struct crypt_device *cd,
struct device *dev,
uint32_t segment_number,
const struct volume_key *vk,
const uint64_t *check_offset_sectors,
const uint64_t *check_length_sectors,
bool *check_read_locked,
bool *check_write_locked);
bool *ret_read_locked,
bool *ret_write_locked);
#endif

View File

@@ -2644,7 +2644,7 @@ int LUKS2_activate(struct crypt_device *cd,
uint32_t flags)
{
int r;
bool dynamic;
bool dynamic, read_lock, write_lock, opal_lock_on_error = false;
uint32_t opal_segment_number;
uint64_t range_offset_sectors, range_length_sectors, device_length_bytes;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
@@ -2697,12 +2697,17 @@ int LUKS2_activate(struct crypt_device *cd,
}
range_offset_sectors = crypt_get_data_offset(cd) + crypt_dev_partition_offset(device_path(crypt_data_device(cd)));
r = opal_range_check_attributes(cd, crypt_data_device(cd), opal_segment_number,
r = opal_range_check_attributes_and_get_lock_state(cd, crypt_data_device(cd), opal_segment_number,
opal_key, &range_offset_sectors, &range_length_sectors,
NULL /* read locked */, NULL /* write locked */);
&read_lock, &write_lock);
if (r < 0)
return r;
opal_lock_on_error = read_lock && write_lock;
if (!opal_lock_on_error && !(flags & CRYPT_ACTIVATE_REFRESH))
log_std(cd, _("OPAL device is %s already unlocked!\n"),
device_path(crypt_data_device(cd)));
r = opal_unlock(cd, crypt_data_device(cd), opal_segment_number, opal_key);
if (r < 0)
return r;
@@ -2771,7 +2776,7 @@ int LUKS2_activate(struct crypt_device *cd,
dm_targets_free(cd, &dmd);
dm_targets_free(cd, &dmdi);
out:
if (r < 0 && opal_key)
if (r < 0 && opal_lock_on_error)
opal_lock(cd, crypt_data_device(cd), opal_segment_number);
return r;