From a462dbeb4e61cfe4284b4f01f57898496d6aee25 Mon Sep 17 00:00:00 2001 From: Ondrej Kozina Date: Mon, 25 Mar 2024 15:22:40 +0100 Subject: [PATCH] Check HW OPAL range parameters in proper units. The opal_range_check_attributes_fd function expected both offset and length parameters of a LR to be passed in sectors (512B). During format we passed it wrongly in OPAL blocks which caused bogus check provided OPAL block size was not 512B. Fixes: #871. --- lib/luks2/hw_opal/hw_opal.c | 26 +++++++++++++++++--------- lib/luks2/hw_opal/hw_opal.h | 5 +++-- lib/setup.c | 3 ++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/lib/luks2/hw_opal/hw_opal.c b/lib/luks2/hw_opal/hw_opal.c index 31ef87ed..cd63aada 100644 --- a/lib/luks2/hw_opal/hw_opal.c +++ b/lib/luks2/hw_opal/hw_opal.c @@ -405,8 +405,9 @@ static int opal_enabled(struct crypt_device *cd, struct device *dev) int opal_setup_ranges(struct crypt_device *cd, struct device *dev, const struct volume_key *vk, - uint64_t range_start, - uint64_t range_length, + uint64_t range_start_blocks, + uint64_t range_length_blocks, + uint32_t opal_block_bytes, uint32_t segment_number, const void *admin_key, size_t admin_key_len) @@ -423,10 +424,15 @@ int opal_setup_ranges(struct crypt_device *cd, assert(vk); assert(admin_key); assert(vk->keylength <= OPAL_KEY_MAX); + assert(opal_block_bytes >= SECTOR_SIZE); if (admin_key_len > OPAL_KEY_MAX) return -EINVAL; + if (((UINT64_MAX / opal_block_bytes) < range_start_blocks) || + ((UINT64_MAX / opal_block_bytes) < range_length_blocks)) + return -EINVAL; + fd = device_open(cd, dev, O_RDONLY); if (fd < 0) return -EIO; @@ -604,8 +610,8 @@ int opal_setup_ranges(struct crypt_device *cd, goto out; } *setup = (struct opal_user_lr_setup) { - .range_start = range_start, - .range_length = range_length, + .range_start = range_start_blocks, + .range_length = range_length_blocks, /* Some drives do not enable Locking Ranges on setup. This have some * interesting consequences: Lock command called later below will pass, * but locking range will _not_ be locked at all. @@ -658,9 +664,10 @@ 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}, - NULL, NULL); + r = opal_range_check_attributes_fd(cd, fd, segment_number, vk, + &(uint64_t) {range_start_blocks * opal_block_bytes / SECTOR_SIZE}, + &(uint64_t) {range_length_blocks * opal_block_bytes / SECTOR_SIZE}, + &(bool) {true}, &(bool){true}, NULL, NULL); out: crypt_safe_free(activate); crypt_safe_free(user_session); @@ -1011,8 +1018,9 @@ void opal_exclusive_unlock(struct crypt_device *cd, struct crypt_lock_handle *op int opal_setup_ranges(struct crypt_device *cd, struct device *dev, const struct volume_key *vk, - uint64_t range_start, - uint64_t range_length, + uint64_t range_start_blocks, + uint64_t range_length_blocks, + uint32_t opal_block_bytes, uint32_t segment_number, const void *admin_key, size_t admin_key_len) diff --git a/lib/luks2/hw_opal/hw_opal.h b/lib/luks2/hw_opal/hw_opal.h index f1823bfe..66bfe168 100644 --- a/lib/luks2/hw_opal/hw_opal.h +++ b/lib/luks2/hw_opal/hw_opal.h @@ -29,8 +29,9 @@ struct crypt_lock_handle; int opal_setup_ranges(struct crypt_device *cd, struct device *dev, const struct volume_key *vk, - uint64_t range_start, - uint64_t range_length, + uint64_t range_start_blocks, + uint64_t range_length_blocks, + uint32_t opal_block_bytes, uint32_t segment_number, const void *admin_key, size_t admin_key_len); diff --git a/lib/setup.c b/lib/setup.c index ff84292b..d6c6001c 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -2556,7 +2556,8 @@ int crypt_format_luks2_opal(struct crypt_device *cd, r = opal_setup_ranges(cd, crypt_data_device(cd), user_key ?: cd->volume_key, range_offset_blocks, range_size_bytes / opal_block_bytes, - opal_segment_number, opal_params->admin_key, opal_params->admin_key_size); + opal_block_bytes, opal_segment_number, + opal_params->admin_key, opal_params->admin_key_size); if (r < 0) { if (r == -EPERM) log_err(cd, _("Incorrect OPAL Admin key."));