diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 5fb149e5..1bf69ce1 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -2325,6 +2325,35 @@ int crypt_wipe(struct crypt_device *cd, #define CRYPT_WIPE_NO_DIRECT_IO (UINT32_C(1) << 0) /** @} */ +enum { + CRYPT_LUKS2_SEGMENT = -2, + CRYPT_NO_SEGMENT = -1, +}; + +/** + * Safe erase of a partition or an entire OPAL device. WARNING: ALL DATA ON + * PARTITION/DISK WILL BE LOST. If the CRYPT_NO_SEGMENT is passed as the segment + * parameter, the entire device will be wiped, not just what is included in the + * LUKS2 device/partition. + * + * @param cd crypt device handle + * @param segment the segment number to wipe (0..8), or CRYPT_LUKS2_SEGMENT + * to wipe the segment configured in the LUKS2 header, or CRYPT_NO_SEGMENT + * to wipe the entire device via a factory reset. + * @param password admin password/PSID (for factory reset) to wipe the + * partition/device + * @param password_size length of password/PSID + * @param flags (currently unused) + * + * @return @e 0 on success or negative errno value otherwise. + */ +int crypt_wipe_hw_opal(struct crypt_device *cd, + int segment, /* 0..8, CRYPT_LUKS2_SEGMENT -2, CRYPT_NO_SEGMENT -1 */ + const char *password, /* Admin1 PIN or PSID */ + size_t password_size, + uint32_t flags /* currently unused */ +); + /** * @defgroup crypt-tokens LUKS2 token wrapper access * diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index fbe3841f..55eb72ff 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -170,4 +170,5 @@ CRYPTSETUP_2.7 { global: crypt_format_luks2_opal; crypt_get_hw_encryption_type; + crypt_wipe_hw_opal; } CRYPTSETUP_2.6; diff --git a/lib/utils_wipe.c b/lib/utils_wipe.c index 1df46c14..ad3ffc7c 100644 --- a/lib/utils_wipe.c +++ b/lib/utils_wipe.c @@ -26,6 +26,8 @@ #include #include #include "internal.h" +#include "luks2/luks2_internal.h" +#include "luks2/hw_opal/hw_opal.h" /* block device zeroout ioctls, introduced in Linux kernel 3.7 */ #ifndef BLKZEROOUT @@ -309,3 +311,62 @@ int crypt_wipe(struct crypt_device *cd, return r; } + +int crypt_wipe_hw_opal(struct crypt_device *cd, + int segment, + const char *password, + size_t password_size, + uint32_t flags) +{ + int r; + struct luks2_hdr *hdr; + uint32_t opal_segment_number; + + if (!cd) + return -EINVAL; + + if (!password) + return -EINVAL; + + if (segment < CRYPT_LUKS2_SEGMENT || segment > 8) + return -EINVAL; + + r = crypt_opal_supported(cd, crypt_data_device(cd)); + if (r < 0) + return r; + + if (segment == CRYPT_NO_SEGMENT) { + r = opal_factory_reset(cd, crypt_data_device(cd), password, password_size); + if (r == -EPERM) + log_err(cd, _("Incorrect OPAL PSID.")); + else if (r < 0) + log_err(cd, _("Cannot erase OPAL device.")); + return r; + } + + if (onlyLUKS2(cd) < 0) + return -EINVAL; + + hdr = crypt_get_hdr(cd, CRYPT_LUKS2); + if (!hdr) + return -EINVAL; + + if (segment == CRYPT_LUKS2_SEGMENT) { + r = LUKS2_get_opal_segment_number(hdr, CRYPT_DEFAULT_SEGMENT, &opal_segment_number); + if (r < 0) { + log_dbg(cd, "Can not get OPAL segment number."); + return r; + } + } else + opal_segment_number = segment; + + r = opal_reset_segment(cd, + crypt_data_device(cd), + opal_segment_number, + password, + password_size); + if (r < 0) + return r; + + return LUKS2_wipe_header_areas(cd, hdr, crypt_header_is_detached(cd)); +} diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 3d28f507..5901e8d7 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -2672,23 +2672,62 @@ out: return r; } +static int opal_erase(struct crypt_device *cd, bool factory_reset) { + char *password = NULL; + size_t password_size = 0; + int r; + + r = tools_get_key(factory_reset ? _("Enter OPAL PSID: ") : _("Enter OPAL Admin password: "), + &password, &password_size, + 0, 0, NULL, + ARG_UINT32(OPT_TIMEOUT_ID), verify_passphrase(1), !ARG_SET(OPT_FORCE_PASSWORD_ID), cd); + if (r < 0) + return r; + + if (factory_reset && !ARG_SET(OPT_BATCH_MODE_ID) && + !yesDialog(_("WARNING: WHOLE disk will be factory reset and all data will be lost! Continue?"), + _("Operation aborted.\n"))) { + return -EPERM; + } + + return crypt_wipe_hw_opal(cd, + factory_reset ? CRYPT_NO_SEGMENT : CRYPT_LUKS2_SEGMENT, + password, + password_size, + 0); +} + static int action_luksErase(void) { struct crypt_device *cd = NULL; crypt_keyslot_info ki; char *msg = NULL; - int i, max, r; + int i, max, r, hw_enc; if ((r = crypt_init(&cd, uuid_or_device_header(NULL)))) goto out; + /* Allow factory reset even if there's no LUKS header, as long as OPAL is enabled on the device */ + if (ARG_SET(OPT_HW_OPAL_FACTORY_RESET_ID)) { + r = opal_erase(cd, true); + goto out; + } + if ((r = crypt_load(cd, luksType(device_type), NULL))) { log_err(_("Device %s is not a valid LUKS device."), uuid_or_device_header(NULL)); goto out; } - if(asprintf(&msg, _("This operation will erase all keyslots on device %s.\n" + hw_enc = crypt_get_hw_encryption_type(cd); + if (hw_enc < 0) + goto out; + if (hw_enc == CRYPT_OPAL_HW_ONLY || hw_enc == CRYPT_SW_AND_OPAL_HW) { + r = opal_erase(cd, false); + goto out; + } + + if (asprintf(&msg, _("This operation will erase all keyslots on device %s.\n" "Device will become unusable after this operation."), uuid_or_device_header(NULL)) == -1) { r = -ENOMEM; @@ -3539,7 +3578,10 @@ int main(int argc, const char **argv) aname = CLOSE_ACTION; } else if (!strcmp(aname, "luksErase")) { aname = ERASE_ACTION; - device_type = "luks"; + if (ARG_SET(OPT_TYPE_ID)) + device_type = ARG_STR(OPT_TYPE_ID); + else + device_type = "luks"; } else if (!strcmp(aname, "luksConfig")) { aname = CONFIG_ACTION; device_type = "luks2"; diff --git a/src/cryptsetup_arg_list.h b/src/cryptsetup_arg_list.h index 98f7c34d..8a2a4c4c 100644 --- a/src/cryptsetup_arg_list.h +++ b/src/cryptsetup_arg_list.h @@ -73,6 +73,8 @@ ARG(OPT_HW_OPAL, '\0', POPT_ARG_NONE, N_("Use HW OPAL encryption together with S ARG(OPT_HW_OPAL_ONLY, '\0', POPT_ARG_NONE, N_("Use only HW OPAL encryption."), NULL, CRYPT_ARG_BOOL, {}, {}) +ARG(OPT_HW_OPAL_FACTORY_RESET, '\0', POPT_ARG_NONE, N_("Wipe WHOLE OPAL disk on luksErase."), NULL, CRYPT_ARG_BOOL, {}, OPT_ERASE_ACTIONS) + ARG(OPT_INIT_ONLY, '\0', POPT_ARG_NONE, N_("Initialize LUKS2 reencryption in metadata only."), NULL, CRYPT_ARG_BOOL, {}, {}) ARG(OPT_INTEGRITY, 'I', POPT_ARG_STRING, N_("Data integrity algorithm (LUKS2 only)"), NULL, CRYPT_ARG_STRING, {}, OPT_INTEGRITY_ACTIONS) diff --git a/src/cryptsetup_args.h b/src/cryptsetup_args.h index 63604a38..e1d393fc 100644 --- a/src/cryptsetup_args.h +++ b/src/cryptsetup_args.h @@ -59,6 +59,7 @@ #define OPT_DEFERRED_ACTIONS { CLOSE_ACTION } #define OPT_DEVICE_SIZE_ACTIONS { OPEN_ACTION, RESIZE_ACTION, REENCRYPT_ACTION } #define OPT_DISABLE_VERACRYPT_ACTIONS { OPEN_ACTION, TCRYPTDUMP_ACTION } +#define OPT_ERASE_ACTIONS { ERASE_ACTION } #define OPT_HOTZONE_SIZE_ACTIONS { REENCRYPT_ACTION } #define OPT_FORCE_OFFLINE_REENCRYPT_ACTIONS { REENCRYPT_ACTION } #define OPT_INTEGRITY_ACTIONS { FORMAT_ACTION, REENCRYPT_ACTION } diff --git a/src/utils_arg_names.h b/src/utils_arg_names.h index e3994bc2..33642176 100644 --- a/src/utils_arg_names.h +++ b/src/utils_arg_names.h @@ -63,6 +63,7 @@ #define OPT_HOTZONE_SIZE "hotzone-size" #define OPT_HW_OPAL "hw-opal" #define OPT_HW_OPAL_ONLY "hw-opal-only" +#define OPT_HW_OPAL_FACTORY_RESET "hw-opal-factory-reset" #define OPT_IGNORE_CORRUPTION "ignore-corruption" #define OPT_IGNORE_ZERO_BLOCKS "ignore-zero-blocks" #define OPT_INIT_ONLY "init-only"