diff --git a/lib/internal.h b/lib/internal.h index 6d4994aa..a48f4478 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -32,6 +32,7 @@ #include "nls.h" #include "bitops.h" +#include "utils_blkid.h" #include "utils_crypt.h" #include "utils_loop.h" #include "utils_dm.h" diff --git a/lib/luks2/luks2_disk_metadata.c b/lib/luks2/luks2_disk_metadata.c index e4a6998d..7abb5e7c 100644 --- a/lib/luks2/luks2_disk_metadata.c +++ b/lib/luks2/luks2_disk_metadata.c @@ -531,12 +531,59 @@ static json_object *parse_and_validate_json(const char *json_area, int length) return jobj; } +static int detect_device_signatures(const char *path) +{ + blk_probe_status prb_state; + int r; + struct blkid_handle *h; + + if (!blk_supported()) { + log_dbg("Blkid probing of device signatures disabled."); + return 0; + } + + if ((r = blk_init_by_path(&h, path))) { + log_dbg("Failed to initialize blkid_handle by path."); + return -EINVAL; + } + + /* We don't care about details. Be fast. */ + blk_set_chains_for_fast_detection(h); + + /* Filter out crypto_LUKS. we don't care now */ + blk_superblocks_filter_luks(h); + + prb_state = blk_safeprobe(h); + + switch (prb_state) { + case PRB_AMBIGUOUS: + log_dbg("Blkid probe couldn't decide device type unambiguously."); + /* fall through */ + case PRB_FAIL: + log_dbg("Blkid probe failed."); + r = -EINVAL; + break; + case PRB_OK: /* crypto_LUKS type is filtered out */ + r = -EINVAL; + + if (blk_is_partition(h)) + log_dbg("Blkid probe detected partition type '%s'", blk_get_partition_type(h)); + else if (blk_is_superblock(h)) + log_dbg("blkid probe detected superblock type '%s'", blk_get_superblock_type(h)); + break; + case PRB_EMPTY: + log_dbg("Blkid probe detected no foreign device signature."); + } + blk_free(h); + return r; +} + /* * Read and convert on-disk LUKS2 header to in-memory representation.. * Try to do recovery if on-disk state is not consistent. */ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, - struct device *device, int do_recovery) + struct device *device, int do_recovery, int do_blkprobe) { enum { HDR_OK, HDR_OBSOLETE, HDR_FAIL, HDR_FAIL_IO } state_hdr1, state_hdr2; struct luks2_hdr_disk hdr_disk1, hdr_disk2; @@ -617,6 +664,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, if (state_hdr1 == HDR_OK && state_hdr2 != HDR_OK) { log_dbg("Secondary LUKS2 header requires recovery."); + if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) { + log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n" + "Please run \"cryptsetup repair\" for recovery.")); + goto err; + } + if (do_recovery) { memcpy(&hdr_disk2, &hdr_disk1, LUKS2_HDR_BIN_LEN); r = crypt_random_get(NULL, (char*)hdr_disk2.salt, sizeof(hdr_disk2.salt), CRYPT_RND_SALT); @@ -632,6 +685,12 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, } else if (state_hdr1 != HDR_OK && state_hdr2 == HDR_OK) { log_dbg("Primary LUKS2 header requires recovery."); + if (do_blkprobe && (r = detect_device_signatures(device_path(device)))) { + log_err(cd, _("Device contains ambiguous signatures, cannot auto-recover LUKS2.\n" + "Please run \"cryptsetup repair\" for recovery.")); + goto err; + } + if (do_recovery) { memcpy(&hdr_disk1, &hdr_disk2, LUKS2_HDR_BIN_LEN); r = crypt_random_get(NULL, (char*)hdr_disk1.salt, sizeof(hdr_disk1.salt), CRYPT_RND_SALT); diff --git a/lib/luks2/luks2_internal.h b/lib/luks2/luks2_internal.h index e9beab89..dcabed75 100644 --- a/lib/luks2/luks2_internal.h +++ b/lib/luks2/luks2_internal.h @@ -42,7 +42,7 @@ * On-disk access function prototypes */ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, - struct device *device, int do_recovery); + struct device *device, int do_recovery, int do_blkprobe); int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device); diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c index 362388ef..125cad93 100644 --- a/lib/luks2/luks2_json_metadata.c +++ b/lib/luks2/luks2_json_metadata.c @@ -853,7 +853,7 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr) return r; } - r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1); + r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, 1); if (r == -EAGAIN) { /* unlikely: auto-recovery is required and failed due to read lock being held */ device_read_unlock(crypt_metadata_device(cd)); @@ -865,7 +865,7 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr) return r; } - r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1); + r = LUKS2_disk_hdr_read(cd, hdr, crypt_metadata_device(cd), 1, 1); device_write_unlock(crypt_metadata_device(cd)); } else