From b0294d170ed8e6302590940144165134202694d6 Mon Sep 17 00:00:00 2001 From: buter Date: Tue, 7 Jun 2022 15:20:00 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DSSL=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E4=B8=AD=E9=97=B4=E4=BA=BA=E6=94=BB?= =?UTF-8?q?=E5=87=BB=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/backend/libpq/pqcomm.cpp | 11 +++++++++++ src/common/interfaces/libpq/fe-connect.cpp | 12 ++++++++++++ src/gausskernel/process/postmaster/postmaster.cpp | 12 ++++++++++++ src/include/libpq/libpq.h | 1 + 4 files changed, 36 insertions(+) diff --git a/src/common/backend/libpq/pqcomm.cpp b/src/common/backend/libpq/pqcomm.cpp index 8e54da4df..fd8929e7b 100644 --- a/src/common/backend/libpq/pqcomm.cpp +++ b/src/common/backend/libpq/pqcomm.cpp @@ -1366,6 +1366,17 @@ static int pq_discardbytes(size_t len) return 0; } +/* -------------------------------- + * pq_buffer_has_data - is any buffered data available to read? + * + * This will *not* attempt to read more data. + * -------------------------------- + */ +bool pq_buffer_has_data(void) +{ + return (t_thrd.libpq_cxt.PqRecvPointer < t_thrd.libpq_cxt.PqRecvLength); +} + /* -------------------------------- * pq_getstring - get a null terminated string from connection * diff --git a/src/common/interfaces/libpq/fe-connect.cpp b/src/common/interfaces/libpq/fe-connect.cpp index 76d1bce74..356c758c3 100644 --- a/src/common/interfaces/libpq/fe-connect.cpp +++ b/src/common/interfaces/libpq/fe-connect.cpp @@ -2610,6 +2610,18 @@ keep_going: /* We will come back to here until there is */ pollres = pqsecure_open_client(conn); if (pollres == PGRES_POLLING_OK) { + /* + * At this point we should have no data already buffered. + * If we do, it was received before we performed the SSL + * handshake, so it wasn't encrypted and indeed may have + * been injected by a man-in-the-middle. + */ + if (conn->inCursor != conn->inEnd) { + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("received unencrypted data after SSL response\n")); + goto error_return; + } + /* SSL handshake done, ready to send startup packet */ conn->status = CONNECTION_MADE; return PGRES_POLLING_WRITING; diff --git a/src/gausskernel/process/postmaster/postmaster.cpp b/src/gausskernel/process/postmaster/postmaster.cpp index 8412eb67d..30c441d41 100644 --- a/src/gausskernel/process/postmaster/postmaster.cpp +++ b/src/gausskernel/process/postmaster/postmaster.cpp @@ -3590,6 +3590,18 @@ int ProcessStartupPacket(Port* port, bool SSLdone) } #endif + /* + * At this point we should have no data already buffered. If we do, + * it was received before we performed the SSL handshake, so it wasn't + * encrypted and indeed may have been injected by a man-in-the-middle. + * We report this case to the client. + */ + if (pq_buffer_has_data()) { + ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("received unencrypted data after SSL request"), + errdetail("This could be either a client-software bug or " + "evidence of an attempted man-in-the-middle attack."))); + } + /* regular startup packet, cancel, etc packet should follow... */ /* but not another SSL negotiation request */ return ProcessStartupPacket(port, true); diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h index f2f429efa..3d364cf18 100644 --- a/src/include/libpq/libpq.h +++ b/src/include/libpq/libpq.h @@ -56,6 +56,7 @@ extern int pq_getmessage(StringInfo s, int maxlen); extern int pq_getbyte(void); extern int pq_peekbyte(void); extern int pq_getbyte_if_available(unsigned char* c); +extern bool pq_buffer_has_data(void); extern int pq_putbytes(const char* s, size_t len); extern int pq_flush(void); extern int pq_flush_if_writable(void);