diff --git a/lib/internal.h b/lib/internal.h index 4c376090..90bf8d3c 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -103,7 +103,7 @@ void device_disable_direct_io(struct device *device); int device_is_identical(struct device *device1, struct device *device2); int device_is_rotational(struct device *device); size_t device_alignment(struct device *device); -int device_direct_io(struct device *device); +int device_direct_io(const struct device *device); int device_open_locked(struct device *device, int flags); int device_read_lock(struct crypt_device *cd, struct device *device); diff --git a/lib/luks2/luks2.h b/lib/luks2/luks2.h index 9deae4af..05369ba0 100644 --- a/lib/luks2/luks2.h +++ b/lib/luks2/luks2.h @@ -109,7 +109,8 @@ struct luks2_hdr { #define LUKS2_MAX_KEYSLOTS_SIZE 0x8000000 /* 128 MiB */ -int LUKS2_hdr_version_unlocked(struct crypt_device *cd); +int LUKS2_hdr_version_unlocked(struct crypt_device *cd, + const char *backup_file); int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr); int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr); diff --git a/lib/luks2/luks2_disk_metadata.c b/lib/luks2/luks2_disk_metadata.c index d5269de0..91579f11 100644 --- a/lib/luks2/luks2_disk_metadata.c +++ b/lib/luks2/luks2_disk_metadata.c @@ -666,14 +666,19 @@ err: return r; } -int LUKS2_hdr_version_unlocked(struct crypt_device *cd) +int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file) { struct { char magic[LUKS2_MAGIC_L]; uint16_t version; } __attribute__ ((packed)) hdr; - struct device *device = crypt_metadata_device(cd); - int r, devfd, flags; + struct device *device = NULL; + int r = 0, devfd = -1, flags; + + if (!backup_file) + device = crypt_metadata_device(cd); + else if (device_alloc(&device, backup_file) < 0) + return 0; if (!device) return 0; @@ -684,16 +689,18 @@ int LUKS2_hdr_version_unlocked(struct crypt_device *cd) devfd = open(device_path(device), flags); if (devfd < 0) - return 0; + goto err; if ((read_lseek_blockwise(devfd, device_block_size(device), - device_alignment(device), &hdr, sizeof(hdr), 0) - != sizeof(hdr)) || - memcmp(hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L)) - r = 0; - else + device_alignment(device), &hdr, sizeof(hdr), 0) == sizeof(hdr)) && + !memcmp(hdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L)) r = (int)be16_to_cpu(hdr.version); +err: + if (devfd != -1) + close(devfd); + + if (backup_file) + device_free(device); - close(devfd); return r; } diff --git a/lib/setup.c b/lib/setup.c index 26837ce1..9f186519 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -724,7 +724,7 @@ static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type, /* This will return 0 if primary LUKS2 header is damaged */ if (!requested_type) - version = LUKS2_hdr_version_unlocked(cd); + version = LUKS2_hdr_version_unlocked(cd, NULL); if (isLUKS1(requested_type) || version == 1) { if (cd->type && isLUKS2(cd->type)) { @@ -2162,7 +2162,7 @@ int crypt_header_restore(struct crypt_device *cd, { struct luks_phdr hdr1; struct luks2_hdr hdr2; - int r; + int r, version; if (requested_type && !isLUKS(requested_type)) return -EINVAL; @@ -2177,15 +2177,21 @@ int crypt_header_restore(struct crypt_device *cd, log_dbg("Requested header restore to device %s (%s) from " "file %s.", mdata_device_path(cd), requested_type ?: "any type", backup_file); - memset(&hdr2, 0, sizeof(hdr2)); - if (!cd->type) { - if (!requested_type || isLUKS2(requested_type)) - r = LUKS2_hdr_restore(cd, &hdr2, backup_file); - else - r = -ENOENT; + version = LUKS2_hdr_version_unlocked(cd, backup_file); + if (!version || + (requested_type && version == 1 && !isLUKS1(requested_type)) || + (requested_type && version == 2 && !isLUKS2(requested_type))) { + log_err(cd, _("Header backup file does not contain compatible LUKS header.\n")); + return -EINVAL; + } - if (r && (!requested_type || isLUKS1(requested_type))) + memset(&hdr2, 0, sizeof(hdr2)); + + if (!cd->type) { + if (version == 1) r = LUKS_hdr_restore(backup_file, &hdr1, cd); + else + r = LUKS2_hdr_restore(cd, &hdr2, backup_file); LUKS2_hdr_free(&hdr2); crypt_memzero(&hdr1, sizeof(hdr1)); diff --git a/lib/utils_device.c b/lib/utils_device.c index 48ec7cbb..0aba1422 100644 --- a/lib/utils_device.c +++ b/lib/utils_device.c @@ -693,7 +693,7 @@ void device_disable_direct_io(struct device *device) device->o_direct = 0; } -int device_direct_io(struct device *device) +int device_direct_io(const struct device *device) { return device->o_direct; }