diff options
author | Ondrej Kozina <okozina@redhat.com> | 2023-12-05 16:31:39 +0100 |
---|---|---|
committer | Milan Broz <gmazyland@gmail.com> | 2023-12-13 20:59:14 +0000 |
commit | 2e978c8776e07917e82d3c2c2eedd079e39b7293 (patch) | |
tree | 71c85ea127331c925cc9ba1f205be9376c0fa804 | |
parent | 31027b924002ef90c2713e3bf14f80c77b4b0c7a (diff) | |
download | cryptsetup-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.c | 76 | ||||
-rw-r--r-- | lib/luks2/hw_opal/hw_opal.h | 6 | ||||
-rw-r--r-- | lib/luks2/luks2_json_metadata.c | 13 |
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; |