Commit befdba9e authored by Maxim Levitsky's avatar Maxim Levitsky Committed by Daniel P. Berrangé
Browse files

qcrypto-luks: more rigorous header checking



Check that keyslots don't overlap with the data,
and check that keyslots don't overlap with each other.
(this is done using naive O(n^2) nested loops,
but since there are just 8 keyslots, this doesn't really matter.

Signed-off-by: default avatarMaxim Levitsky <mlevitsk@redhat.com>
Reviewed-by: default avatarDaniel P. Berrangé <berrange@redhat.com>
Signed-off-by: default avatarDaniel P. Berrangé <berrange@redhat.com>
parent bd56a55a
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -530,6 +530,11 @@ qcrypto_block_luks_load_header(QCryptoBlock *block,
static int
qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp)
{
    size_t i, j;

    unsigned int header_sectors = QCRYPTO_BLOCK_LUKS_KEY_SLOT_OFFSET /
        QCRYPTO_BLOCK_LUKS_SECTOR_SIZE;

    if (memcmp(luks->header.magic, qcrypto_block_luks_magic,
               QCRYPTO_BLOCK_LUKS_MAGIC_LEN) != 0) {
        error_setg(errp, "Volume is not in LUKS format");
@@ -541,6 +546,53 @@ qcrypto_block_luks_check_header(const QCryptoBlockLUKS *luks, Error **errp)
                   luks->header.version);
        return -1;
    }

    /* Check all keyslots for corruption  */
    for (i = 0 ; i < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS ; i++) {

        const QCryptoBlockLUKSKeySlot *slot1 = &luks->header.key_slots[i];
        unsigned int start1 = slot1->key_offset_sector;
        unsigned int len1 =
            qcrypto_block_luks_splitkeylen_sectors(luks,
                                                   header_sectors,
                                                   slot1->stripes);

        if (slot1->stripes == 0) {
            error_setg(errp, "Keyslot %zu is corrupted (stripes == 0)", i);
            return -1;
        }

        if (slot1->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_DISABLED &&
            slot1->active != QCRYPTO_BLOCK_LUKS_KEY_SLOT_ENABLED) {
            error_setg(errp,
                       "Keyslot %zu state (active/disable) is corrupted", i);
            return -1;
        }

        if (start1 + len1 > luks->header.payload_offset_sector) {
            error_setg(errp,
                       "Keyslot %zu is overlapping with the encrypted payload",
                       i);
            return -1;
        }

        for (j = i + 1 ; j < QCRYPTO_BLOCK_LUKS_NUM_KEY_SLOTS ; j++) {
            const QCryptoBlockLUKSKeySlot *slot2 = &luks->header.key_slots[j];
            unsigned int start2 = slot2->key_offset_sector;
            unsigned int len2 =
                qcrypto_block_luks_splitkeylen_sectors(luks,
                                                       header_sectors,
                                                       slot2->stripes);

            if (start1 + len1 > start2 && start2 + len2 > start1) {
                error_setg(errp,
                           "Keyslots %zu and %zu are overlapping in the header",
                           i, j);
                return -1;
            }
        }

    }
    return 0;
}