Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 28e2412

Browse files
committed
Reject extraneous data after SSL or GSS encryption handshake.
The server collects up to a bufferload of data whenever it reads data from the client socket. When SSL or GSS encryption is requested during startup, any additional data received with the initial request message remained in the buffer, and would be treated as already-decrypted data once the encryption handshake completed. Thus, a man-in-the-middle with the ability to inject data into the TCP connection could stuff some cleartext data into the start of a supposedly encryption-protected database session. This could be abused to send faked SQL commands to the server, although that would only work if the server did not demand any authentication data. (However, a server relying on SSL certificate authentication might well not do so.) To fix, throw a protocol-violation error if the internal buffer is not empty after the encryption handshake. Our thanks to Jacob Champion for reporting this problem. Security: CVE-2021-23214
1 parent 39a3105 commit 28e2412

File tree

3 files changed

+37
-0
lines changed

3 files changed

+37
-0
lines changed

src/backend/libpq/pqcomm.c

+12
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,18 @@ pq_discardbytes(size_t len)
11411141
return 0;
11421142
}
11431143

1144+
/* --------------------------------
1145+
* pq_buffer_has_data - is any buffered data available to read?
1146+
*
1147+
* This will *not* attempt to read more data.
1148+
* --------------------------------
1149+
*/
1150+
bool
1151+
pq_buffer_has_data(void)
1152+
{
1153+
return (PqRecvPointer < PqRecvLength);
1154+
}
1155+
11441156

11451157
/* --------------------------------
11461158
* pq_startmsgread - begin reading a message from the client.

src/backend/postmaster/postmaster.c

+24
Original file line numberDiff line numberDiff line change
@@ -2110,6 +2110,18 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
21102110
return STATUS_ERROR;
21112111
#endif
21122112

2113+
/*
2114+
* At this point we should have no data already buffered. If we do,
2115+
* it was received before we performed the SSL handshake, so it wasn't
2116+
* encrypted and indeed may have been injected by a man-in-the-middle.
2117+
* We report this case to the client.
2118+
*/
2119+
if (pq_buffer_has_data())
2120+
ereport(FATAL,
2121+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
2122+
errmsg("received unencrypted data after SSL request"),
2123+
errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
2124+
21132125
/*
21142126
* regular startup packet, cancel, etc packet should follow, but not
21152127
* another SSL negotiation request, and a GSS request should only
@@ -2142,6 +2154,18 @@ ProcessStartupPacket(Port *port, bool ssl_done, bool gss_done)
21422154
return STATUS_ERROR;
21432155
#endif
21442156

2157+
/*
2158+
* At this point we should have no data already buffered. If we do,
2159+
* it was received before we performed the GSS handshake, so it wasn't
2160+
* encrypted and indeed may have been injected by a man-in-the-middle.
2161+
* We report this case to the client.
2162+
*/
2163+
if (pq_buffer_has_data())
2164+
ereport(FATAL,
2165+
(errcode(ERRCODE_PROTOCOL_VIOLATION),
2166+
errmsg("received unencrypted data after GSSAPI encryption request"),
2167+
errdetail("This could be either a client-software bug or evidence of an attempted man-in-the-middle attack.")));
2168+
21452169
/*
21462170
* regular startup packet, cancel, etc packet should follow, but not
21472171
* another GSS negotiation request, and an SSL request should only

src/include/libpq/libpq.h

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ extern int pq_getmessage(StringInfo s, int maxlen);
7979
extern int pq_getbyte(void);
8080
extern int pq_peekbyte(void);
8181
extern int pq_getbyte_if_available(unsigned char *c);
82+
extern bool pq_buffer_has_data(void);
8283
extern int pq_putmessage_v2(char msgtype, const char *s, size_t len);
8384
extern bool pq_check_connection(void);
8485

0 commit comments

Comments
 (0)