[Libguestfs] [libnbd PATCH 4/4] states: Use RESYNC to handle more structured reply server bugs

Eric Blake eblake at redhat.com
Fri Aug 12 13:07:25 UTC 2022


On Thu, Aug 11, 2022 at 09:06:38PM -0500, Eric Blake wrote:
> 
> Again, compliant servers will never trip over to the new state; but an
> easy way to demonstrate this in action is with a temporary patch to
> nbdkit:

That tested one of the error paths; I found a few others where the
patch needed tweaks:

> @@ -222,13 +181,25 @@ STATE_MACHINE {
>      return 0;
>    case 0:
>      length = be32toh (h->sbuf.sr.structured_reply.length);
> +    assert (length >= sizeof h->sbuf.sr.payload.error.error.error);
> +    assert (cmd);
> +
> +    if (length < sizeof h->sbuf.sr.payload.error.error) {
> +    resync:
> +      /* Favor the error packet's errno over RESYNC's EPROTO. */
> +      error = be32toh (h->sbuf.sr.payload.error.error.error);
> +      if (cmd->error = 0)

Typo: that should be == rather than =.

> +        cmd->error = nbd_internal_errno_of_nbd_error (error);
> +      h->rbuf = NULL;
> +      h->rlen = length - MIN (length, sizeof h->sbuf.sr.payload.error.error);
> +      SET_NEXT_STATE (%RESYNC);
> +      return 0;
> +    }
> +
>      msglen = be16toh (h->sbuf.sr.payload.error.error.len);
...

> @@ -257,24 +228,21 @@ STATE_MACHINE {
>        debug (h, "structured error server message: %.*s", (int) msglen,
>               h->sbuf.sr.payload.error.msg);
> 
> -    /* Special case two specific errors; ignore the tail for all others */
> +    /* Special case two specific errors; silently ignore tail for all others */
>      h->rbuf = NULL;
>      h->rlen = length;
>      switch (type) {
>      case NBD_REPLY_TYPE_ERROR:
> -      if (length != 0) {
> -        SET_NEXT_STATE (%.DEAD);
> -        set_error (0, "error payload length too large");
> -        return 0;
> -      }
> +      if (length != 0)
> +        debug (h, "ignoring unexpected slop after error message, "
> +               "the server may have a bug");
>        break;
>      case NBD_REPLY_TYPE_ERROR_OFFSET:
> -      if (length != sizeof h->sbuf.sr.payload.error.offset) {
> -        SET_NEXT_STATE (%.DEAD);
> -        set_error (0, "invalid error payload length");
> -        return 0;
> -      }
> -      h->rbuf = &h->sbuf.sr.payload.error.offset;
> +      if (length == sizeof h->sbuf.sr.payload.error.offset)

and that should be !=, not ==.

> +        debug (h, "unable to safely extract error offset, "
> +               "the server may have a bug");
> +      else
> +        h->rbuf = &h->sbuf.sr.payload.error.offset;
>        break;
>      }
>      SET_NEXT_STATE (%RECV_ERROR_TAIL);

Plus a typo in the subject for 1/4.  With everything fixed, the series
is now in as 185195d..0883029.

Another leniency issue I am exploring is whether structured reply mode
can cope with a server that mistakenly sends a simply reply to
NBD_CMD_READ, and whether the client can ignore replies for an unknown
cookie.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org


More information about the Libguestfs mailing list