mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-10 14:57:42 +00:00
tpm: Use fd to pass password to swtpm_setup and swtpm
Allow vTPM state encryption when swtpm_setup and swtpm support passing a passphrase using a file descriptor. This patch enables the encryption of the vTPM state only. It does not encrypt the state during migration, so the destination secret does not need to have the same password at this point. Signed-off-by: Stefan Berger <stefanb@linux.ibm.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
parent
52f115682f
commit
5eeff28585
@ -3182,7 +3182,9 @@ virTPMEmulatorInit;
|
|||||||
virTPMGetSwtpm;
|
virTPMGetSwtpm;
|
||||||
virTPMGetSwtpmIoctl;
|
virTPMGetSwtpmIoctl;
|
||||||
virTPMGetSwtpmSetup;
|
virTPMGetSwtpmSetup;
|
||||||
|
virTPMSwtpmCapsGet;
|
||||||
virTPMSwtpmFeatureTypeFromString;
|
virTPMSwtpmFeatureTypeFromString;
|
||||||
|
virTPMSwtpmSetupCapsGet;
|
||||||
virTPMSwtpmSetupFeatureTypeFromString;
|
virTPMSwtpmSetupFeatureTypeFromString;
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "dirname.h"
|
#include "dirname.h"
|
||||||
#include "qemu_tpm.h"
|
#include "qemu_tpm.h"
|
||||||
#include "virtpm.h"
|
#include "virtpm.h"
|
||||||
|
#include "secret_util.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NONE
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
||||||
|
|
||||||
@ -373,6 +374,66 @@ qemuTPMEmulatorPrepareHost(virDomainTPMDefPtr tpm,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* qemuTPMSetupEncryption
|
||||||
|
*
|
||||||
|
* @secretuuid: The UUID with the secret holding passphrase
|
||||||
|
* @cmd: the virCommand to transfer the secret to
|
||||||
|
*
|
||||||
|
* Returns file descriptor representing the read-end of a pipe.
|
||||||
|
* The passphrase can be read from this pipe. Returns < 0 in case
|
||||||
|
* of error.
|
||||||
|
*
|
||||||
|
* This function reads the passphrase and writes it into the
|
||||||
|
* write-end of a pipe so that the read-end of the pipe can be
|
||||||
|
* passed to the emulator for reading the passphrase from.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
qemuTPMSetupEncryption(const unsigned char *secretuuid,
|
||||||
|
virCommandPtr cmd)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
int pipefd[2] = { -1, -1 };
|
||||||
|
virConnectPtr conn;
|
||||||
|
VIR_AUTOFREE(uint8_t *) secret = NULL;
|
||||||
|
size_t secret_len;
|
||||||
|
virSecretLookupTypeDef seclookupdef = {
|
||||||
|
.type = VIR_SECRET_LOOKUP_TYPE_UUID,
|
||||||
|
};
|
||||||
|
|
||||||
|
conn = virGetConnectSecret();
|
||||||
|
if (!conn)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memcpy(seclookupdef.u.uuid, secretuuid, sizeof(seclookupdef.u.uuid));
|
||||||
|
if (virSecretGetSecretString(conn, &seclookupdef,
|
||||||
|
VIR_SECRET_USAGE_TYPE_VTPM,
|
||||||
|
&secret, &secret_len) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (pipe(pipefd) == -1) {
|
||||||
|
virReportSystemError(errno, "%s",
|
||||||
|
_("Unable to create pipe"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virCommandSetSendBuffer(cmd, pipefd[1], secret, secret_len) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
secret = NULL;
|
||||||
|
ret = pipefd[0];
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virObjectUnref(conn);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
error:
|
||||||
|
VIR_FORCE_CLOSE(pipefd[1]);
|
||||||
|
VIR_FORCE_CLOSE(pipefd[0]);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* qemuTPMEmulatorRunSetup
|
* qemuTPMEmulatorRunSetup
|
||||||
@ -387,6 +448,7 @@ qemuTPMEmulatorPrepareHost(virDomainTPMDefPtr tpm,
|
|||||||
* @logfile: The file to write the log into; it must be writable
|
* @logfile: The file to write the log into; it must be writable
|
||||||
* for the user given by userid or 'tss'
|
* for the user given by userid or 'tss'
|
||||||
* @tpmversion: The version of the TPM, either a TPM 1.2 or TPM 2
|
* @tpmversion: The version of the TPM, either a TPM 1.2 or TPM 2
|
||||||
|
* @encryption: pointer to virStorageEncryption holding secret
|
||||||
*
|
*
|
||||||
* Setup the external swtpm by creating endorsement key and
|
* Setup the external swtpm by creating endorsement key and
|
||||||
* certificates for it.
|
* certificates for it.
|
||||||
@ -399,7 +461,8 @@ qemuTPMEmulatorRunSetup(const char *storagepath,
|
|||||||
uid_t swtpm_user,
|
uid_t swtpm_user,
|
||||||
gid_t swtpm_group,
|
gid_t swtpm_group,
|
||||||
const char *logfile,
|
const char *logfile,
|
||||||
const virDomainTPMVersion tpmversion)
|
const virDomainTPMVersion tpmversion,
|
||||||
|
const unsigned char *secretuuid)
|
||||||
{
|
{
|
||||||
virCommandPtr cmd = NULL;
|
virCommandPtr cmd = NULL;
|
||||||
int exitstatus;
|
int exitstatus;
|
||||||
@ -407,6 +470,7 @@ qemuTPMEmulatorRunSetup(const char *storagepath,
|
|||||||
char uuid[VIR_UUID_STRING_BUFLEN];
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
||||||
char *vmid = NULL;
|
char *vmid = NULL;
|
||||||
VIR_AUTOFREE(char *)swtpm_setup = virTPMGetSwtpmSetup();
|
VIR_AUTOFREE(char *)swtpm_setup = virTPMGetSwtpmSetup();
|
||||||
|
VIR_AUTOCLOSE pwdfile_fd = -1;
|
||||||
|
|
||||||
if (!swtpm_setup)
|
if (!swtpm_setup)
|
||||||
return -1;
|
return -1;
|
||||||
@ -439,6 +503,23 @@ qemuTPMEmulatorRunSetup(const char *storagepath,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (secretuuid) {
|
||||||
|
if (!virTPMSwtpmSetupCapsGet(
|
||||||
|
VIR_TPM_SWTPM_SETUP_FEATURE_CMDARG_PWDFILE_FD)) {
|
||||||
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
|
||||||
|
_("%s does not support passing a passphrase using a file "
|
||||||
|
"descriptor"), virTPMGetSwtpmSetup());
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if ((pwdfile_fd = qemuTPMSetupEncryption(secretuuid, cmd)) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
virCommandAddArg(cmd, "--pwdfile-fd");
|
||||||
|
virCommandAddArgFormat(cmd, "%d", pwdfile_fd);
|
||||||
|
virCommandAddArgList(cmd, "--cipher", "aes-256-cbc", NULL);
|
||||||
|
virCommandPassFD(cmd, pwdfile_fd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
||||||
|
pwdfile_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
virCommandAddArgList(cmd,
|
virCommandAddArgList(cmd,
|
||||||
"--tpm-state", storagepath,
|
"--tpm-state", storagepath,
|
||||||
@ -502,6 +583,8 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDefPtr tpm,
|
|||||||
bool created = false;
|
bool created = false;
|
||||||
char *pidfile;
|
char *pidfile;
|
||||||
VIR_AUTOFREE(char *) swtpm = virTPMGetSwtpm();
|
VIR_AUTOFREE(char *) swtpm = virTPMGetSwtpm();
|
||||||
|
VIR_AUTOCLOSE pwdfile_fd = -1;
|
||||||
|
const unsigned char *secretuuid = NULL;
|
||||||
|
|
||||||
if (!swtpm)
|
if (!swtpm)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -510,10 +593,14 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDefPtr tpm,
|
|||||||
&created, swtpm_user, swtpm_group) < 0)
|
&created, swtpm_user, swtpm_group) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (tpm->data.emulator.hassecretuuid)
|
||||||
|
secretuuid = tpm->data.emulator.secretuuid;
|
||||||
|
|
||||||
if (created &&
|
if (created &&
|
||||||
qemuTPMEmulatorRunSetup(tpm->data.emulator.storagepath, vmname, vmuuid,
|
qemuTPMEmulatorRunSetup(tpm->data.emulator.storagepath, vmname, vmuuid,
|
||||||
privileged, swtpm_user, swtpm_group,
|
privileged, swtpm_user, swtpm_group,
|
||||||
tpm->data.emulator.logfile, tpm->version) < 0)
|
tpm->data.emulator.logfile, tpm->version,
|
||||||
|
secretuuid) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
unlink(tpm->data.emulator.source.data.nix.path);
|
unlink(tpm->data.emulator.source.data.nix.path);
|
||||||
@ -556,6 +643,25 @@ qemuTPMEmulatorBuildCommand(virDomainTPMDefPtr tpm,
|
|||||||
virCommandAddArgFormat(cmd, "file=%s", pidfile);
|
virCommandAddArgFormat(cmd, "file=%s", pidfile);
|
||||||
VIR_FREE(pidfile);
|
VIR_FREE(pidfile);
|
||||||
|
|
||||||
|
if (tpm->data.emulator.hassecretuuid) {
|
||||||
|
if (!virTPMSwtpmCapsGet(VIR_TPM_SWTPM_FEATURE_CMDARG_PWD_FD)) {
|
||||||
|
virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
|
||||||
|
_("%s does not support passing passphrase via file descriptor"),
|
||||||
|
virTPMGetSwtpm());
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
pwdfile_fd = qemuTPMSetupEncryption(tpm->data.emulator.secretuuid, cmd);
|
||||||
|
if (pwdfile_fd)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
virCommandAddArg(cmd, "--key");
|
||||||
|
virCommandAddArgFormat(cmd, "pwdfd=%d,mode=aes-256-cbc",
|
||||||
|
pwdfile_fd);
|
||||||
|
virCommandPassFD(cmd, pwdfile_fd, VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
||||||
|
pwdfile_fd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
|
@ -349,3 +349,19 @@ virTPMEmulatorInit(void)
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
virTPMSwtpmCapsGet(unsigned int cap)
|
||||||
|
{
|
||||||
|
if (virTPMEmulatorInit() < 0)
|
||||||
|
return false;
|
||||||
|
return virBitmapIsBitSet(swtpm_caps, cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
virTPMSwtpmSetupCapsGet(unsigned int cap)
|
||||||
|
{
|
||||||
|
if (virTPMEmulatorInit() < 0)
|
||||||
|
return false;
|
||||||
|
return virBitmapIsBitSet(swtpm_setup_caps, cap);
|
||||||
|
}
|
||||||
|
@ -27,6 +27,9 @@ char *virTPMGetSwtpmSetup(void);
|
|||||||
char *virTPMGetSwtpmIoctl(void);
|
char *virTPMGetSwtpmIoctl(void);
|
||||||
int virTPMEmulatorInit(void);
|
int virTPMEmulatorInit(void);
|
||||||
|
|
||||||
|
bool virTPMSwtpmCapsGet(unsigned int cap);
|
||||||
|
bool virTPMSwtpmSetupCapsGet(unsigned int cap);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
VIR_TPM_SWTPM_FEATURE_CMDARG_PWD_FD,
|
VIR_TPM_SWTPM_FEATURE_CMDARG_PWD_FD,
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user