mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Read and compare metadata sequence id after taking write lock.
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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."),
|
||||
|
||||
Reference in New Issue
Block a user