[libvirt] [PATCH 13/19] util: Add 'luks' to the FileTypeInfo

John Ferlan jferlan at redhat.com
Tue Jun 21 14:22:26 UTC 2016



On 06/21/2016 08:41 AM, Peter Krempa wrote:
> On Mon, Jun 13, 2016 at 20:27:52 -0400, John Ferlan wrote:
>> 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 at 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__ */
> 
> Since you are adding this code and also the tests below it looks like a
> job for a separate patch.
> 

OK - easily done

>> diff --git a/src/util/virstoragefile.c b/src/util/virstoragefile.c
>> index 5c2519c..f7a9632 100644
>> --- a/src/util/virstoragefile.c
>> +++ b/src/util/virstoragefile.c
> 
> [...]
> 
>> @@ -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
> 
> The encryption header offset is not used here. You are not extracting
> the cipher name from the header.
> 

Hmm... I think at one time I had thought it might need to be. I can drop
LUKS_HDR_CRYPT_OFFSET


>> +    },
>>      /* 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)
> 
> This should be selected with a different property than the file type.
> The idea of the structure above was to avoid having to tweak this code
> with individual cases for every single file type. You'll either need to
> pass a function pointer for extraction or switch it according to the
> passed size.
> 

Ewww.  I think going with versionSize will be easier, although
versionFunc would be just as entertaining

>> +            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 */
> 
> FI_CRYPT_LUKS is implied by by the type which in turn implies
> encryption. Also the encryption header offset is rather useless here
> since it's not used.
> 
> Are you expecting to add extraction of the actual cipher type here?
> 

At one time I thought I might have to get more data, but it seems it
really doesn't matter unless we wanted to display it somehow.  As I was
going through the implementation phase, I thought I'd have to know which
crypt algorithm was used, but all that is handled by qemu - all we need
to provide on open/read is the AES secret in order to provide the
password used to encrypt the data.

Since this code was written I've noted Daniel has a qemu patches:

https://lists.gnu.org/archive/html/qemu-devel/2016-06/msg03885.html

which will allow qemu-img display a whole lot more luks information
which I think would be a better option than us needing to keep track of
more header information.  When v2 comes along, we'd have more work to do
in order to print out information.

Perhaps a nice addition, but as I've found out not technically necessary
to make things work.

> In such case it would be actually desired to have the switch as you've
> added here, but you should change it to VIR_ prefix and perhaps add a
> more sane comment than /* style of crypt */ ... I prefer gothic crypts.
> 

I prefer not to visit the crypt...

John
>> +        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 9424fed..8d5c45a 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 4072507..f858e5c 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;
>> +
> 
> With these it's definitely stuff for a separate patch.
> 
>>      ret = 0;
>>   cleanup:
>>      return ret;
>> -- 
>> 2.5.5
>>
>> --
>> libvir-list mailing list
>> libvir-list at redhat.com
>> https://www.redhat.com/mailman/listinfo/libvir-list




More information about the libvir-list mailing list