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(a)redhat.com>
---
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