cryptsetup: support for hw-opal in luksErase

Wipe and disable the segment. Also support the factory reset ioctl for
a complete wipe of the entire drive with a specific argument.

Signed-off-by: Luca Boccassi <bluca@debian.org>
This commit is contained in:
Luca Boccassi
2022-12-27 00:14:23 +01:00
parent 5716f959a7
commit decbe09fb3
7 changed files with 140 additions and 3 deletions

View File

@@ -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
*

View File

@@ -170,4 +170,5 @@ CRYPTSETUP_2.7 {
global:
crypt_format_luks2_opal;
crypt_get_hw_encryption_type;
crypt_wipe_hw_opal;
} CRYPTSETUP_2.6;

View File

@@ -26,6 +26,8 @@
#include <sys/stat.h>
#include <linux/fs.h>
#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));
}

View File

@@ -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";

View File

@@ -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)

View File

@@ -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 }

View File

@@ -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"