[libvirt] [PATCH 2/3] qemu: Create domain master key

John Ferlan jferlan at redhat.com
Tue Mar 29 14:41:22 UTC 2016



On 03/29/2016 08:56 AM, Peter Krempa wrote:
[,,,]

>>  
>> +/* qemuDomainGetMasterKeyFilePath:
>> + * @libDir: Directory path to domain lib files
>> + *
>> + * This API will generate a path of the domain's libDir (e.g.
>> + * (/var/lib/libvirt/qemu/domain-#-$NAME/) and a name 'master.key'.
>> + *
>> + * This API will check and fail if the libDir is NULL as that results
>> + * in an invalid path generated.
>> + *
>> + * This API does not check if the resulting path exists, that is left
>> + * up to the caller.
>> + *
>> + * Returns path to memory containing the name of the file. It is up to the
>> + * caller to free; otherwise, NULL on failure.
> 
> Whoah, docs longer than the code itself.
> 

Setting future expectations. I'll shorten it though.

>> + */
>> +char *
>> +qemuDomainGetMasterKeyFilePath(const char *libDir)
>> +{
>> +    if (!libDir) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +                       _("invalid path for master key file"));
>> +        return NULL;
> 
> And the code is rather self-explanatory.
> 
>> +    }
>> +    return virFileBuildPath(libDir, "master.key", NULL);
>> +}
>> +

[...]

>> +qemuDomainMasterKeyReadFile(qemuDomainObjPrivatePtr priv)
>> +{
>> +    char *path;
>> +    char *base64Key = NULL;
>> +    int base64KeySize = 0;
>> +    char *masterKey = NULL;
>> +    size_t masterKeySize = 0;
>> +    int ret = -1;
>> +
>> +    /* If we don't have the capability, then do nothing. */
>> +    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET))
>> +        return 0;
>> +
>> +    if (!(path = qemuDomainGetMasterKeyFilePath(priv->libDir)))
>> +        return -1;
>> +
>> +    if (!virFileExists(path)) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                       _("domain master key file doesn't exist in %s"),
>> +                       priv->libDir);
>> +        goto cleanup;
>> +    }
>> +
>> +    /* Read the base64 encooded secret from the file, decode it, and
>> +     * store in the domain private object.
>> +     */
>> +    if ((base64KeySize = virFileReadAll(path, 1024, &base64Key)) < 0)
>> +        goto cleanup;
>> +
>> +    if (!base64_decode_alloc(base64Key, base64KeySize,
>> +                             &masterKey, &masterKeySize)) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>> +                       _("invalid base64 in domain master key file"));
>> +        goto cleanup;
>> +    }
>> +
>> +    if (!masterKey || masterKeySize != QEMU_DOMAIN_MASTER_KEY_LEN) {
>> +        virReportError(VIR_ERR_INTERNAL_ERROR,
>> +                       _("invalid encoded master key read, size=%zd"),
>> +                       masterKeySize);
>> +        goto cleanup;
>> +    }
>> +
>> +    priv->masterKey = masterKey;
>> +    masterKey = NULL;
> 
> so this is NULL now and masterKeySize > 0
> 

doh.  Yep. and that's what happens when adding the cleanup: late

>> +
>> +    ret = 0;
>> +
>> + cleanup:
>> +    if (masterKeySize > 0)
>> +        memset(masterKey, 0, masterKeySize);
> 
> ... memset(NULL, 0, 32);
> 
> This crashes on success path.
> 
>> +    VIR_FREE(masterKey);
>> +
>> +    if (base64KeySize > 0)
>> +        memset(base64Key, 0, base64KeySize);
>> +    VIR_FREE(base64Key);
>> +
>> +    VIR_FREE(path);
>> +
>> +    return ret;
>> +}
>> +

[...]

>> +void
>> +qemuDomainMasterKeyRemove(qemuDomainObjPrivatePtr priv)
>> +{
>> +    char *path = NULL;
>> +
>> +    if (!priv->masterKey)
>> +        return;
>> +
>> +    /* Clear the heap */
>> +    memset(priv->masterKey, 0, QEMU_DOMAIN_MASTER_KEY_LEN);
>> +    VIR_FREE(priv->masterKey);
>> +
>> +    /* Clear and remove the master key file */
>> +    path = qemuDomainGetMasterKeyFilePath(priv->libDir);
>> +    if (path && virFileExists(path)) {
>> +        /* Write a "0" to the file even though we're about to delete it */
> 
> This still doesn't make any sense. The filesystem needs to guarantee
> this anyways. This is just a false sense of security.
> 

See my note in response to Dan's review. IDC either way.

>> +        ignore_value(virFileWriteStr(path, "0", 0600));
>> +        unlink(path);
>> +    }
>> +    VIR_FREE(path);
>> +}
>> +
>> +
>> +/* qemuDomainMasterKeyCreate:
>> + * @priv: Pointer to the domain private object
>> + *
>> + * As long as the underlying qemu has the secret capability,
>> + * generate and store as a base64 encoded value a random 32-byte
>> + * key to be used as a secret shared with qemu to share sensitive data.
>> + *
>> + * Returns: 0 on success, -1 w/ error message on failure
>> + */
>> +int
>> +qemuDomainMasterKeyCreate(qemuDomainObjPrivatePtr priv)
>> +{
>> +    char *key = NULL;
>> +
>> +    /* If we don't have the capability, then do nothing. */
>> +    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_OBJECT_SECRET))
>> +        return 0;
>> +
>> +    if (!(key = qemuDomainGenerateRandomKey(QEMU_DOMAIN_MASTER_KEY_LEN)))
>> +        goto error;
>> +
>> +    priv->masterKey = key;
>> +    key = NULL;
> 
> key isn't touched after the previous line, thus it doesn't make much
> sense to clear that variable.
> 

It was at one time, but there's no need for it now. No need for local
either.

>> +
>> +    if (qemuDomainWriteMasterKeyFile(priv) < 0)
>> +        goto error;
>> +
>> +    return 0;
>> +
>> + error:
>> +    qemuDomainMasterKeyRemove(priv);
>> +    return -1;
>> +}
>> +
>> +
>>  static virClassPtr qemuDomainDiskPrivateClass;
>>  
>>  static int
>> diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h
>> index 573968c..f85f17f 100644
>> --- a/src/qemu/qemu_domain.h
>> +++ b/src/qemu/qemu_domain.h
>> @@ -147,6 +147,7 @@ struct qemuDomainJobObj {
>>  typedef void (*qemuDomainCleanupCallback)(virQEMUDriverPtr driver,
>>                                            virDomainObjPtr vm);
>>  
>> +# define QEMU_DOMAIN_MASTER_KEY_LEN 32  /* For a 32-byte random masterKey */
> 
> 256 bit.
> 

6 of one, half dozen of another.

Tks -

John




More information about the libvir-list mailing list