/*
* Try to validate message length before using it.
+ *
* Authentication requests can't be very large, although GSS
* auth requests may not be that small. Same for
- * NegotiateProtocolVersion. Errors can be a
- * little larger, but not huge. If we see a large apparent
- * length in an error, it means we're really talking to a
- * pre-3.0-protocol server; cope. (Before version 14, the
- * server also used the old protocol for errors that happened
- * before processing the startup packet.)
+ * NegotiateProtocolVersion.
+ *
+ * Errors can be a little larger, but not huge. If we see a
+ * large apparent length in an error, it means we're really
+ * talking to a pre-3.0-protocol server; cope. (Before
+ * version 14, the server also used the old protocol for
+ * errors that happened before processing the startup packet.)
*/
- if ((beresp == 'R' || beresp == 'v') && (msgLength < 8 || msgLength > 2000))
+ if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
{
- libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
- beresp);
+ libpq_append_conn_error(conn, "received invalid authentication request");
+ goto error_return;
+ }
+ if (beresp == 'v' && (msgLength < 8 || msgLength > 2000))
+ {
+ libpq_append_conn_error(conn, "received invalid protocol negotiation message");
goto error_return;
}
- if (beresp == 'E' && (msgLength < 8 || msgLength > 30000))
+#define MAX_ERRLEN 30000
+ if (beresp == 'E' && (msgLength < 8 || msgLength > MAX_ERRLEN))
{
/* Handle error from a pre-3.0 server */
conn->inCursor = conn->inStart + 1; /* reread data */
if (pqGets_append(&conn->errorMessage, conn))
{
+ /*
+ * We may not have authenticated the server yet, so
+ * don't let the buffer grow forever.
+ */
+ avail = conn->inEnd - conn->inCursor;
+ if (avail > MAX_ERRLEN)
+ {
+ libpq_append_conn_error(conn, "received invalid error message");
+ goto error_return;
+ }
+
/* We'll come back when there is more data */
return PGRES_POLLING_READING;
}
goto error_return;
}
+#undef MAX_ERRLEN
/*
* Can't process if message body isn't all here yet.
+ *
+ * After this check passes, any further EOF during parsing
+ * implies that the server sent a bad/truncated message.
+ * Reading more bytes won't help in that case, so don't return
+ * PGRES_POLLING_READING after this point.
*/
msgLength -= 4;
avail = conn->inEnd - conn->inCursor;
{
if (pqGetErrorNotice3(conn, true))
{
- /* We'll come back when there is more data */
- return PGRES_POLLING_READING;
+ libpq_append_conn_error(conn, "received invalid error message");
+ goto error_return;
}
/* OK, we read the message; mark data consumed */
conn->inStart = conn->inCursor;
{
if (pqGetNegotiateProtocolVersion3(conn))
{
+ libpq_append_conn_error(conn, "received invalid protocol negotiation message");
goto error_return;
}
/* OK, we read the message; mark data consumed */
/* Get the type of request. */
if (pqGetInt((int *) &areq, 4, conn))
{
+ /* can't happen because we checked the length already */
+ libpq_append_conn_error(conn, "received invalid authentication request");
goto error_return;
}
msgLength -= 4;