Add the ability to detect a luks encrypted device. This also adding new 16 bit big/little endian macros since the version of a luks device is stored in a uint16_t. Signed-off-by: John Ferlan <jferlan@xxxxxxxxxx> --- src/util/virendian.h | 24 ++++++++++++++++++++++++ src/util/virstoragefile.c | 38 ++++++++++++++++++++++++++++++++------ src/util/virstoragefile.h | 1 + tests/virendiantest.c | 18 ++++++++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/src/util/virendian.h b/src/util/virendian.h index eefe48c..97940bd 100644 --- a/src/util/virendian.h +++ b/src/util/virendian.h @@ -90,4 +90,28 @@ ((uint32_t)(uint8_t)((buf)[2]) << 16) | \ ((uint32_t)(uint8_t)((buf)[3]) << 24)) +/** + * virReadBufInt16BE: + * @buf: byte to start reading at (can be 'char*' or 'unsigned char*'); + * evaluating buf must not have any side effects + * + * Read 2 bytes at BUF as a big-endian 16-bit number. Caller is + * responsible to avoid reading beyond array bounds. + */ +# define virReadBufInt16BE(buf) \ + (((uint16_t)(uint8_t)((buf)[0]) << 8) | \ + (uint16_t)(uint8_t)((buf)[1])) + +/** + * virReadBufInt16LE: + * @buf: byte to start reading at (can be 'char*' or 'unsigned char*'); + * evaluating buf must not have any side effects + * + * Read 2 bytes at BUF as a little-endian 16-bit number. Caller is + * responsible to avoid reading beyond array bounds. + */ +# define virReadBufInt16LE(buf) \ + ((uint16_t)(uint8_t)((buf)[0]) | \ + ((uint16_t)(uint8_t)((buf)[1]) << 8)) + #endif /* __VIR_ENDIAN_H__ */ diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c index 5d086b9..fbdd323 100644 --- a/src/util/virstoragefile.c +++ b/src/util/virstoragefile.c @@ -63,7 +63,7 @@ VIR_ENUM_IMPL(virStorageFileFormat, "cloop", "dmg", "iso", "vpc", "vdi", /* Not direct file formats, but used for various drivers */ - "fat", "vhd", "ploop", + "fat", "vhd", "ploop", "luks", /* Formats with backing file below here */ "cow", "qcow", "qcow2", "qed", "vmdk") @@ -113,7 +113,8 @@ enum { enum fi_crypt { FI_CRYPT_NONE = 0, - FI_CRYPT_QCOW + FI_CRYPT_QCOW, + FI_CRYPT_LUKS }; #define FILE_TYPE_VERSIONS_LAST 2 @@ -193,6 +194,14 @@ qedGetBackingStore(char **, int *, const char *, size_t); #define PLOOP_IMAGE_SIZE_OFFSET 36 #define PLOOP_SIZE_MULTIPLIER 512 +#define LUKS_HDR_MAGIC_LEN 6 +#define LUKS_HDR_VERSION_LEN 2 + +/* Format described by qemu commit id '3e308f20e' */ +#define LUKS_HDR_VERSION_OFFSET LUKS_HDR_MAGIC_LEN +#define LUKS_HDR_CRYPT_OFFSET LUKS_HDR_MAGIC_LEN + LUKS_HDR_VERSION_LEN + + static struct FileTypeInfo const fileTypeInfo[] = { [VIR_STORAGE_FILE_NONE] = { 0, NULL, NULL, LV_LITTLE_ENDIAN, -1, {0}, 0, 0, 0, FI_CRYPT_NONE, 0, NULL, NULL }, @@ -249,6 +258,13 @@ static struct FileTypeInfo const fileTypeInfo[] = { PLOOP_SIZE_MULTIPLIER, FI_CRYPT_NONE, -1, NULL, NULL }, + /* Magic is 'L','U','K','S', 0xBA, 0xBE + * Set sizeOffset = -1 and let hypervisor handle */ + [VIR_STORAGE_FILE_LUKS] = { + 0, "\x4c\x55\x4b\x53\xba\xbe", NULL, + LV_BIG_ENDIAN, LUKS_HDR_VERSION_OFFSET, {1}, + -1, 0, 0, FI_CRYPT_LUKS, LUKS_HDR_CRYPT_OFFSET, NULL, NULL + }, /* All formats with a backing store probe below here */ [VIR_STORAGE_FILE_COW] = { 0, "OOOM", NULL, @@ -634,7 +650,7 @@ virStorageFileMatchesVersion(int format, char *buf, size_t buflen) { - int version; + int version = 0; size_t i; /* Validate version number info */ @@ -648,10 +664,16 @@ virStorageFileMatchesVersion(int format, if ((fileTypeInfo[format].versionOffset + 4) > buflen) return false; - if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) + if (fileTypeInfo[format].endian == LV_LITTLE_ENDIAN) { version = virReadBufInt32LE(buf + fileTypeInfo[format].versionOffset); - else - version = virReadBufInt32BE(buf + fileTypeInfo[format].versionOffset); + } else { + if (format == VIR_STORAGE_FILE_LUKS) + version = virReadBufInt16BE(buf + + fileTypeInfo[format].versionOffset); + else + version = virReadBufInt32BE(buf + + fileTypeInfo[format].versionOffset); + } for (i = 0; i < FILE_TYPE_VERSIONS_LAST && fileTypeInfo[format].versionNumbers[i]; @@ -832,6 +854,10 @@ virStorageFileGetMetadataInternal(virStorageSourcePtr meta, if (crypt_format && !meta->encryption && VIR_ALLOC(meta->encryption) < 0) goto cleanup; + } else if (fileTypeInfo[meta->format].cryptType == FI_CRYPT_LUKS) { + /* By definition, this is encrypted */ + if (!meta->encryption && VIR_ALLOC(meta->encryption) < 0) + goto cleanup; } VIR_FREE(meta->backingStoreRaw); diff --git a/src/util/virstoragefile.h b/src/util/virstoragefile.h index b4ad42e..1c93f6b 100644 --- a/src/util/virstoragefile.h +++ b/src/util/virstoragefile.h @@ -74,6 +74,7 @@ typedef enum { VIR_STORAGE_FILE_FAT, VIR_STORAGE_FILE_VHD, VIR_STORAGE_FILE_PLOOP, + VIR_STORAGE_FILE_LUKS, /* Not a format, but a marker: all formats below this point have * libvirt support for following a backing chain */ diff --git a/tests/virendiantest.c b/tests/virendiantest.c index 2097c28..5b96ed8 100644 --- a/tests/virendiantest.c +++ b/tests/virendiantest.c @@ -50,6 +50,15 @@ test1(const void *data ATTRIBUTE_UNUSED) if (virReadBufInt32LE(array + 9) != 0x8d8c8b8aU) goto cleanup; + if (virReadBufInt16BE(array) != 0x0102U) + goto cleanup; + if (virReadBufInt16BE(array + 11) != 0x8c8dU) + goto cleanup; + if (virReadBufInt16LE(array) != 0x0201U) + goto cleanup; + if (virReadBufInt16LE(array + 11) != 0x8d8cU) + goto cleanup; + ret = 0; cleanup: return ret; @@ -81,6 +90,15 @@ test2(const void *data ATTRIBUTE_UNUSED) if (virReadBufInt32LE(array + 9) != 0x8d8c8b8aU) goto cleanup; + if (virReadBufInt16BE(array) != 0x0102U) + goto cleanup; + if (virReadBufInt16BE(array + 11) != 0x8c8dU) + goto cleanup; + if (virReadBufInt16LE(array) != 0x0201U) + goto cleanup; + if (virReadBufInt16LE(array + 11) != 0x8d8cU) + goto cleanup; + ret = 0; cleanup: return ret; -- 2.5.5 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list