# HG changeset patch
# User John Levon <john.levon(a)sun.com>
# Date 1231946129 28800
# Node ID c7538cb7fab4e6f3aa6714fdd4126dcf2f0371b4
# Parent cfe04caba5de61620fa6d1c2bff85cfd62255c1d
Fix oversized stack allocation
REMOTE_MESSAGE_MAX is a whopping 262Kb and shouldn't be allocated on the
stack.
Signed-off-by: Ryan Scott <ryan.scott(a)sun.com>
diff --git a/src/remote_internal.c b/src/remote_internal.c
--- a/src/remote_internal.c
+++ b/src/remote_internal.c
@@ -4797,10 +4797,11 @@ call (virConnectPtr conn, struct private
xdrproc_t args_filter, char *args,
xdrproc_t ret_filter, char *ret)
{
- char buffer[REMOTE_MESSAGE_MAX];
+ char *buffer = NULL;
char buffer2[4];
struct remote_message_header hdr;
XDR xdr;
+ int err = -1;
int len;
struct remote_error rerror;
@@ -4814,18 +4815,23 @@ call (virConnectPtr conn, struct private
hdr.serial = serial;
hdr.status = REMOTE_OK;
+ if ((buffer = malloc(REMOTE_MESSAGE_MAX)) == NULL) {
+ error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ goto out;
+ }
+
/* Serialise header followed by args. */
- xdrmem_create (&xdr, buffer, sizeof buffer, XDR_ENCODE);
+ xdrmem_create (&xdr, buffer, REMOTE_MESSAGE_MAX, XDR_ENCODE);
if (!xdr_remote_message_header (&xdr, &hdr)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("xdr_remote_message_header failed"));
- return -1;
+ goto out;
}
if (!(*args_filter) (&xdr, args)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC,
_("marshalling args"));
- return -1;
+ goto out;
}
/* Get the length stored in buffer. */
@@ -4842,25 +4848,25 @@ call (virConnectPtr conn, struct private
if (!xdr_int (&xdr, &len)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC,
_("xdr_int (length word)"));
- return -1;
+ goto out;
}
xdr_destroy (&xdr);
/* Send length word followed by header+args. */
if (really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof
buffer2) == -1 ||
really_write (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len-4) == -1)
- return -1;
+ goto out;
retry_read:
/* Read and deserialise length word. */
if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer2, sizeof
buffer2) == -1)
- return -1;
+ goto out;
xdrmem_create (&xdr, buffer2, sizeof buffer2, XDR_DECODE);
if (!xdr_int (&xdr, &len)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("xdr_int (length word, reply)"));
- return -1;
+ goto out;
}
xdr_destroy (&xdr);
@@ -4870,20 +4876,25 @@ retry_read:
if (len < 0 || len > REMOTE_MESSAGE_MAX) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("packet received from server too large"));
- return -1;
}
/* Read reply header and what follows (either a ret or an error). */
if (really_read (conn, priv, flags & REMOTE_CALL_IN_OPEN, buffer, len) == -1)
- return -1;
+ goto out;
/* Deserialise reply header. */
xdrmem_create (&xdr, buffer, len, XDR_DECODE);
if (!xdr_remote_message_header (&xdr, &hdr)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("invalid header in reply"));
- return -1;
- }
+ goto out;
+ }
+
+ /*
+ * Although the previous lines were the last references to buffer in this
+ * function, we can't free it yet, as the xdr struct still has some
+ * pointers to it.
+ */
/* Check program, version, etc. are what we expect. */
if (hdr.prog != REMOTE_PROGRAM) {
@@ -4892,7 +4903,7 @@ retry_read:
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown program (received %x, expected %x)"),
hdr.prog, REMOTE_PROGRAM);
- return -1;
+ goto out;
}
if (hdr.vers != REMOTE_PROTOCOL_VERSION) {
virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
@@ -4900,7 +4911,7 @@ retry_read:
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown protocol version (received %x, expected
%x)"),
hdr.vers, REMOTE_PROTOCOL_VERSION);
- return -1;
+ goto out;
}
if (hdr.proc == REMOTE_PROC_DOMAIN_EVENT &&
@@ -4923,7 +4934,7 @@ retry_read:
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown procedure (received %x, expected %x)"),
hdr.proc, proc_nr);
- return -1;
+ goto out;
}
if (hdr.direction != REMOTE_REPLY) {
virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
@@ -4931,14 +4942,14 @@ retry_read:
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown direction (received %x, expected %x)"),
hdr.direction, REMOTE_REPLY);
- return -1;
+ goto out;
}
if (hdr.serial != serial) {
virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL,
VIR_FROM_REMOTE,
VIR_ERR_RPC, VIR_ERR_ERROR, NULL, NULL, NULL, 0, 0,
_("unknown serial (received %x, expected %x)"),
hdr.serial, serial);
- return -1;
+ goto out;
}
/* Status is either REMOTE_OK (meaning that what follows is a ret
@@ -4950,17 +4961,18 @@ retry_read:
if (!(*ret_filter) (&xdr, ret)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, VIR_ERR_RPC,
_("unmarshalling ret"));
- return -1;
+ goto out;
}
xdr_destroy (&xdr);
- return 0;
+ err = 0;
+ goto out;
case REMOTE_ERROR:
memset (&rerror, 0, sizeof rerror);
if (!xdr_remote_error (&xdr, &rerror)) {
error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
VIR_ERR_RPC, _("unmarshalling remote_error"));
- return -1;
+ goto out;
}
xdr_destroy (&xdr);
/* See if caller asked us to keep quiet about missing RPCs
@@ -4970,11 +4982,12 @@ retry_read:
rerror.code == VIR_ERR_RPC &&
rerror.level == VIR_ERR_ERROR &&
STRPREFIX(*rerror.message, "unknown procedure")) {
- return -2;
+ err = -2;
+ goto out;
}
server_error (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, &rerror);
xdr_free ((xdrproc_t) xdr_remote_error, (char *) &rerror);
- return -1;
+ goto out;
default:
virRaiseError (flags & REMOTE_CALL_IN_OPEN ? NULL : conn, NULL, NULL,
VIR_FROM_REMOTE,
@@ -4982,8 +4995,12 @@ retry_read:
_("unknown status (received %x)"),
hdr.status);
xdr_destroy (&xdr);
- return -1;
- }
+ goto out;
+ }
+
+out:
+ VIR_FREE (buffer);
+ return err;
}
static int
@@ -5551,7 +5568,7 @@ remoteDomainEventFired(int watch,
int event,
void *opaque)
{
- char buffer[REMOTE_MESSAGE_MAX];
+ char *buffer = NULL;
char buffer2[4];
struct remote_message_header hdr;
XDR xdr;
@@ -5566,22 +5583,22 @@ remoteDomainEventFired(int watch,
DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or "
"VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__);
virEventRemoveHandle(watch);
- return;
+ goto out;
}
if (fd != priv->sock) {
virEventRemoveHandle(watch);
- return;
+ goto out;
}
/* Read and deserialise length word. */
if (really_read (conn, priv, 0, buffer2, sizeof buffer2) == -1)
- return;
+ goto out;
xdrmem_create (&xdr, buffer2, sizeof buffer2, XDR_DECODE);
if (!xdr_int (&xdr, &len)) {
error (conn, VIR_ERR_RPC, _("xdr_int (length word, reply)"));
- return;
+ goto out;
}
xdr_destroy (&xdr);
@@ -5590,20 +5607,25 @@ remoteDomainEventFired(int watch,
if (len < 0 || len > REMOTE_MESSAGE_MAX) {
error (conn, VIR_ERR_RPC, _("packet received from server too large"));
- return;
+ goto out;
+ }
+
+ if ((buffer = malloc(REMOTE_MESSAGE_MAX)) == NULL) {
+ error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
+ goto out;
}
/* Read reply header and what follows (either a ret or an error). */
if (really_read (conn, priv, 0, buffer, len) == -1) {
error (conn, VIR_ERR_RPC, _("error reading buffer from memory"));
- return;
+ goto out;
}
/* Deserialise reply header. */
xdrmem_create (&xdr, buffer, len, XDR_DECODE);
if (!xdr_remote_message_header (&xdr, &hdr)) {
error (conn, VIR_ERR_RPC, _("invalid header in event firing"));
- return;
+ goto out;
}
if (hdr.proc == REMOTE_PROC_DOMAIN_EVENT &&
@@ -5614,6 +5636,9 @@ remoteDomainEventFired(int watch,
DEBUG0("invalid proc in event firing");
error (conn, VIR_ERR_RPC, _("invalid proc in event firing"));
}
+
+out:
+ VIR_FREE (buffer);
}
void