Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uIuht-00DW5X-OB for pgsql-bugs@arkaria.postgresql.org; Sat, 24 May 2025 19:38:58 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1uIuhs-00DKZg-Su for pgsql-bugs@arkaria.postgresql.org; Sat, 24 May 2025 19:38:56 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uIuhs-00DKYy-Hz for pgsql-bugs@lists.postgresql.org; Sat, 24 May 2025 19:38:56 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1uIuhp-000n9m-0w for pgsql-bugs@lists.postgresql.org; Sat, 24 May 2025 19:38:55 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.15.2/8.15.2) with ESMTP id 54OJcmWI3125965; Sat, 24 May 2025 15:38:48 -0400 From: Tom Lane To: Chris Gooch cc: Jacob Champion , "pgsql-bugs@lists.postgresql.org" Subject: Re: [EXT] Re: GSS Auth issue when user member of lots of AD groups In-reply-to: <3125813.1748115425@sss.pgh.pa.us> References: <1529314.1747928806@sss.pgh.pa.us> <1536692.1747933034@sss.pgh.pa.us> <1647590.1747936713@sss.pgh.pa.us> <3060113.1748096813@sss.pgh.pa.us> <3125813.1748115425@sss.pgh.pa.us> Comments: In-reply-to Tom Lane message dated "Sat, 24 May 2025 15:37:05 -0400" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <3125953.1748115521.0@sss.pgh.pa.us> Date: Sat, 24 May 2025 15:38:48 -0400 Message-ID: <3125964.1748115528@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <3125953.1748115521.1@sss.pgh.pa.us> I wrote: > OK, here's a set of draft patches for that. Sigh, it'd help if I actually attached the patches ... regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="gssapi-fix-HEAD.patch"; charset="us-ascii" Content-ID: <3125953.1748115521.2@sss.pgh.pa.us> Content-Description: gssapi-fix-HEAD.patch Content-Transfer-Encoding: quoted-printable diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-s= ecure-gssapi.c index 717ba9824f9..910c7f22711 100644 --- a/src/backend/libpq/be-secure-gssapi.c +++ b/src/backend/libpq/be-secure-gssapi.c @@ -46,11 +46,19 @@ * don't want the other side to send arbitrarily huge packets as we * would have to allocate memory for them to then pass them to GSSAPI. * - * Therefore, these two #define's are effectively part of the protocol + * Therefore, this #define is effectively part of the protocol * spec and can't ever be changed. */ -#define PQ_GSS_SEND_BUFFER_SIZE 16384 -#define PQ_GSS_RECV_BUFFER_SIZE 16384 +#define PQ_GSS_MAX_PACKET_SIZE 16384 + +/* + * However, during the authentication exchange we must cope with whatever + * message size the GSSAPI library wants to send (because our protocol + * doesn't support splitting those messages). Depending on configuration + * those messages might be as much as 64kB. To provide some safety margi= n + * we use 128kB buffers during transport negotiation. + */ +#define PQ_GSS_AUTH_BUFFER_SIZE 131072 = /* * Since we manage at most one GSS-encrypted connection per backend, @@ -210,12 +218,12 @@ be_gssapi_write(Port *port, const void *ptr, size_t = len) errno =3D ECONNRESET; return -1; } - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)", (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)))); errno =3D ECONNRESET; return -1; } @@ -346,12 +354,12 @@ be_gssapi_read(Port *port, void *ptr, size_t len) /* Decode the packet length and check for overlength packet */ input.length =3D pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); = - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)))); errno =3D ECONNRESET; return -1; } @@ -517,10 +525,13 @@ secure_open_gssapi(Port *port) * that will never use them, and we ensure that the buffers are * sufficiently aligned for the length-word accesses that we do in some * places in this file. + * + * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport + * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE. */ - PqGSSSendBuffer =3D malloc(PQ_GSS_SEND_BUFFER_SIZE); - PqGSSRecvBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); - PqGSSResultBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); + PqGSSSendBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) ereport(FATAL, (errcode(ERRCODE_OUT_OF_MEMORY), @@ -568,16 +579,16 @@ secure_open_gssapi(Port *port) = /* * During initialization, packets are always fully consumed and - * shouldn't ever be over PQ_GSS_RECV_BUFFER_SIZE in length. + * shouldn't ever be over PQ_GSS_AUTH_BUFFER_SIZE in total length. * * Verify on our side that the client doesn't do something funny. */ - if (input.length > PQ_GSS_RECV_BUFFER_SIZE) + if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { ereport(COMMERROR, - (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)", + (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE))); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)))); return -1; } = @@ -631,12 +642,12 @@ secure_open_gssapi(Port *port) { uint32 netlen =3D pg_hton32(output.length); = - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)", (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)))); gss_release_buffer(&minor, &output); return -1; } @@ -691,12 +702,29 @@ secure_open_gssapi(Port *port) break; } = + /* + * Release the large authentication buffers and allocate the ones we wan= t + * for normal operation. + */ + free(PqGSSSendBuffer); + free(PqGSSRecvBuffer); + free(PqGSSResultBuffer); + PqGSSSendBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) + ereport(FATAL, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + PqGSSSendLength =3D PqGSSSendNext =3D PqGSSSendConsumed =3D 0; + PqGSSRecvLength =3D PqGSSResultLength =3D PqGSSResultNext =3D 0; + /* * Determine the max packet size which will fit in our buffer, after * accounting for the length. be_gssapi_write will need this. */ major =3D gss_wrap_size_limit(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAU= LT, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32), + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32), &PqGSSMaxPktSize); = if (GSS_ERROR(major)) diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libp= q/fe-secure-gssapi.c index ce183bc04b4..9bdf0192f1e 100644 --- a/src/interfaces/libpq/fe-secure-gssapi.c +++ b/src/interfaces/libpq/fe-secure-gssapi.c @@ -47,11 +47,19 @@ * don't want the other side to send arbitrarily huge packets as we * would have to allocate memory for them to then pass them to GSSAPI. * - * Therefore, these two #define's are effectively part of the protocol + * Therefore, this #define is effectively part of the protocol * spec and can't ever be changed. */ -#define PQ_GSS_SEND_BUFFER_SIZE 16384 -#define PQ_GSS_RECV_BUFFER_SIZE 16384 +#define PQ_GSS_MAX_PACKET_SIZE 16384 + +/* + * However, during the authentication exchange we must cope with whatever + * message size the GSSAPI library wants to send (because our protocol + * doesn't support splitting those messages). Depending on configuration + * those messages might be as much as 64kB. To provide some safety margi= n + * we use 128kB buffers during transport negotiation. + */ +#define PQ_GSS_AUTH_BUFFER_SIZE 131072 = /* * We need these state variables per-connection. To allow the functions @@ -203,11 +211,11 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t l= en) goto cleanup; } = - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { libpq_append_conn_error(conn, "client tried to send oversize GSSAPI pa= cket (%zu > %zu)", (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)); errno =3D EIO; /* for lack of a better idea */ goto cleanup; } @@ -342,11 +350,11 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) /* Decode the packet length and check for overlength packet */ input.length =3D pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); = - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { libpq_append_conn_error(conn, "oversize GSSAPI packet sent by the serv= er (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)); errno =3D EIO; /* for lack of a better idea */ return -1; } @@ -485,12 +493,15 @@ pqsecure_open_gss(PGconn *conn) * initialize state variables. By malloc'ing the buffers separately, we * ensure that they are sufficiently aligned for the length-word accesse= s * that we do in some places in this file. + * + * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport + * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE. */ if (PqGSSSendBuffer =3D=3D NULL) { - PqGSSSendBuffer =3D malloc(PQ_GSS_SEND_BUFFER_SIZE); - PqGSSRecvBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); - PqGSSResultBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); + PqGSSSendBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) { libpq_append_conn_error(conn, "out of memory"); @@ -564,13 +575,13 @@ pqsecure_open_gss(PGconn *conn) * so leave a spot at the end for a NULL byte too) and report that * back to the caller. */ - result =3D gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_RE= CV_BUFFER_SIZE - PqGSSRecvLength - 1, &ret); + result =3D gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_AU= TH_BUFFER_SIZE - PqGSSRecvLength - 1, &ret); if (result !=3D PGRES_POLLING_OK) return result; = PqGSSRecvLength +=3D ret; = - Assert(PqGSSRecvLength < PQ_GSS_RECV_BUFFER_SIZE); + Assert(PqGSSRecvLength < PQ_GSS_AUTH_BUFFER_SIZE); PqGSSRecvBuffer[PqGSSRecvLength] =3D '\0'; appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); = @@ -584,11 +595,11 @@ pqsecure_open_gss(PGconn *conn) = /* Get the length and check for over-length packet */ input.length =3D pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { libpq_append_conn_error(conn, "oversize GSSAPI packet sent by the serv= er (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)); return PGRES_POLLING_FAILED; } = @@ -668,12 +679,33 @@ pqsecure_open_gss(PGconn *conn) conn->gcred =3D GSS_C_NO_CREDENTIAL; gss_release_buffer(&minor, &output); = + /* + * Release the large authentication buffers and allocate the ones we + * want for normal operation. (This maneuver is safe only because + * pqDropConnection will drop the buffers; otherwise, during a + * reconnection we'd be at risk of using undersized buffers during + * negotiation.) + */ + free(PqGSSSendBuffer); + free(PqGSSRecvBuffer); + free(PqGSSResultBuffer); + PqGSSSendBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) + { + libpq_append_conn_error(conn, "out of memory"); + return PGRES_POLLING_FAILED; + } + PqGSSSendLength =3D PqGSSSendNext =3D PqGSSSendConsumed =3D 0; + PqGSSRecvLength =3D PqGSSResultLength =3D PqGSSResultNext =3D 0; + /* * Determine the max packet size which will fit in our buffer, after * accounting for the length. pg_GSS_write will need this. */ major =3D gss_wrap_size_limit(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32), + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32), &PqGSSMaxPktSize); = if (GSS_ERROR(major)) @@ -687,10 +719,11 @@ pqsecure_open_gss(PGconn *conn) } = /* Must have output.length > 0 */ - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { - pg_GSS_error(libpq_gettext("GSSAPI context establishment error"), - conn, major, minor); + libpq_append_conn_error(conn, "client tried to send oversize GSSAPI pac= ket (%zu > %zu)", + (size_t) output.length, + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)); gss_release_buffer(&minor, &output); return PGRES_POLLING_FAILED; } ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="gssapi-fix-v15.patch"; charset="us-ascii" Content-ID: <3125953.1748115521.3@sss.pgh.pa.us> Content-Description: gssapi-fix-v15.patch Content-Transfer-Encoding: quoted-printable diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-s= ecure-gssapi.c index d3337a3d1c4..4aa828bef08 100644 --- a/src/backend/libpq/be-secure-gssapi.c +++ b/src/backend/libpq/be-secure-gssapi.c @@ -45,11 +45,19 @@ * don't want the other side to send arbitrarily huge packets as we * would have to allocate memory for them to then pass them to GSSAPI. * - * Therefore, these two #define's are effectively part of the protocol + * Therefore, this #define is effectively part of the protocol * spec and can't ever be changed. */ -#define PQ_GSS_SEND_BUFFER_SIZE 16384 -#define PQ_GSS_RECV_BUFFER_SIZE 16384 +#define PQ_GSS_MAX_PACKET_SIZE 16384 + +/* + * However, during the authentication exchange we must cope with whatever + * message size the GSSAPI library wants to send (because our protocol + * doesn't support splitting those messages). Depending on configuration + * those messages might be as much as 64kB. To provide some safety margi= n + * we use 128kB buffers during transport negotiation. + */ +#define PQ_GSS_AUTH_BUFFER_SIZE 131072 = /* * Since we manage at most one GSS-encrypted connection per backend, @@ -209,12 +217,12 @@ be_gssapi_write(Port *port, void *ptr, size_t len) errno =3D ECONNRESET; return -1; } - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)", (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)))); errno =3D ECONNRESET; return -1; } @@ -345,12 +353,12 @@ be_gssapi_read(Port *port, void *ptr, size_t len) /* Decode the packet length and check for overlength packet */ input.length =3D pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); = - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)))); errno =3D ECONNRESET; return -1; } @@ -510,10 +518,13 @@ secure_open_gssapi(Port *port) * that will never use them, and we ensure that the buffers are * sufficiently aligned for the length-word accesses that we do in some * places in this file. + * + * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport + * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE. */ - PqGSSSendBuffer =3D malloc(PQ_GSS_SEND_BUFFER_SIZE); - PqGSSRecvBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); - PqGSSResultBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); + PqGSSSendBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) ereport(FATAL, (errcode(ERRCODE_OUT_OF_MEMORY), @@ -560,16 +571,16 @@ secure_open_gssapi(Port *port) = /* * During initialization, packets are always fully consumed and - * shouldn't ever be over PQ_GSS_RECV_BUFFER_SIZE in length. + * shouldn't ever be over PQ_GSS_AUTH_BUFFER_SIZE in total length. * * Verify on our side that the client doesn't do something funny. */ - if (input.length > PQ_GSS_RECV_BUFFER_SIZE) + if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { ereport(COMMERROR, - (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)", + (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE))); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)))); return -1; } = @@ -616,12 +627,12 @@ secure_open_gssapi(Port *port) { uint32 netlen =3D pg_hton32(output.length); = - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)", (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)))); gss_release_buffer(&minor, &output); return -1; } @@ -676,12 +687,29 @@ secure_open_gssapi(Port *port) break; } = + /* + * Release the large authentication buffers and allocate the ones we wan= t + * for normal operation. + */ + free(PqGSSSendBuffer); + free(PqGSSRecvBuffer); + free(PqGSSResultBuffer); + PqGSSSendBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) + ereport(FATAL, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + PqGSSSendLength =3D PqGSSSendNext =3D PqGSSSendConsumed =3D 0; + PqGSSRecvLength =3D PqGSSResultLength =3D PqGSSResultNext =3D 0; + /* * Determine the max packet size which will fit in our buffer, after * accounting for the length. be_gssapi_write will need this. */ major =3D gss_wrap_size_limit(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAU= LT, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32), + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32), &PqGSSMaxPktSize); = if (GSS_ERROR(major)) diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libp= q/fe-secure-gssapi.c index a3768cd70a3..eb23731645f 100644 --- a/src/interfaces/libpq/fe-secure-gssapi.c +++ b/src/interfaces/libpq/fe-secure-gssapi.c @@ -47,11 +47,19 @@ * don't want the other side to send arbitrarily huge packets as we * would have to allocate memory for them to then pass them to GSSAPI. * - * Therefore, these two #define's are effectively part of the protocol + * Therefore, this #define is effectively part of the protocol * spec and can't ever be changed. */ -#define PQ_GSS_SEND_BUFFER_SIZE 16384 -#define PQ_GSS_RECV_BUFFER_SIZE 16384 +#define PQ_GSS_MAX_PACKET_SIZE 16384 + +/* + * However, during the authentication exchange we must cope with whatever + * message size the GSSAPI library wants to send (because our protocol + * doesn't support splitting those messages). Depending on configuration + * those messages might be as much as 64kB. To provide some safety margi= n + * we use 128kB buffers during transport negotiation. + */ +#define PQ_GSS_AUTH_BUFFER_SIZE 131072 = /* * We need these state variables per-connection. To allow the functions @@ -204,12 +212,12 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t l= en) goto cleanup; } = - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("client tried to send oversize GSSAPI packet (%zu = > %zu)\n"), (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)); errno =3D EIO; /* for lack of a better idea */ goto cleanup; } @@ -344,12 +352,12 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) /* Decode the packet length and check for overlength packet */ input.length =3D pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); = - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("oversize GSSAPI packet sent by the server (%zu > = %zu)\n"), (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)); errno =3D EIO; /* for lack of a better idea */ return -1; } @@ -488,12 +496,15 @@ pqsecure_open_gss(PGconn *conn) * initialize state variables. By malloc'ing the buffers separately, we * ensure that they are sufficiently aligned for the length-word accesse= s * that we do in some places in this file. + * + * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport + * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE. */ if (PqGSSSendBuffer =3D=3D NULL) { - PqGSSSendBuffer =3D malloc(PQ_GSS_SEND_BUFFER_SIZE); - PqGSSRecvBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); - PqGSSResultBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); + PqGSSSendBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) { appendPQExpBufferStr(&conn->errorMessage, @@ -568,13 +579,13 @@ pqsecure_open_gss(PGconn *conn) * so leave a spot at the end for a NULL byte too) and report that * back to the caller. */ - result =3D gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_RE= CV_BUFFER_SIZE - PqGSSRecvLength - 1, &ret); + result =3D gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_AU= TH_BUFFER_SIZE - PqGSSRecvLength - 1, &ret); if (result !=3D PGRES_POLLING_OK) return result; = PqGSSRecvLength +=3D ret; = - Assert(PqGSSRecvLength < PQ_GSS_RECV_BUFFER_SIZE); + Assert(PqGSSRecvLength < PQ_GSS_AUTH_BUFFER_SIZE); PqGSSRecvBuffer[PqGSSRecvLength] =3D '\0'; appendPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); = @@ -588,12 +599,12 @@ pqsecure_open_gss(PGconn *conn) = /* Get the length and check for over-length packet */ input.length =3D pg_ntoh32(*(uint32 *) PqGSSRecvBuffer); - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { appendPQExpBuffer(&conn->errorMessage, libpq_gettext("oversize GSSAPI packet sent by the server (%zu > = %zu)\n"), (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)); return PGRES_POLLING_FAILED; } = @@ -655,12 +666,34 @@ pqsecure_open_gss(PGconn *conn) conn->gcred =3D GSS_C_NO_CREDENTIAL; gss_release_buffer(&minor, &output); = + /* + * Release the large authentication buffers and allocate the ones we + * want for normal operation. (This maneuver is safe only because + * pqDropConnection will drop the buffers; otherwise, during a + * reconnection we'd be at risk of using undersized buffers during + * negotiation.) + */ + free(PqGSSSendBuffer); + free(PqGSSRecvBuffer); + free(PqGSSResultBuffer); + PqGSSSendBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) + { + appendPQExpBufferStr(&conn->errorMessage, + libpq_gettext("out of memory\n")); + return PGRES_POLLING_FAILED; + } + PqGSSSendLength =3D PqGSSSendNext =3D PqGSSSendConsumed =3D 0; + PqGSSRecvLength =3D PqGSSResultLength =3D PqGSSResultNext =3D 0; + /* * Determine the max packet size which will fit in our buffer, after * accounting for the length. pg_GSS_write will need this. */ major =3D gss_wrap_size_limit(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32), + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32), &PqGSSMaxPktSize); = if (GSS_ERROR(major)) @@ -674,10 +707,12 @@ pqsecure_open_gss(PGconn *conn) } = /* Must have output.length > 0 */ - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { - pg_GSS_error(libpq_gettext("GSSAPI context establishment error"), - conn, major, minor); + appendPQExpBuffer(&conn->errorMessage, + libpq_gettext("client tried to send oversize GSSAPI packet (%zu >= %zu)\n"), + (size_t) output.length, + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)); gss_release_buffer(&minor, &output); return PGRES_POLLING_FAILED; } ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name="gssapi-fix-v13.patch"; charset="us-ascii" Content-ID: <3125953.1748115521.4@sss.pgh.pa.us> Content-Description: gssapi-fix-v13.patch Content-Transfer-Encoding: quoted-printable diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-s= ecure-gssapi.c index 0fc7d565e2a..4992ff5bd20 100644 --- a/src/backend/libpq/be-secure-gssapi.c +++ b/src/backend/libpq/be-secure-gssapi.c @@ -45,11 +45,19 @@ * don't want the other side to send arbitrarily huge packets as we * would have to allocate memory for them to then pass them to GSSAPI. * - * Therefore, these two #define's are effectively part of the protocol + * Therefore, this #define is effectively part of the protocol * spec and can't ever be changed. */ -#define PQ_GSS_SEND_BUFFER_SIZE 16384 -#define PQ_GSS_RECV_BUFFER_SIZE 16384 +#define PQ_GSS_MAX_PACKET_SIZE 16384 + +/* + * However, during the authentication exchange we must cope with whatever + * message size the GSSAPI library wants to send (because our protocol + * doesn't support splitting those messages). Depending on configuration + * those messages might be as much as 64kB. To provide some safety margi= n + * we use 128kB buffers during transport negotiation. + */ +#define PQ_GSS_AUTH_BUFFER_SIZE 131072 = /* * Since we manage at most one GSS-encrypted connection per backend, @@ -209,12 +217,12 @@ be_gssapi_write(Port *port, void *ptr, size_t len) errno =3D ECONNRESET; return -1; } - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)", (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)))); errno =3D ECONNRESET; return -1; } @@ -345,12 +353,12 @@ be_gssapi_read(Port *port, void *ptr, size_t len) /* Decode the packet length and check for overlength packet */ input.length =3D ntohl(*(uint32 *) PqGSSRecvBuffer); = - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)))); errno =3D ECONNRESET; return -1; } @@ -510,10 +518,13 @@ secure_open_gssapi(Port *port) * that will never use them, and we ensure that the buffers are * sufficiently aligned for the length-word accesses that we do in some * places in this file. + * + * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport + * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE. */ - PqGSSSendBuffer =3D malloc(PQ_GSS_SEND_BUFFER_SIZE); - PqGSSRecvBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); - PqGSSResultBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); + PqGSSSendBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) ereport(FATAL, (errcode(ERRCODE_OUT_OF_MEMORY), @@ -560,16 +571,16 @@ secure_open_gssapi(Port *port) = /* * During initialization, packets are always fully consumed and - * shouldn't ever be over PQ_GSS_RECV_BUFFER_SIZE in length. + * shouldn't ever be over PQ_GSS_AUTH_BUFFER_SIZE in total length. * * Verify on our side that the client doesn't do something funny. */ - if (input.length > PQ_GSS_RECV_BUFFER_SIZE) + if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { ereport(COMMERROR, - (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)", + (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)", (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE))); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)))); return -1; } = @@ -616,12 +627,12 @@ secure_open_gssapi(Port *port) { uint32 netlen =3D htonl(output.length); = - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { ereport(COMMERROR, (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)", (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)))); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)))); gss_release_buffer(&minor, &output); return -1; } @@ -676,12 +687,29 @@ secure_open_gssapi(Port *port) break; } = + /* + * Release the large authentication buffers and allocate the ones we wan= t + * for normal operation. + */ + free(PqGSSSendBuffer); + free(PqGSSRecvBuffer); + free(PqGSSResultBuffer); + PqGSSSendBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) + ereport(FATAL, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + PqGSSSendLength =3D PqGSSSendNext =3D PqGSSSendConsumed =3D 0; + PqGSSRecvLength =3D PqGSSResultLength =3D PqGSSResultNext =3D 0; + /* * Determine the max packet size which will fit in our buffer, after * accounting for the length. be_gssapi_write will need this. */ major =3D gss_wrap_size_limit(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAU= LT, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32), + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32), &PqGSSMaxPktSize); = if (GSS_ERROR(major)) diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libp= q/fe-secure-gssapi.c index ac2a8c8563f..abc07fe5f04 100644 --- a/src/interfaces/libpq/fe-secure-gssapi.c +++ b/src/interfaces/libpq/fe-secure-gssapi.c @@ -47,11 +47,19 @@ * don't want the other side to send arbitrarily huge packets as we * would have to allocate memory for them to then pass them to GSSAPI. * - * Therefore, these two #define's are effectively part of the protocol + * Therefore, this #define is effectively part of the protocol * spec and can't ever be changed. */ -#define PQ_GSS_SEND_BUFFER_SIZE 16384 -#define PQ_GSS_RECV_BUFFER_SIZE 16384 +#define PQ_GSS_MAX_PACKET_SIZE 16384 + +/* + * However, during the authentication exchange we must cope with whatever + * message size the GSSAPI library wants to send (because our protocol + * doesn't support splitting those messages). Depending on configuration + * those messages might be as much as 64kB. To provide some safety margi= n + * we use 128kB buffers during transport negotiation. + */ +#define PQ_GSS_AUTH_BUFFER_SIZE 131072 = /* * We need these state variables per-connection. To allow the functions @@ -204,12 +212,12 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t l= en) goto cleanup; } = - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("client tried to send oversize GSSAPI packet (%zu = > %zu)\n"), (size_t) output.length, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)); errno =3D EIO; /* for lack of a better idea */ goto cleanup; } @@ -344,12 +352,12 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len) /* Decode the packet length and check for overlength packet */ input.length =3D ntohl(*(uint32 *) PqGSSRecvBuffer); = - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("oversize GSSAPI packet sent by the server (%zu > = %zu)\n"), (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32)); errno =3D EIO; /* for lack of a better idea */ return -1; } @@ -488,12 +496,15 @@ pqsecure_open_gss(PGconn *conn) * initialize state variables. By malloc'ing the buffers separately, we * ensure that they are sufficiently aligned for the length-word accesse= s * that we do in some places in this file. + * + * We'll use PQ_GSS_AUTH_BUFFER_SIZE-sized buffers until transport + * negotiation is complete, then switch to PQ_GSS_MAX_PACKET_SIZE. */ if (PqGSSSendBuffer =3D=3D NULL) { - PqGSSSendBuffer =3D malloc(PQ_GSS_SEND_BUFFER_SIZE); - PqGSSRecvBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); - PqGSSResultBuffer =3D malloc(PQ_GSS_RECV_BUFFER_SIZE); + PqGSSSendBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_AUTH_BUFFER_SIZE); if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) { printfPQExpBuffer(&conn->errorMessage, @@ -568,13 +579,13 @@ pqsecure_open_gss(PGconn *conn) * so leave a spot at the end for a NULL byte too) and report that * back to the caller. */ - result =3D gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_RE= CV_BUFFER_SIZE - PqGSSRecvLength - 1, &ret); + result =3D gss_read(conn, PqGSSRecvBuffer + PqGSSRecvLength, PQ_GSS_AU= TH_BUFFER_SIZE - PqGSSRecvLength - 1, &ret); if (result !=3D PGRES_POLLING_OK) return result; = PqGSSRecvLength +=3D ret; = - Assert(PqGSSRecvLength < PQ_GSS_RECV_BUFFER_SIZE); + Assert(PqGSSRecvLength < PQ_GSS_AUTH_BUFFER_SIZE); PqGSSRecvBuffer[PqGSSRecvLength] =3D '\0'; printfPQExpBuffer(&conn->errorMessage, "%s\n", PqGSSRecvBuffer + 1); = @@ -588,12 +599,12 @@ pqsecure_open_gss(PGconn *conn) = /* Get the length and check for over-length packet */ input.length =3D ntohl(*(uint32 *) PqGSSRecvBuffer); - if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)) + if (input.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("oversize GSSAPI packet sent by the server (%zu > = %zu)\n"), (size_t) input.length, - PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32)); + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)); return PGRES_POLLING_FAILED; } = @@ -655,12 +666,34 @@ pqsecure_open_gss(PGconn *conn) conn->gcred =3D GSS_C_NO_CREDENTIAL; gss_release_buffer(&minor, &output); = + /* + * Release the large authentication buffers and allocate the ones we + * want for normal operation. (This maneuver is safe only because + * pqDropConnection will drop the buffers; otherwise, during a + * reconnection we'd be at risk of using undersized buffers during + * negotiation.) + */ + free(PqGSSSendBuffer); + free(PqGSSRecvBuffer); + free(PqGSSResultBuffer); + PqGSSSendBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSRecvBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + PqGSSResultBuffer =3D malloc(PQ_GSS_MAX_PACKET_SIZE); + if (!PqGSSSendBuffer || !PqGSSRecvBuffer || !PqGSSResultBuffer) + { + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("out of memory\n")); + return PGRES_POLLING_FAILED; + } + PqGSSSendLength =3D PqGSSSendNext =3D PqGSSSendConsumed =3D 0; + PqGSSRecvLength =3D PqGSSResultLength =3D PqGSSResultNext =3D 0; + /* * Determine the max packet size which will fit in our buffer, after * accounting for the length. pg_GSS_write will need this. */ major =3D gss_wrap_size_limit(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT, - PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32), + PQ_GSS_MAX_PACKET_SIZE - sizeof(uint32), &PqGSSMaxPktSize); = if (GSS_ERROR(major)) @@ -674,10 +707,12 @@ pqsecure_open_gss(PGconn *conn) } = /* Must have output.length > 0 */ - if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32)) + if (output.length > PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)) { - pg_GSS_error(libpq_gettext("GSSAPI context establishment error"), - conn, major, minor); + printfPQExpBuffer(&conn->errorMessage, + libpq_gettext("client tried to send oversize GSSAPI packet (%zu >= %zu)\n"), + (size_t) output.length, + PQ_GSS_AUTH_BUFFER_SIZE - sizeof(uint32)); gss_release_buffer(&minor, &output); return PGRES_POLLING_FAILED; } ------- =_aaaaaaaaaa0--