diff --git a/lib/luks2/luks2.h b/lib/luks2/luks2.h index 2e098740..4769d2ea 100644 --- a/lib/luks2/luks2.h +++ b/lib/luks2/luks2.h @@ -55,6 +55,8 @@ /* 20 MiBs */ #define LUKS2_DEFAULT_NONE_REENCRYPTION_LENGTH 0x1400000 +struct device; + /* * LUKS2 header on-disk. * @@ -215,8 +217,12 @@ crypt_reencrypt_info LUKS2_reenc_status(struct luks2_hdr *hdr); int LUKS2_hdr_version_unlocked(struct crypt_device *cd, const char *backup_file); +int LUKS2_device_write_lock(struct crypt_device *cd, + struct luks2_hdr *hdr, struct device *device); + int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair); int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr); +int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr); int LUKS2_hdr_dump(struct crypt_device *cd, struct luks2_hdr *hdr); int LUKS2_hdr_uuid(struct crypt_device *cd, diff --git a/lib/luks2/luks2_disk_metadata.c b/lib/luks2/luks2_disk_metadata.c index cab12531..da10d143 100644 --- a/lib/luks2/luks2_disk_metadata.c +++ b/lib/luks2/luks2_disk_metadata.c @@ -349,11 +349,59 @@ static int hdr_write_disk(struct crypt_device *cd, return r; } +static int LUKS2_check_sequence_id(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device) +{ + int devfd; + struct luks2_hdr_disk dhdr; + + if (!hdr) + return -EINVAL; + + devfd = device_open_locked(cd, device, O_RDONLY); + if (devfd < 0) + return devfd == -1 ? -EINVAL : devfd; + + /* we need only first 512 bytes, see luks2_hdr_disk structure */ + if ((read_lseek_blockwise(devfd, device_block_size(cd, device), + device_alignment(device), &dhdr, 512, 0) != 512)) + return -EIO; + + /* there's nothing to check if there's no LUKS2 header */ + if ((be16_to_cpu(dhdr.version) != 2) || + memcmp(dhdr.magic, LUKS2_MAGIC_1ST, LUKS2_MAGIC_L) || + strcmp(dhdr.uuid, hdr->uuid)) + return 0; + + return hdr->seqid != be64_to_cpu(dhdr.seqid); +} + +int LUKS2_device_write_lock(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device) +{ + int r = device_write_lock(cd, device); + + if (r < 0) { + log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device)); + return r; + } + + /* run sequence id check only on first write lock (r == 1) and w/o LUKS2 reencryption in-progress */ + if (r == 1 && !crypt_get_reenc_context(cd)) { + log_dbg(cd, "Checking context sequence id matches value stored on disk."); + if (LUKS2_check_sequence_id(cd, hdr, device)) { + device_write_unlock(cd, device); + log_err(cd, _("Detected attempt for concurrent LUKS2 metadata update. Aborting operation.")); + return -EINVAL; + } + } + + return 0; +} + /* * Convert in-memory LUKS2 header and write it to disk. * This will increase sequence id, write both header copies and calculate checksum. */ -int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device) +int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device *device, bool seqid_check) { char *json_area; const char *json_text; @@ -395,16 +443,18 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct } strncpy(json_area, json_text, json_area_len); - /* Increase sequence id before writing it to disk. */ - hdr->seqid++; - - r = device_write_lock(cd, device); + if (seqid_check) + r = LUKS2_device_write_lock(cd, hdr, device); + else + r = device_write_lock(cd, device); if (r < 0) { - log_err(cd, _("Failed to acquire write device lock.")); free(json_area); return r; } + /* Increase sequence id before writing it to disk. */ + hdr->seqid++; + /* Write primary and secondary header */ r = hdr_write_disk(cd, device, hdr, json_area, 0); if (!r) @@ -415,8 +465,6 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct device_write_unlock(cd, device); - /* FIXME: try recovery here? */ - free(json_area); return r; } diff --git a/lib/luks2/luks2_internal.h b/lib/luks2/luks2_internal.h index 38b3311c..f6eff7f8 100644 --- a/lib/luks2/luks2_internal.h +++ b/lib/luks2/luks2_internal.h @@ -44,7 +44,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, 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); + struct device *device, bool seqid_check); /* * JSON struct access helpers diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c index da0ed5dc..2b62f2e8 100644 --- a/lib/luks2/luks2_json_metadata.c +++ b/lib/luks2/luks2_json_metadata.c @@ -945,6 +945,7 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair) /* unlikely: auto-recovery is required and failed due to read lock being held */ device_read_unlock(cd, crypt_metadata_device(cd)); + /* Do not use LUKS2_device_write lock. Recovery. */ r = device_write_lock(cd, crypt_metadata_device(cd)); if (r < 0) { log_err(cd, _("Failed to acquire write lock on device %s."), @@ -961,6 +962,18 @@ int LUKS2_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, int repair) return r; } +int LUKS2_hdr_write_force(struct crypt_device *cd, struct luks2_hdr *hdr) +{ + /* NOTE: is called before LUKS2 validation routines */ + /* erase unused digests (no assigned keyslot or segment) */ + LUKS2_digests_erase_unused(cd, hdr); + + if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN)) + return -EINVAL; + + return LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd), false); +} + int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr) { /* NOTE: is called before LUKS2 validation routines */ @@ -970,7 +983,7 @@ int LUKS2_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr) if (LUKS2_hdr_validate(cd, hdr->jobj, hdr->hdr_size - LUKS2_HDR_BIN_LEN)) return -EINVAL; - return LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd)); + return LUKS2_disk_hdr_write(cd, hdr, crypt_metadata_device(cd), true); } int LUKS2_hdr_uuid(struct crypt_device *cd, struct luks2_hdr *hdr, const char *uuid) @@ -1125,7 +1138,6 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr, if (r < 0) return r; - /* FIXME: why lock backup device ? */ r = device_read_lock(cd, backup_device); if (r) { log_err(cd, _("Failed to acquire read lock on device %s."), @@ -1219,7 +1231,7 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr, log_dbg(cd, "Storing backup of header (%zu bytes) to device %s.", buffer_size, device_path(device)); - /* TODO: perform header restore on bdev in stand-alone routine? */ + /* Do not use LUKS2_device_write lock for checking sequence id on restore */ r = device_write_lock(cd, device); if (r < 0) { log_err(cd, _("Failed to acquire write lock on device %s."), @@ -1246,8 +1258,6 @@ int LUKS2_hdr_restore(struct crypt_device *cd, struct luks2_hdr *hdr, r = 0; device_write_unlock(cd, device); - /* end of TODO */ - out: LUKS2_hdr_free(cd, hdr); LUKS2_hdr_free(cd, &hdr_file); diff --git a/lib/luks2/luks2_keyslot.c b/lib/luks2/luks2_keyslot.c index bae9aac3..18b07e6b 100644 --- a/lib/luks2/luks2_keyslot.c +++ b/lib/luks2/luks2_keyslot.c @@ -709,13 +709,10 @@ int LUKS2_keyslot_wipe(struct crypt_device *cd, if (wipe_area_only) log_dbg(cd, "Wiping keyslot %d area only.", keyslot); - /* Just check that nobody uses the metadata now */ - r = device_write_lock(cd, device); - if (r < 0) { - log_err(cd, _("Failed to acquire write lock on device %s."), - device_path(device)); + /* FIXME: crypt_wipe_device requires 'locked' variant. */ + r = LUKS2_device_write_lock(cd, hdr, device); + if (r) return r; - } device_write_unlock(cd, device); /* secure deletion of possible key material in keyslot area */ diff --git a/lib/luks2/luks2_keyslot_luks2.c b/lib/luks2/luks2_keyslot_luks2.c index 55896fe7..669d1ecf 100644 --- a/lib/luks2/luks2_keyslot_luks2.c +++ b/lib/luks2/luks2_keyslot_luks2.c @@ -38,13 +38,11 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength, { struct device *device = crypt_metadata_device(cd); #ifndef ENABLE_AF_ALG /* Support for old kernel without Crypto API */ - int r = device_write_lock(cd, device); - if (r < 0) { - log_err(cd, _("Failed to acquire write lock on device %s."), device_path(device)); + int r = LUKS2_device_write_lock(cd, crypt_get_hdr(cd, CRYPT_LUKS2), device); + if (r) return r; - } r = LUKS_encrypt_to_storage(src, srcLength, cipher, cipher_mode, vk, sector, cd); - device_write_unlock(cd, crypt_metadata_device(cd)); + device_write_unlock(cd, device); return r; #else struct crypt_storage *s; @@ -67,12 +65,9 @@ static int luks2_encrypt_to_storage(char *src, size_t srcLength, if (r) return r; - r = device_write_lock(cd, device); - if (r < 0) { - log_err(cd, _("Failed to acquire write lock on device %s."), - device_path(device)); + r = LUKS2_device_write_lock(cd, crypt_get_hdr(cd, CRYPT_LUKS2), device); + if (r) return r; - } devfd = device_open_locked(cd, device, O_RDWR); if (devfd >= 0) { @@ -577,11 +572,9 @@ static int luks2_keyslot_store(struct crypt_device *cd, if (!jobj_keyslot) return -EINVAL; - if ((r = device_write_lock(cd, crypt_metadata_device(cd))) < 0) { - log_err(cd, _("Failed to acquire write lock on device %s."), - device_path(crypt_metadata_device(cd))); + r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd)); + if(r) return r; - } r = luks2_keyslot_set_key(cd, jobj_keyslot, password, password_len, diff --git a/lib/luks2/luks2_keyslot_reenc.c b/lib/luks2/luks2_keyslot_reenc.c index 82815b45..e88a25ab 100644 --- a/lib/luks2/luks2_keyslot_reenc.c +++ b/lib/luks2/luks2_keyslot_reenc.c @@ -119,12 +119,9 @@ static int reenc_keyslot_store_data(struct crypt_device *cd, if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length)) return -EINVAL; - r = device_write_lock(cd, device); - if (r < 0) { - log_err(cd, _("Failed to acquire write lock on device %s."), - device_path(device)); + r = LUKS2_device_write_lock(cd, crypt_get_hdr(cd, CRYPT_LUKS2), device); + if (r) return r; - } devfd = device_open_locked(cd, device, O_RDWR); if (devfd >= 0) { diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c index 367683e9..a9e49a08 100644 --- a/lib/luks2/luks2_reencrypt.c +++ b/lib/luks2/luks2_reencrypt.c @@ -2810,12 +2810,9 @@ static int _reencrypt_init_by_passphrase(struct crypt_device *cd, return r; } - r = device_write_lock(cd, crypt_metadata_device(cd)); - if (r < 0) { - log_err(cd, _("Failed to acquire write lock on device %s."), - device_path(crypt_metadata_device(cd))); + r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd)); + if (r) return r; - } r = atomic_get_reencryption_flag(cd); diff --git a/lib/setup.c b/lib/setup.c index 1599ab78..5c716064 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -1796,7 +1796,8 @@ static int _crypt_format_luks2(struct crypt_device *cd, if (r < 0) goto out; - r = LUKS2_hdr_write(cd, &cd->u.luks2.hdr); + /* override sequence id check with format */ + r = LUKS2_hdr_write_force(cd, &cd->u.luks2.hdr); if (r < 0) { if (r == -EBUSY) log_err(cd, _("Cannot format device %s in use."),