Fix severe memory leaks in GSSAPI encryption support.
authorTom Lane
Tue, 5 May 2020 17:10:09 +0000 (13:10 -0400)
committerTom Lane
Tue, 5 May 2020 17:10:09 +0000 (13:10 -0400)
Both the backend and libpq leaked buffers containing encrypted data
to be transmitted, so that the process size would grow roughly as
the total amount of data sent.

There were also far-less-critical leaks of the same sort in GSSAPI
session establishment.

Oversight in commit b0b39f72b, which I failed to notice while
reviewing the code in 2c0cdc818.

Per complaint from pmc@citylink.
Back-patch to v12 where this code was introduced.

Discussion: https://postgr.es/m/20200504115649[email protected]

src/backend/libpq/be-secure-gssapi.c
src/interfaces/libpq/fe-secure-gssapi.c

index d248d113fcc21440e4690489f3944117787975b7..d565f92a21019c72ee1e0c406ecd2e73d6653d7b 100644 (file)
@@ -215,6 +215,9 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
 
        memcpy(PqGSSSendBuffer + PqGSSSendLength, output.value, output.length);
        PqGSSSendLength += output.length;
+
+       /* Release buffer storage allocated by GSSAPI */
+       gss_release_buffer(&minor, &output);
    }
 
    /* If we get here, our counters should all match up. */
@@ -371,6 +374,7 @@ be_gssapi_read(Port *port, void *ptr, size_t len)
        /* Our receive buffer is now empty, reset it */
        PqGSSRecvLength = 0;
 
+       /* Release buffer storage allocated by GSSAPI */
        gss_release_buffer(&minor, &output);
    }
 
@@ -590,7 +594,10 @@ secure_open_gssapi(Port *port)
                 */
                if (ret < 0 &&
                    !(errno == EWOULDBLOCK || errno == EAGAIN || errno == EINTR))
+               {
+                   gss_release_buffer(&minor, &output);
                    return -1;
+               }
 
                /* Wait and retry if we couldn't write yet */
                if (ret <= 0)
index 2ba24df68d61e7112488340fa3e9f81e0ca2e558..e8d687c6889c8ad16e0bc688688f23ca2bf7031b 100644 (file)
@@ -232,6 +232,9 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
 
        memcpy(PqGSSSendBuffer + PqGSSSendLength, output.value, output.length);
        PqGSSSendLength += output.length;
+
+       /* Release buffer storage allocated by GSSAPI */
+       gss_release_buffer(&minor, &output);
    }
 
    /* If we get here, our counters should all match up. */
@@ -241,6 +244,7 @@ pg_GSS_write(PGconn *conn, const void *ptr, size_t len)
    ret = bytes_sent;
 
 cleanup:
+   /* Release GSSAPI buffer storage, if we didn't already */
    if (output.value != NULL)
        gss_release_buffer(&minor, &output);
    return ret;
@@ -408,12 +412,14 @@ pg_GSS_read(PGconn *conn, void *ptr, size_t len)
        /* Our receive buffer is now empty, reset it */
        PqGSSRecvLength = 0;
 
+       /* Release buffer storage allocated by GSSAPI */
        gss_release_buffer(&minor, &output);
    }
 
    ret = bytes_returned;
 
 cleanup:
+   /* Release GSSAPI buffer storage, if we didn't already */
    if (output.value != NULL)
        gss_release_buffer(&minor, &output);
    return ret;
@@ -652,6 +658,7 @@ pqsecure_open_gss(PGconn *conn)
        gss_release_cred(&minor, &conn->gcred);
        conn->gcred = GSS_C_NO_CREDENTIAL;
        conn->gssenc = true;
+       gss_release_buffer(&minor, &output);
 
        /*
         * Determine the max packet size which will fit in our buffer, after
@@ -676,6 +683,7 @@ pqsecure_open_gss(PGconn *conn)
    {
        pg_GSS_error(libpq_gettext("GSSAPI context establishment error"),
                     conn, major, minor);
+       gss_release_buffer(&minor, &output);
        return PGRES_POLLING_FAILED;
    }
 
@@ -690,6 +698,7 @@ pqsecure_open_gss(PGconn *conn)
 
    /* We don't bother with PqGSSSendConsumed here */
 
+   /* Release buffer storage allocated by GSSAPI */
    gss_release_buffer(&minor, &output);
 
    /* Ask to be called again to write data */