Re: [Qemu-devel] [PATCH V22 6/7] Add support for cancelling of a TPM command

2013-02-15 Thread Corey Bryant



On 02/14/2013 04:43 PM, Stefan Berger wrote:

This patch adds support for cancelling an executing TPM command.
In Linux for example a user can cancel a command through the TPM's
sysfs 'cancel' entry using

echo 1  /sysfs/class/misc/tpm0/device/cancel

This patch propagates the cancellation of a command inside a VM
to the host TPM's sysfs entry.
It also uses the possibility to cancel the command before QEMU VM
shutdown or reboot, which helps in preventing QEMU from hanging while
waiting for the completion of the command.
To relieve higher layers or users from having to determine the TPM's
cancel sysfs entry, the driver searches for the entry in well known
locations.

Signed-off-by: Stefan Berger stef...@linux.vnet.ibm.com
---
  qemu-options.hx   |  13 +++-
  tpm/tpm_passthrough.c | 166 ++
  vl.c  |   5 ++
  3 files changed, 168 insertions(+), 16 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index ede6d94..410b7fa 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2193,8 +2193,10 @@ DEFHEADING()
  DEFHEADING(TPM device options:)

  DEF(tpmdev, HAS_ARG, QEMU_OPTION_tpmdev, \
--tpmdev passthrough,id=id[,path=path]\n
-use path to provide path to a character device; default is 
/dev/tpm0\n,
+-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n
+use path to provide path to a character device; default is 
/dev/tpm0\n
+use cancel-path to provide path to TPM's cancel sysfs entry; 
if\n
+not provided it will be searched for in 
/sys/class/misc/tpm?/device\n,
  QEMU_ARCH_ALL)
  STEXI

@@ -2216,7 +2218,7 @@ Use 'help' to print all available TPM backend types.
  qemu -tpmdev help
  @end example

-@item -tpmdev passthrough, id=@var{id}, path=@var{path}
+@item -tpmdev passthrough, id=@var{id}, path=@var{path}, path=@var{cancel-path}

  (Linux-host only) Enable access to the host's TPM using the passthrough
  driver.
@@ -2225,6 +2227,11 @@ driver.
  a Linux host this would be @code{/dev/tpm0}.
  @option{path} is optional and by default @code{/dev/tpm0} is used.

+@option{cancel-path} specifies the path to the host TPM device's sysfs
+entry allowing for cancellation of an ongoing TPM command.
+@option{cancel-path} is optional and by default QEMU will search for the
+sysfs entry to use.
+
  Some notes about using the host's TPM with the passthrough driver:

  The TPM device accessed by the passthrough driver must not be
diff --git a/tpm/tpm_passthrough.c b/tpm/tpm_passthrough.c
index 7d5de8e..300575b 100644
--- a/tpm/tpm_passthrough.c
+++ b/tpm/tpm_passthrough.c
@@ -22,6 +22,8 @@
   * License along with this library; if not, see http://www.gnu.org/licenses/
   */

+#include dirent.h
+
  #include qemu-common.h
  #include qapi/error.h
  #include qemu/sockets.h
@@ -57,11 +59,18 @@ struct TPMPassthruState {

  char *tpm_dev;
  int tpm_fd;
+bool tpm_executing;
+bool tpm_op_canceled;
+int cancel_fd;
  bool had_startup_error;
  };

  #define TPM_PASSTHROUGH_DEFAULT_DEVICE /dev/tpm0

+/* functions */
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
+
  static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t 
len)
  {
  return send_all(fd, buf, len);
@@ -79,25 +88,36 @@ static uint32_t tpm_passthrough_get_size_from_buffer(const 
uint8_t *buf)
  return be32_to_cpu(resp-len);
  }

-static int tpm_passthrough_unix_tx_bufs(int tpm_fd,
+static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
  const uint8_t *in, uint32_t in_len,
  uint8_t *out, uint32_t out_len)
  {
  int ret;

-ret = tpm_passthrough_unix_write(tpm_fd, in, in_len);
+tpm_pt-tpm_op_canceled = false;
+tpm_pt-tpm_executing = true;
+
+ret = tpm_passthrough_unix_write(tpm_pt-tpm_fd, in, in_len);
  if (ret != in_len) {
-error_report(tpm_passthrough: error while transmitting data 
- to TPM: %s (%i)\n,
- strerror(errno), errno);
+if (!tpm_pt-tpm_op_canceled ||
+(tpm_pt-tpm_op_canceled  errno != ECANCELED)) {
+error_report(tpm_passthrough: error while transmitting data 
+ to TPM: %s (%i)\n,
+ strerror(errno), errno);
+}
  goto err_exit;
  }

-ret = tpm_passthrough_unix_read(tpm_fd, out, out_len);
+tpm_pt-tpm_executing = false;
+
+ret = tpm_passthrough_unix_read(tpm_pt-tpm_fd, out, out_len);
  if (ret  0) {
-error_report(tpm_passthrough: error while reading data from 
- TPM: %s (%i)\n,
- strerror(errno), errno);
+if (!tpm_pt-tpm_op_canceled ||
+(tpm_pt-tpm_op_canceled  errno != ECANCELED)) {
+error_report(tpm_passthrough: error while reading data from 
+ TPM: %s 

[Qemu-devel] [PATCH V22 6/7] Add support for cancelling of a TPM command

2013-02-14 Thread Stefan Berger
This patch adds support for cancelling an executing TPM command.
In Linux for example a user can cancel a command through the TPM's
sysfs 'cancel' entry using

echo 1  /sysfs/class/misc/tpm0/device/cancel

This patch propagates the cancellation of a command inside a VM
to the host TPM's sysfs entry.
It also uses the possibility to cancel the command before QEMU VM
shutdown or reboot, which helps in preventing QEMU from hanging while
waiting for the completion of the command.
To relieve higher layers or users from having to determine the TPM's
cancel sysfs entry, the driver searches for the entry in well known
locations.

Signed-off-by: Stefan Berger stef...@linux.vnet.ibm.com
---
 qemu-options.hx   |  13 +++-
 tpm/tpm_passthrough.c | 166 ++
 vl.c  |   5 ++
 3 files changed, 168 insertions(+), 16 deletions(-)

diff --git a/qemu-options.hx b/qemu-options.hx
index ede6d94..410b7fa 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2193,8 +2193,10 @@ DEFHEADING()
 DEFHEADING(TPM device options:)
 
 DEF(tpmdev, HAS_ARG, QEMU_OPTION_tpmdev, \
--tpmdev passthrough,id=id[,path=path]\n
-use path to provide path to a character device; default 
is /dev/tpm0\n,
+-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n
+use path to provide path to a character device; default 
is /dev/tpm0\n
+use cancel-path to provide path to TPM's cancel sysfs 
entry; if\n
+not provided it will be searched for in 
/sys/class/misc/tpm?/device\n,
 QEMU_ARCH_ALL)
 STEXI
 
@@ -2216,7 +2218,7 @@ Use 'help' to print all available TPM backend types.
 qemu -tpmdev help
 @end example
 
-@item -tpmdev passthrough, id=@var{id}, path=@var{path}
+@item -tpmdev passthrough, id=@var{id}, path=@var{path}, path=@var{cancel-path}
 
 (Linux-host only) Enable access to the host's TPM using the passthrough
 driver.
@@ -2225,6 +2227,11 @@ driver.
 a Linux host this would be @code{/dev/tpm0}.
 @option{path} is optional and by default @code{/dev/tpm0} is used.
 
+@option{cancel-path} specifies the path to the host TPM device's sysfs
+entry allowing for cancellation of an ongoing TPM command.
+@option{cancel-path} is optional and by default QEMU will search for the
+sysfs entry to use.
+
 Some notes about using the host's TPM with the passthrough driver:
 
 The TPM device accessed by the passthrough driver must not be
diff --git a/tpm/tpm_passthrough.c b/tpm/tpm_passthrough.c
index 7d5de8e..300575b 100644
--- a/tpm/tpm_passthrough.c
+++ b/tpm/tpm_passthrough.c
@@ -22,6 +22,8 @@
  * License along with this library; if not, see http://www.gnu.org/licenses/
  */
 
+#include dirent.h
+
 #include qemu-common.h
 #include qapi/error.h
 #include qemu/sockets.h
@@ -57,11 +59,18 @@ struct TPMPassthruState {
 
 char *tpm_dev;
 int tpm_fd;
+bool tpm_executing;
+bool tpm_op_canceled;
+int cancel_fd;
 bool had_startup_error;
 };
 
 #define TPM_PASSTHROUGH_DEFAULT_DEVICE /dev/tpm0
 
+/* functions */
+
+static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
+
 static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
 {
 return send_all(fd, buf, len);
@@ -79,25 +88,36 @@ static uint32_t tpm_passthrough_get_size_from_buffer(const 
uint8_t *buf)
 return be32_to_cpu(resp-len);
 }
 
-static int tpm_passthrough_unix_tx_bufs(int tpm_fd,
+static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
 const uint8_t *in, uint32_t in_len,
 uint8_t *out, uint32_t out_len)
 {
 int ret;
 
-ret = tpm_passthrough_unix_write(tpm_fd, in, in_len);
+tpm_pt-tpm_op_canceled = false;
+tpm_pt-tpm_executing = true;
+
+ret = tpm_passthrough_unix_write(tpm_pt-tpm_fd, in, in_len);
 if (ret != in_len) {
-error_report(tpm_passthrough: error while transmitting data 
- to TPM: %s (%i)\n,
- strerror(errno), errno);
+if (!tpm_pt-tpm_op_canceled ||
+(tpm_pt-tpm_op_canceled  errno != ECANCELED)) {
+error_report(tpm_passthrough: error while transmitting data 
+ to TPM: %s (%i)\n,
+ strerror(errno), errno);
+}
 goto err_exit;
 }
 
-ret = tpm_passthrough_unix_read(tpm_fd, out, out_len);
+tpm_pt-tpm_executing = false;
+
+ret = tpm_passthrough_unix_read(tpm_pt-tpm_fd, out, out_len);
 if (ret  0) {
-error_report(tpm_passthrough: error while reading data from 
- TPM: %s (%i)\n,
- strerror(errno), errno);
+if (!tpm_pt-tpm_op_canceled ||
+(tpm_pt-tpm_op_canceled  errno != ECANCELED)) {
+error_report(tpm_passthrough: error while reading data from 
+ TPM: %s (%i)\n,
+ strerror(errno), errno);
+}
 }