All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Daniel P. Berrangé" <berrange@redhat.com>
To: Stefan Berger <stefanb@linux.ibm.com>
Cc: qemu-devel@nongnu.org, marcandre.lureau@gmail.com
Subject: Re: [PATCH v3 2/2] tpm_emulator: Read control channel response in 2 passes
Date: Wed, 16 Oct 2024 16:16:39 +0100	[thread overview]
Message-ID: <Zw_Y1y-Cc134pkDW@redhat.com> (raw)
In-Reply-To: <20241016145708.1166471-3-stefanb@linux.ibm.com>

On Wed, Oct 16, 2024 at 10:57:08AM -0400, Stefan Berger wrote:
> Error responses from swtpm are typically only 4 bytes long with the
> exception of a few commands that return more bytes. Therefore, read the
> entire response in 2 passes and stop if the first few bytes indicate an
> error response with no subsequent bytes readable. Read the rest in a 2nd
> pass, if needed. This avoids getting stuck while waiting for too many
> bytes. The 'getting stuck' condition has not been observed in practice so
> far, though.
> 
> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2615
> Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
> ---
>  backends/tpm/tpm_emulator.c | 65 ++++++++++++++++++++++++++++---------
>  1 file changed, 49 insertions(+), 16 deletions(-)
> 
> diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c
> index b0e2fb3fc7..dfb298a16d 100644
> --- a/backends/tpm/tpm_emulator.c
> +++ b/backends/tpm/tpm_emulator.c
> @@ -123,12 +123,17 @@ static const char *tpm_emulator_strerror(uint32_t tpm_result)
>  }
>  
>  static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
> -                                size_t msg_len_in, size_t msg_len_out)
> +                                size_t msg_len_in, size_t msg_len_out_err,
> +                                size_t msg_len_out_total)
>  {
>      CharBackend *dev = &tpm->ctrl_chr;
>      uint32_t cmd_no = cpu_to_be32(cmd);
>      ssize_t n = sizeof(uint32_t) + msg_len_in;
> +    size_t left_to_read = msg_len_out_total;
>      uint8_t *buf = NULL;
> +    ptm_res res;
> +    off_t o = 0;
> +    int to_read;
>  
>      WITH_QEMU_LOCK_GUARD(&tpm->mutex) {
>          buf = g_alloca(n);
> @@ -140,11 +145,28 @@ static int tpm_emulator_ctrlcmd(TPMEmulator *tpm, unsigned long cmd, void *msg,
>              return -1;
>          }
>  
> -        if (msg_len_out != 0) {
> -            n = qemu_chr_fe_read_all(dev, msg, msg_len_out);
> +        if (msg_len_out_err > 0) {
> +            to_read = msg_len_out_err;
> +        } else {
> +            to_read = left_to_read;
> +        }
> +        while (to_read > 0) {
> +            n = qemu_chr_fe_read_all(dev, (uint8_t *)msg + o, to_read);
>              if (n <= 0) {
>                  return -1;
>              }
> +            left_to_read -= n;
> +            if (left_to_read == 0) {
> +                return 0;
> +            }
> +            /* result error code is always in the first 4 bytes */
> +            memcpy(&res, msg, sizeof(res));
> +            if (res) {
> +                return 0;
> +            }
> +
> +            o = to_read;
> +            to_read = left_to_read;
>          }

Using qemu_chr_fe_read_all in a loop feels like an anti-pattern, since
it will always read exactly the full amount you ask, or return an error.

IOW, there code here is a rather confusing way to do exactly 2 reads
of the required size.  I think it'd be much clearer to just read in
two steps, without a loop like this:

  n = qemu_chr_fe_read_all(dev, (uint8_t *)msg, msg_len_out_err);
  if (n != msg_len_out_err) {
    return -1;
  }
 
  /* result error code is always in the first 4 bytes */
  memcpy(&res, msg, sizeof(res));
  if (res) {
     return 0;
  }

  assert(msg_len_out_err <= msg_len_out_total);
  msg_len_out_total -= msg_len_out_err;
  n = qemu_chr_fe_read_all(dev, (uint8_t *)msg + msg_len_out_err,
                           msg_len_out_total);
  if (n != msg_len_out_total) {
    return -1;
  }

  return 0;

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



      reply	other threads:[~2024-10-16 15:17 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-10-16 14:57 [PATCH v3 0/2] tpm: Resolve potential blocking-forever issue Stefan Berger
2024-10-16 14:57 ` [PATCH v3 1/2] tpm: Use new ptm_cap_n structure for PTM_GET_CAPABILITY Stefan Berger
2024-10-16 15:03   ` Daniel P. Berrangé
2024-10-16 17:01     ` Stefan Berger
2024-10-16 14:57 ` [PATCH v3 2/2] tpm_emulator: Read control channel response in 2 passes Stefan Berger
2024-10-16 15:16   ` Daniel P. Berrangé [this message]

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=Zw_Y1y-Cc134pkDW@redhat.com \
    --to=berrange@redhat.com \
    --cc=marcandre.lureau@gmail.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanb@linux.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.