[Libguestfs] [libnbd PATCH] states: Validate error message size

Eric Blake eblake at redhat.com
Fri Jun 14 14:35:14 UTC 2019


On 6/14/19 8:08 AM, Eric Blake wrote:
> If the server passes us a malformed error reply type with a message
> length longer than the overall structured reply, we would blindly obey
> that size and get out of sync with the server (perhaps even hanging on
> a read for data that will never come).  Broken since its introduction
> in commit 28952eda.
> 
> Fix it by parsing the tail of an error separate from the message,
> which also lets us add other sanity checking, and makes it easier if a
> future patch wants to capture instead of ignore the server's message.
> ---
> 


>   REPLY.STRUCTURED_REPLY.RECV_ERROR_MESSAGE:
> +  uint32_t length, msglen;
> +  uint16_t type;
> +
> +  switch (recv_into_rbuf (h)) {
> +  case -1: SET_NEXT_STATE (%.DEAD); return -1;
> +  case 0:
> +    length = be32toh (h->sbuf.sr.structured_reply.length);
> +    msglen = be16toh (h->sbuf.sr.payload.error.len);
> +    type = be16toh (h->sbuf.sr.structured_reply.type);

h->sbuf is a union...

> +
> +    length -= sizeof h->sbuf.sr.payload.error - msglen;
> +
> +    /* Special case two specific errors; ignore the 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 -1;
> +      }
> +      break;
> +    case NBD_REPLY_TYPE_ERROR_OFFSET:
> +      if (length != sizeof h->sbuf.offset) {
> +        SET_NEXT_STATE (%.DEAD);
> +        set_error (0, "error payload length too large");
> +        return -1;
> +      }
> +      h->rbuf = &h->sbuf.offset;

...placing offset directly in sbuf means that sbuf.sr is partially
invalidated...

> +      break;
> +    }
> +    SET_NEXT_STATE (%RECV_ERROR_TAIL);
> +  }
> +  return 0;
> +
> + REPLY.STRUCTURED_REPLY.RECV_ERROR_TAIL:
>    struct command_in_flight *cmd;
>    uint16_t flags;
>    uint64_t handle;
>    uint32_t error;
> +  uint64_t offset;
> 
>    switch (recv_into_rbuf (h)) {
>    case -1: SET_NEXT_STATE (%.DEAD); return -1;
  case 0:
    flags = be16toh (h->sbuf.sr.structured_reply.flags);
    handle = be64toh (h->sbuf.sr.structured_reply.handle);
    error = be32toh (h->sbuf.sr.payload.error.error);

which is not good for this.

> +++ b/lib/internal.h
> @@ -143,6 +143,7 @@ struct nbd_handle {
>      uint32_t len;
>      uint16_t nrinfos;
>      uint32_t nrqueries;
> +    uint64_t offset;
>    } sbuf;

So I'll need to move offset to a separate location other than sbuf.

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

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20190614/79fc56d3/attachment.sig>


More information about the Libguestfs mailing list