diff --git a/src/libvirt.c b/src/libvirt.c index 467f6dde45..33a4419941 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -7786,6 +7786,8 @@ error: * For your program to be able to work reliably over a remote * connection you should split large requests to <= 65536 bytes. * However, with 0.9.13 this RPC limit has been raised to 1M byte. + * Starting with version 1.0.6 the RPC limit has been raised again. + * Now large requests up to 16M byte are supported. * * Returns: 0 in case of success or -1 in case of failure. */ @@ -7936,6 +7938,8 @@ error: * For your program to be able to work reliably over a remote * connection you should split large requests to <= 65536 bytes. * However, with 0.9.13 this RPC limit has been raised to 1M byte. + * Starting with version 1.0.6 the RPC limit has been raised again. + * Now large requests up to 16M byte are supported. * * Returns: 0 in case of success or -1 in case of failure. */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 512ba2e292..f61d10c0cd 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -65,7 +65,7 @@ * This is an arbitrary limit designed to stop the decoder from trying * to allocate unbounded amounts of memory when fed with a bad message. */ -const REMOTE_STRING_MAX = 1048576; +const REMOTE_STRING_MAX = 4194304; /* A long string, which may NOT be NULL. */ typedef string remote_nonnull_string; @@ -160,13 +160,13 @@ const REMOTE_DOMAIN_SNAPSHOT_LIST_NAMES_MAX = 1024; * Note applications need to be aware of this limit and issue multiple * requests for large amounts of data. */ -const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 1048576; +const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 4194304; /* Maximum length of a memory peek buffer message. * Note applications need to be aware of this limit and issue multiple * requests for large amounts of data. */ -const REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX = 1048576; +const REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX = 4194304; /* * Maximum length of a security label list. diff --git a/src/rpc/virnetmessage.c b/src/rpc/virnetmessage.c index 647fef7be4..b2c6e5b02a 100644 --- a/src/rpc/virnetmessage.c +++ b/src/rpc/virnetmessage.c @@ -221,7 +221,7 @@ int virNetMessageEncodeHeader(virNetMessagePtr msg) int ret = -1; unsigned int len = 0; - msg->bufferLength = VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX; + msg->bufferLength = VIR_NET_MESSAGE_INITIAL + VIR_NET_MESSAGE_LEN_MAX; if (VIR_REALLOC_N(msg->buffer, msg->bufferLength) < 0) { virReportOOMError(); return ret; @@ -351,9 +351,27 @@ int virNetMessageEncodePayload(virNetMessagePtr msg, xdrmem_create(&xdr, msg->buffer + msg->bufferOffset, msg->bufferLength - msg->bufferOffset, XDR_ENCODE); - if (!(*filter)(&xdr, data)) { - virReportError(VIR_ERR_RPC, "%s", _("Unable to encode message payload")); - goto error; + /* Try to encode the payload. If the buffer is too small increase it. */ + while (!(*filter)(&xdr, data)) { + if ((msg->bufferLength - VIR_NET_MESSAGE_LEN_MAX) * 4 > VIR_NET_MESSAGE_MAX) { + virReportError(VIR_ERR_RPC, "%s", _("Unable to encode message payload")); + goto error; + } + + xdr_destroy(&xdr); + + msg->bufferLength = (msg->bufferLength - VIR_NET_MESSAGE_LEN_MAX) * 4 + + VIR_NET_MESSAGE_LEN_MAX; + + if (VIR_REALLOC_N(msg->buffer, msg->bufferLength) < 0) { + virReportOOMError(); + goto error; + } + + xdrmem_create(&xdr, msg->buffer + msg->bufferOffset, + msg->bufferLength - msg->bufferOffset, XDR_ENCODE); + + VIR_DEBUG("Increased message buffer length = %zu", msg->bufferLength); } /* Get the length stored in buffer. */ @@ -415,11 +433,23 @@ int virNetMessageEncodePayloadRaw(virNetMessagePtr msg, XDR xdr; unsigned int msglen; + /* If the message buffer is too small for the payload increase it accordingly. */ if ((msg->bufferLength - msg->bufferOffset) < len) { - virReportError(VIR_ERR_RPC, - _("Stream data too long to send (%zu bytes needed, %zu bytes available)"), - len, (msg->bufferLength - msg->bufferOffset)); - return -1; + if ((msg->bufferOffset + len) > VIR_NET_MESSAGE_MAX) { + virReportError(VIR_ERR_RPC, + _("Stream data too long to send (%zu bytes needed, %zu bytes available)"), + len, (VIR_NET_MESSAGE_MAX - msg->bufferOffset)); + return -1; + } + + msg->bufferLength = msg->bufferOffset + len; + + if (VIR_REALLOC_N(msg->buffer, msg->bufferLength) < 0) { + virReportOOMError(); + return -1; + } + + VIR_DEBUG("Increased message buffer length = %zu", msg->bufferLength); } memcpy(msg->buffer + msg->bufferOffset, data, len); diff --git a/src/rpc/virnetmessage.h b/src/rpc/virnetmessage.h index dfa1c6ca87..c94dddc259 100644 --- a/src/rpc/virnetmessage.h +++ b/src/rpc/virnetmessage.h @@ -34,7 +34,8 @@ typedef void (*virNetMessageFreeCallback)(virNetMessagePtr msg, void *opaque); struct _virNetMessage { bool tracked; - char *buffer; /* Typically VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX */ + char *buffer; /* Initially VIR_NET_MESSAGE_INITIAL + VIR_NET_MESSAGE_LEN_MAX */ + /* Maximum VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX */ size_t bufferLength; size_t bufferOffset; diff --git a/src/rpc/virnetprotocol.x b/src/rpc/virnetprotocol.x index eb2e81d7d4..131e40b1c3 100644 --- a/src/rpc/virnetprotocol.x +++ b/src/rpc/virnetprotocol.x @@ -44,23 +44,31 @@ /*----- Data types. -----*/ +/* Initial message size. + * When the message payload is larger this initial size will be + * quadrupled until the maximum total message size is reached. + */ +const VIR_NET_MESSAGE_INITIAL = 65536; + /* Maximum total message size (serialised). */ -const VIR_NET_MESSAGE_MAX = 4194304; +const VIR_NET_MESSAGE_MAX = 16777216; /* Size of struct virNetMessageHeader (serialised)*/ const VIR_NET_MESSAGE_HEADER_MAX = 24; /* Size of message payload */ -const VIR_NET_MESSAGE_PAYLOAD_MAX = 4194280; +const VIR_NET_MESSAGE_PAYLOAD_MAX = 16777192; -/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX */ +/* Size of message length field. Not counted in VIR_NET_MESSAGE_MAX + * and VIR_NET_MESSAGE_INITIAL. + */ const VIR_NET_MESSAGE_LEN_MAX = 4; /* Length of long, but not unbounded, strings. * This is an arbitrary limit designed to stop the decoder from trying * to allocate unbounded amounts of memory when fed with a bad message. */ -const VIR_NET_MESSAGE_STRING_MAX = 1048576; +const VIR_NET_MESSAGE_STRING_MAX = 4194304; /* Limit on number of File Descriptors allowed to be * passed per message diff --git a/tests/virnetmessagetest.c b/tests/virnetmessagetest.c index 96defe420f..fabeffd19b 100644 --- a/tests/virnetmessagetest.c +++ b/tests/virnetmessagetest.c @@ -46,7 +46,7 @@ static int testMessageHeaderEncode(const void *args ATTRIBUTE_UNUSED) }; /* According to doc to virNetMessageEncodeHeader(&msg): * msg->buffer will be this long */ - unsigned long msg_buf_size = VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX; + unsigned long msg_buf_size = VIR_NET_MESSAGE_INITIAL + VIR_NET_MESSAGE_LEN_MAX; int ret = -1; if (!msg) {