Tweak libpq to avoid crashing due to incorrect buffer size calculation when
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 29 May 2008 22:02:44 +0000 (22:02 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 29 May 2008 22:02:44 +0000 (22:02 +0000)
we are on a 64-bit machine (ie, size_t is wider than int) and someone passes
in a query string that approaches or exceeds INT_MAX bytes.  Also, just for
paranoia's sake, guard against similar overflows in sizing the input buffer.

The backend will not in the foreseeable future be prepared to send or receive
strings exceeding 1GB, so I didn't take the more invasive step of switching
all the buffer index variables from int to size_t; though someday we might
want to do that.

I have a suspicion that this is not the only such bug in libpq, but this
fix is enough to take care of the crash reported by Francisco Reyes.

src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-misc.c
src/interfaces/libpq/fe-protocol3.c
src/interfaces/libpq/libpq-int.h

index 55f9b2ffc708db44c1ef325fe4c8c1311e5c8776..307b8053e8b76990a91f3e3113ead94418d01c25 100644 (file)
@@ -1581,7 +1581,8 @@ keep_going:                                               /* We will come back to here until there is
                                         * needed to hold the whole message; see notes in
                                         * pqParseInput3.
                                         */
-                                       if (pqCheckInBufferSpace(conn->inCursor + msgLength, conn))
+                                       if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
+                                                                                        conn))
                                                goto error_return;
                                        /* We'll come back when there is more data */
                                        return PGRES_POLLING_READING;
index c3bc843d02deb5860b297f93fbe416a82f38ad18..97bfcf990f1b4cf2a340d992e7060c0b8961a3ed 100644 (file)
@@ -1685,7 +1685,8 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
                {
                        if (pqFlush(conn) < 0)
                                return -1;
-                       if (pqCheckOutBufferSpace(conn->outCount + 5 + nbytes, conn))
+                       if (pqCheckOutBufferSpace(conn->outCount + 5 + (size_t) nbytes,
+                                                                         conn))
                                return pqIsnonblocking(conn) ? 0 : -1;
                }
                /* Send the data (too simple to delegate to fe-protocol files) */
index 0ca46cdb11cd059f49b040e23a1f6aa95734a70a..dcb227a7ace75d214d543116c01ddb7089155e5a 100644 (file)
@@ -278,12 +278,12 @@ pqPutInt(int value, size_t bytes, PGconn *conn)
  * Returns 0 on success, EOF if failed to enlarge buffer
  */
 int
-pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
+pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn)
 {
        int                     newsize = conn->outBufSize;
        char       *newbuf;
 
-       if (bytes_needed <= newsize)
+       if (bytes_needed <= (size_t) newsize)
                return 0;
 
        /*
@@ -296,9 +296,9 @@ pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
        do
        {
                newsize *= 2;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->outBuffer, newsize);
                if (newbuf)
@@ -314,9 +314,9 @@ pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
        do
        {
                newsize += 8192;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->outBuffer, newsize);
                if (newbuf)
@@ -341,12 +341,12 @@ pqCheckOutBufferSpace(int bytes_needed, PGconn *conn)
  * Returns 0 on success, EOF if failed to enlarge buffer
  */
 int
-pqCheckInBufferSpace(int bytes_needed, PGconn *conn)
+pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn)
 {
        int                     newsize = conn->inBufSize;
        char       *newbuf;
 
-       if (bytes_needed <= newsize)
+       if (bytes_needed <= (size_t) newsize)
                return 0;
 
        /*
@@ -359,9 +359,9 @@ pqCheckInBufferSpace(int bytes_needed, PGconn *conn)
        do
        {
                newsize *= 2;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->inBuffer, newsize);
                if (newbuf)
@@ -377,9 +377,9 @@ pqCheckInBufferSpace(int bytes_needed, PGconn *conn)
        do
        {
                newsize += 8192;
-       } while (bytes_needed > newsize && newsize > 0);
+       } while (newsize > 0 && bytes_needed > (size_t) newsize);
 
-       if (bytes_needed <= newsize)
+       if (newsize > 0 && bytes_needed <= (size_t) newsize)
        {
                newbuf = realloc(conn->inBuffer, newsize);
                if (newbuf)
@@ -572,7 +572,7 @@ pqReadData(PGconn *conn)
         */
        if (conn->inBufSize - conn->inEnd < 8192)
        {
-               if (pqCheckInBufferSpace(conn->inEnd + 8192, conn))
+               if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn))
                {
                        /*
                         * We don't insist that the enlarge worked, but we need some room
index 152f05694b0b00944bdba51616fe1c282406a516..c07a827a1a2af854661108a5bc2070ad9cce80de 100644 (file)
@@ -115,7 +115,8 @@ pqParseInput3(PGconn *conn)
                         * recovery strategy if we are unable to make the buffer big
                         * enough.
                         */
-                       if (pqCheckInBufferSpace(conn->inCursor + msgLength, conn))
+                       if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
+                                                                        conn))
                        {
                                /*
                                 * XXX add some better recovery code... plan is to skip over
@@ -1310,7 +1311,8 @@ getCopyDataMessage(PGconn *conn)
                         * Before returning, enlarge the input buffer if needed to hold
                         * the whole message.  See notes in parseInput.
                         */
-                       if (pqCheckInBufferSpace(conn->inCursor + msgLength - 4, conn))
+                       if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength - 4,
+                                                                        conn))
                        {
                                /*
                                 * XXX add some better recovery code... plan is to skip over
@@ -1745,7 +1747,8 @@ pqFunctionCall3(PGconn *conn, Oid fnid,
                         * Before looping, enlarge the input buffer if needed to hold the
                         * whole message.  See notes in parseInput.
                         */
-                       if (pqCheckInBufferSpace(conn->inCursor + msgLength, conn))
+                       if (pqCheckInBufferSpace(conn->inCursor + (size_t) msgLength,
+                                                                        conn))
                        {
                                /*
                                 * XXX add some better recovery code... plan is to skip over
index 38c06d4bb7f37bd4f0f87213e4b5d63752d828f7..4af13880a77d144de71d198c549ceb6d124849b3 100644 (file)
@@ -511,8 +511,8 @@ extern PGresult *pqFunctionCall3(PGconn *conn, Oid fnid,
   * Get, EOF merely means the buffer is exhausted, not that there is
   * necessarily any error.
   */
-extern int     pqCheckOutBufferSpace(int bytes_needed, PGconn *conn);
-extern int     pqCheckInBufferSpace(int bytes_needed, PGconn *conn);
+extern int     pqCheckOutBufferSpace(size_t bytes_needed, PGconn *conn);
+extern int     pqCheckInBufferSpace(size_t bytes_needed, PGconn *conn);
 extern int     pqGetc(char *result, PGconn *conn);
 extern int     pqPutc(char c, PGconn *conn);
 extern int     pqGets(PQExpBuffer buf, PGconn *conn);