@@ -109,7 +109,23 @@ REPLY.START:
REPLY.RECV_REPLY:
switch (recv_into_rbuf (h)) {
case -1: SET_NEXT_STATE (%.DEAD); return 0;
- case 1: SET_NEXT_STATE (%.READY); return 0;
+ case 1: SET_NEXT_STATE (%.READY);
+ /* Special case: if we have a short read, but got at least far
+ * enough to decode the magic number, we can check if the server
+ * is matching our expectations. This lets us avoid deadlocking if
+ * a buggy server sends only 16 bytes of a simple reply, and is
+ * waiting for our next command, while we are blocked waiting for
+ * the server to send 32 bytes of an extended reply.
+ */
+ if (h->extended_headers &&
+ (char *) h->rbuf >= (char *) &h->sbuf.reply.hdr.extended.flags) {
+ uint32_t magic = be32toh (h->sbuf.reply.hdr.extended.magic);
+ if (magic != NBD_EXTENDED_REPLY_MAGIC) {
+ SET_NEXT_STATE (%.DEAD); /* We've probably lost synchronization. */
+ set_error (0, "invalid or unexpected reply magic 0x%" PRIx32, magic);
+ }
+ }
+ return 0;
case 0: SET_NEXT_STATE (%CHECK_SIMPLE_OR_STRUCTURED_REPLY);
}
return 0;