From: Amarnath Valluri <amarnath.valluri@intel.com>
To: "Daniel P. Berrange" <berrange@redhat.com>
Cc: qemu-devel@nongnu.org, patrick.ohly@intel.com,
stefanb@linux.vnet.ibm.com, marcandre.lureau@gmail.com
Subject: Re: [Qemu-devel] [PATCH v2 9/9] tpm: Added support for TPM emulator
Date: Mon, 10 Apr 2017 10:08:21 +0300 [thread overview]
Message-ID: <d74c2094-051e-bf1d-7c41-316b0e3651bc@intel.com> (raw)
In-Reply-To: <20170407144100.GL26896@redhat.com>
On 07.04.2017 17:41, Daniel P. Berrange wrote:
> On Fri, Apr 07, 2017 at 05:30:31PM +0300, Amarnath Valluri wrote:
>> This change introduces a new TPM backend driver that can communicate with
>> swtpm(software TPM emulator) using unix domain socket interface.
>>
>> Swtpm uses two unix sockets, one for plain TPM commands and responses, and one
>> for out-of-band control messages.
>>
>> The swtpm and associated tools can be found here:
>> https://github.com/stefanberger/swtpm
>>
>> Usage:
>> # setup TPM state directory
>> mkdir /tmp/mytpm
>> chown -R tss:root /tmp/mytpm
>> /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek
>>
>> # Ask qemu to use TPM emulator with given tpm state directory
>> qemu-system-x86_64 \
>> [...] \
>> -tpmdev emulator,id=tpm0,tpmstatedir=/tmp/mytpm,logfile=/tmp/swtpm.log \
>> -device tpm-tis,tpmdev=tpm0 \
>> [...]
>>
>> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
>> ---
>> configure | 15 +-
>> hmp.c | 21 ++
>> hw/tpm/Makefile.objs | 1 +
>> hw/tpm/tpm_emulator.c | 927 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> hw/tpm/tpm_ioctl.h | 243 +++++++++++++
>> qapi-schema.json | 36 +-
>> qemu-options.hx | 53 ++-
>> tpm.c | 2 +-
>> 8 files changed, 1289 insertions(+), 9 deletions(-)
>> create mode 100644 hw/tpm/tpm_emulator.c
>> create mode 100644 hw/tpm/tpm_ioctl.h
>> +static int tpm_emulator_spawn_emulator(TPMEmulator *tpm_pt)
>> +{
>> + int fds[2] = { -1, -1 };
>> + int ctrl_fds[2] = { -1, -1 };
>> + pid_t cpid;
>> +
>> + if (!tpm_pt->ops->has_data_path) {
>> + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {
>> + return -1;
>> + }
>> + }
>> +
>> + if (!tpm_pt->ops->has_ctrl_path) {
>> + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctrl_fds) < 0) {
>> + if (!tpm_pt->ops->has_data_path) {
>> + closesocket(fds[0]);
>> + closesocket(fds[1]);
>> + }
>> + return -1;
>> + }
>> + }
>> +
>> + cpid = qemu_fork(NULL);
>> + if (cpid < 0) {
>> + error_report("tpm-emulator: Fork failure: %s", strerror(errno));
>> + if (!tpm_pt->ops->has_data_path) {
>> + closesocket(fds[0]);
>> + closesocket(fds[1]);
>> + }
>> + if (!tpm_pt->ops->has_ctrl_path) {
>> + closesocket(ctrl_fds[0]);
>> + closesocket(ctrl_fds[1]);
>> + }
>> + return -1;
>> + }
>> +
>> + if (cpid == 0) { /* CHILD */
>> + enum {
>> + PARAM_PATH,
>> + PARAM_IFACE,
>> + PARAM_SERVER, PARAM_SERVER_ARGS,
>> + PARAM_CTRL, PARAM_CTRL_ARGS,
>> + PARAM_STATE, PARAM_STATE_ARGS,
>> + PARAM_PIDFILE, PARAM_PIDFILE_ARGS,
>> + PARAM_LOG, PARAM_LOG_ARGS,
>> + PARAM_MAX
>> + };
>> +
>> + int i;
>> + int data_fd = -1, ctrl_fd = -1;
>> + char *argv[PARAM_MAX+1];
>> +
>> + /* close all unused inherited sockets */
>> + if (fds[0] >= 0)
>> + closesocket(fds[0]);
>> + if (ctrl_fds[0] >= 0)
>> + closesocket(ctrl_fds[0]);
> The 'if' checks are pointless - its already guaranteed by the
> fact you check socketpair() status.
socketpairs might not be created in case of data-path & ctrl-path
provided, so i feel these checks are needed.
>
>> + i = STDERR_FILENO + 1;
>> + if (fds[1] >= 0) {
>> + data_fd = dup2(fds[1], i++);
>> + if (data_fd < 0) {
>> + error_report("tpm-emulator: dup2() failure - %s",
>> + strerror(errno));
>> + goto exit_child;
>> + }
>> + }
>> + if (ctrl_fds[1] >= 0) {
>> + ctrl_fd = dup2(ctrl_fds[1], i++);
>> + if (ctrl_fd < 0) {
>> + error_report("tpm-emulator: dup2() failure - %s",
>> + strerror(errno));
>> + goto exit_child;
>> + }
>> + }
>> + for ( ; i < _SC_OPEN_MAX; i++) {
> Errr, _SC_OPEN_MAX is not the maximum number of FDs - it is parameter to
> use with sysconf() to query the number of files - you must call sysconf().
Ya, thanks for educating me, i will change this.
>
>> + closesocket(i);
> close, not closesocket - you can't assume these are all sockets.
Does this change makes any difference, as per
include/sysemu/os-posix.h, closesocket() is define as close(), and this
backend is targeted only for "Linux" targets. Please let me know if i am
missing something.
>
>
>> + DPRINT("\n")
>> + if (execv(tpm_pt->ops->path, (char * const *)argv) < 0) {
>> + error_report("execv() failure : %s", strerror(errno));
>> + }
>> +
>> +exit_child:
>> + g_strfreev(argv);
>> + if (data_fd >= 0)
>> + closesocket(data_fd);
>> + if (ctrl_fd >= 0)
>> + closesocket(ctrl_fd);
>> +
>> + exit(0);
> You need _exit(), not exit() as you don't want to run atexit() handlers
> here. You also want '1' not '0' since this is a failure scenario.
Sure, i will change this.
>
>> + } else { /* self */
>> + struct stat st;
>> + DPRINTF("child pid: %d", cpid);
>> + int rc;
>> + int timeout = 3; /* wait for max 3 seconds */
>> +
>> + /* close unsed sockets */
>> + if (fds[1] >= 0)
>> + closesocket(fds[1]);
>> + if (ctrl_fds[1] >= 0)
>> + closesocket(ctrl_fds[1]);
>> +
>> + while((rc = stat(TPM_EMULATOR_PIDFILE, &st)) < 0 && timeout--) {
>> + sleep(1);
>> + }
> A fixed 3 second timeout will inevitably cause failures on systems with
> high load.
>
> Presumably you're trying to handle the scenario where the child process
> exits without creating the pid file ?
The check is mainly to know if the child setup is done and ready to
accept requests.
>
> In which case you can use 'kill(cpid, 0)' and if errno == ESRCH
> then the child has exited.
>
>> +
>> + if (timeout == -1) {
>> + error_report("tpm-emulator: failed to find pid file: %s",
>> + strerror(errno));
>> + goto err_kill_child;
>> + }
>> +
>> + tpm_pt->data_ioc = _iochannel_new(tpm_pt->ops->data_path, fds[0], NULL);
>> + if (!tpm_pt->data_ioc) {
>> + error_report("tpm-emulator: Unable to connect socket : %s",
>> + tpm_pt->ops->data_path);
>> + goto err_kill_child;
>> + }
>> +
>> + tpm_pt->ctrl_ioc = _iochannel_new(tpm_pt->ops->ctrl_path, ctrl_fds[0], NULL);
>> + if (!tpm_pt->ctrl_ioc) {
>> + error_report("tpm-emulator: Unable to connect socket : %s",
>> + tpm_pt->ops->ctrl_path);
>> + goto err_kill_child;
>> + }
>> +
>> + tpm_pt->child_running = true;
>> +
>> + qemu_add_child_watch(cpid);
>> +
>> + qio_channel_add_watch(tpm_pt->data_ioc, G_IO_HUP|G_IO_ERR,
>> + tpm_emulator_fd_handler, tpm_pt, NULL);
>> + }
>> +
>> + return 0;
>> +
>> +err_kill_child:
>> + kill(cpid, SIGTERM);
>> + closesocket(fds[0]);
>> + closesocket(ctrl_fds[0]);
> You can't assume the child has gone after a SIGTERM. You need to
> check, and be prepared to SIGKILL after time reasonable time,
> if needed.
Ok, i will add this check.
>
>> + tpm_pt->child_running = false;
>> +
>> + return -1;
>> +}
>> +
>> +static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
>> + TPM_STANDARD_CMDLINE_OPTS,
>> + {
>> + .name = "tpmstatedir",
>> + .type = QEMU_OPT_STRING,
>> + .help = "TPM state directroy",
>> + },
>> + {
>> + .name = "spawn",
>> + .type = QEMU_OPT_BOOL,
>> + .help = "Wether to spwan given emlatory binary",
>> + },
>> + {
>> + .name = "path",
>> + .type = QEMU_OPT_STRING,
>> + .help = "Path to TPM emulator binary",
>> + },
>> + {
>> + .name = "data-path",
>> + .type = QEMU_OPT_STRING,
>> + .help = "Socket path to use for data exhange",
>> + },
>> + {
>> + .name = "ctrl-path",
>> + .type = QEMU_OPT_STRING,
>> + .help = "Socket path to use for out-of-band control messages",
>> + },
> I'm still not convinced by the need for 2 separate UNIX sockets, unless
> there's a performance reason, but that looks unlikely.
I myself, is not expert of swtpm's interface, hence i cannot defend this.
i am just trying to enable emulation support in qemu using swtpm. Stefan
Berger is the right person to comment on this.
- Amarnath
next prev parent reply other threads:[~2017-04-10 7:09 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-04-07 14:30 [Qemu-devel] [PATCH v2 0/9] Provide support for the software TPM Amarnath Valluri
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 1/9] tpm-backend: Remove unneeded member variable from backend class Amarnath Valluri
2017-04-25 18:19 ` Stefan Berger
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 2/9] tpm-backend: Move thread handling inside TPMBackend Amarnath Valluri
2017-04-25 18:21 ` Stefan Berger
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 3/9] tpm-backend: Initialize and free data members in it's own methods Amarnath Valluri
2017-04-25 18:27 ` Stefan Berger
2017-05-02 7:09 ` Amarnath Valluri
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 4/9] tpm-backend: Made few interface methods optional Amarnath Valluri
2017-04-25 18:29 ` Stefan Berger
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 5/9] tmp backend: Add new api to read backend TpmInfo Amarnath Valluri
2017-04-25 18:51 ` Stefan Berger
2017-04-25 18:59 ` Eric Blake
2017-05-02 7:17 ` Amarnath Valluri
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 6/9] tpm-backend: Remove unneeded destroy() method from TpmDriverOps interface Amarnath Valluri
2017-04-25 18:59 ` Stefan Berger
2017-05-02 7:42 ` Amarnath Valluri
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 7/9] tpm-backend: Move realloc_buffer() implementation to base class Amarnath Valluri
2017-04-25 19:01 ` Stefan Berger
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 8/9] tpm-passthrough: move reusable code to utils Amarnath Valluri
2017-04-25 19:09 ` Stefan Berger
2017-04-07 14:30 ` [Qemu-devel] [PATCH v2 9/9] tpm: Added support for TPM emulator Amarnath Valluri
2017-04-07 14:41 ` Daniel P. Berrange
2017-04-07 15:11 ` Marc-André Lureau
2017-04-10 7:34 ` Amarnath Valluri
2017-04-10 9:54 ` Marc-André Lureau
2017-04-10 10:07 ` Patrick Ohly
2017-04-10 16:14 ` Stefan Berger
2017-04-10 21:11 ` Stefan Berger
2017-04-10 7:08 ` Amarnath Valluri [this message]
2017-04-10 8:31 ` Daniel P. Berrange
2017-04-10 16:15 ` Stefan Berger
2017-04-25 19:35 ` Stefan Berger
2017-04-12 23:52 ` [Qemu-devel] [PATCH v2 0/9] Provide support for the software TPM no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=d74c2094-051e-bf1d-7c41-316b0e3651bc@intel.com \
--to=amarnath.valluri@intel.com \
--cc=berrange@redhat.com \
--cc=marcandre.lureau@gmail.com \
--cc=patrick.ohly@intel.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanb@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).