Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5e04447

Browse filesBrowse files
committed
Check for unbounded authentication exchanges in libpq.
A couple of code paths in CONNECTION_AWAITING_RESPONSE will eagerly read bytes off a connection that should be closed. Don't let a misbehaving server chew up client resources here; a v2 error can't be infinitely long, and a v3 error should be bounded by its original message length. For the existing error_return cases, I added some additional error messages for symmetry with the new ones, and cleaned up some message rot. Author: Jacob Champion Discussion: https://www.postgresql.org/message-id/8e729daf-7d71-6965-9687-8bc0630599b3%40timescale.com
1 parent a75ff55 commit 5e04447
Copy full SHA for 5e04447

File tree

1 file changed

+39
-12
lines changed
Filter options

1 file changed

+39
-12
lines changed

‎src/interfaces/libpq/fe-connect.c

Copy file name to clipboardExpand all lines: src/interfaces/libpq/fe-connect.c
+39-12Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3214,28 +3214,46 @@ PQconnectPoll(PGconn *conn)
32143214

32153215
/*
32163216
* Try to validate message length before using it.
3217+
*
32173218
* Authentication requests can't be very large, although GSS
32183219
* auth requests may not be that small. Same for
3219-
* NegotiateProtocolVersion. Errors can be a
3220-
* little larger, but not huge. If we see a large apparent
3221-
* length in an error, it means we're really talking to a
3222-
* pre-3.0-protocol server; cope. (Before version 14, the
3223-
* server also used the old protocol for errors that happened
3224-
* before processing the startup packet.)
3220+
* NegotiateProtocolVersion.
3221+
*
3222+
* Errors can be a little larger, but not huge. If we see a
3223+
* large apparent length in an error, it means we're really
3224+
* talking to a pre-3.0-protocol server; cope. (Before
3225+
* version 14, the server also used the old protocol for
3226+
* errors that happened before processing the startup packet.)
32253227
*/
3226-
if ((beresp == 'R' || beresp == 'v') && (msgLength < 8 || msgLength > 2000))
3228+
if (beresp == 'R' && (msgLength < 8 || msgLength > 2000))
32273229
{
3228-
libpq_append_conn_error(conn, "expected authentication request from server, but received %c",
3229-
beresp);
3230+
libpq_append_conn_error(conn, "received invalid authentication request");
3231+
goto error_return;
3232+
}
3233+
if (beresp == 'v' && (msgLength < 8 || msgLength > 2000))
3234+
{
3235+
libpq_append_conn_error(conn, "received invalid protocol negotiation message");
32303236
goto error_return;
32313237
}
32323238

3233-
if (beresp == 'E' && (msgLength < 8 || msgLength > 30000))
3239+
#define MAX_ERRLEN 30000
3240+
if (beresp == 'E' && (msgLength < 8 || msgLength > MAX_ERRLEN))
32343241
{
32353242
/* Handle error from a pre-3.0 server */
32363243
conn->inCursor = conn->inStart + 1; /* reread data */
32373244
if (pqGets_append(&conn->errorMessage, conn))
32383245
{
3246+
/*
3247+
* We may not have authenticated the server yet, so
3248+
* don't let the buffer grow forever.
3249+
*/
3250+
avail = conn->inEnd - conn->inCursor;
3251+
if (avail > MAX_ERRLEN)
3252+
{
3253+
libpq_append_conn_error(conn, "received invalid error message");
3254+
goto error_return;
3255+
}
3256+
32393257
/* We'll come back when there is more data */
32403258
return PGRES_POLLING_READING;
32413259
}
@@ -3255,9 +3273,15 @@ PQconnectPoll(PGconn *conn)
32553273

32563274
goto error_return;
32573275
}
3276+
#undef MAX_ERRLEN
32583277

32593278
/*
32603279
* Can't process if message body isn't all here yet.
3280+
*
3281+
* After this check passes, any further EOF during parsing
3282+
* implies that the server sent a bad/truncated message.
3283+
* Reading more bytes won't help in that case, so don't return
3284+
* PGRES_POLLING_READING after this point.
32613285
*/
32623286
msgLength -= 4;
32633287
avail = conn->inEnd - conn->inCursor;
@@ -3280,8 +3304,8 @@ PQconnectPoll(PGconn *conn)
32803304
{
32813305
if (pqGetErrorNotice3(conn, true))
32823306
{
3283-
/* We'll come back when there is more data */
3284-
return PGRES_POLLING_READING;
3307+
libpq_append_conn_error(conn, "received invalid error message");
3308+
goto error_return;
32853309
}
32863310
/* OK, we read the message; mark data consumed */
32873311
conn->inStart = conn->inCursor;
@@ -3357,6 +3381,7 @@ PQconnectPoll(PGconn *conn)
33573381
{
33583382
if (pqGetNegotiateProtocolVersion3(conn))
33593383
{
3384+
libpq_append_conn_error(conn, "received invalid protocol negotiation message");
33603385
goto error_return;
33613386
}
33623387
/* OK, we read the message; mark data consumed */
@@ -3370,6 +3395,8 @@ PQconnectPoll(PGconn *conn)
33703395
/* Get the type of request. */
33713396
if (pqGetInt((int *) &areq, 4, conn))
33723397
{
3398+
/* can't happen because we checked the length already */
3399+
libpq_append_conn_error(conn, "received invalid authentication request");
33733400
goto error_return;
33743401
}
33753402
msgLength -= 4;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.