aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Kozina <okozina@redhat.com>2023-12-05 16:31:39 +0100
committerMilan Broz <gmazyland@gmail.com>2023-12-13 20:59:14 +0000
commit2e978c8776e07917e82d3c2c2eedd079e39b7293 (patch)
tree71c85ea127331c925cc9ba1f205be9376c0fa804
parent31027b924002ef90c2713e3bf14f80c77b4b0c7a (diff)
downloadcryptsetup-2e978c8776e07917e82d3c2c2eedd079e39b7293.tar.gz
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.
-rw-r--r--lib/luks2/hw_opal/hw_opal.c76
-rw-r--r--lib/luks2/hw_opal/hw_opal.h6
-rw-r--r--lib/luks2/luks2_json_metadata.c13
3 files changed, 56 insertions, 39 deletions
diff --git a/lib/luks2/hw_opal/hw_opal.c b/lib/luks2/hw_opal/hw_opal.c
index 18d89e6c..b56cb64b 100644
--- a/lib/luks2/hw_opal/hw_opal.c
+++ b/lib/luks2/hw_opal/hw_opal.c
@@ -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;
}
diff --git a/lib/luks2/hw_opal/hw_opal.h b/lib/luks2/hw_opal/hw_opal.h
index c13dd368..b2835dab 100644
--- a/lib/luks2/hw_opal/hw_opal.h
+++ b/lib/luks2/hw_opal/hw_opal.h
@@ -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
diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c
index 24f26071..c6084f4a 100644
--- a/lib/luks2/luks2_json_metadata.c
+++ b/lib/luks2/luks2_json_metadata.c
@@ -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;