Read and compare metadata sequence id after taking write lock.

This commit is contained in:
Ondrej Kozina
2019-05-28 14:51:45 +02:00
parent 96a87170f7
commit bbdf9b2745
9 changed files with 94 additions and 45 deletions

View File

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

View File

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

View File

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

View File

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

View 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 */

View File

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

View File

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

View File

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

View File

@@ -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."),