summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane2008-05-29 22:02:44 +0000
committerTom Lane2008-05-29 22:02:44 +0000
commitf90959b9c3f8e84b6c2db591b1bceda7fe43023e (patch)
tree5e302d5d9a3dd20a0c6eab32fe8a8b4fdc7617c8
parent05614bd8bd222ea55e04851c566154af83e0738a (diff)
Tweak libpq to avoid crashing due to incorrect buffer size calculation when
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.
-rw-r--r--src/interfaces/libpq/fe-connect.c3
-rw-r--r--src/interfaces/libpq/fe-exec.c3
-rw-r--r--src/interfaces/libpq/fe-misc.c26
-rw-r--r--src/interfaces/libpq/fe-protocol3.c9
-rw-r--r--src/interfaces/libpq/libpq-int.h4
5 files changed, 25 insertions, 20 deletions
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 55f9b2ffc7..307b8053e8 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -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;
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index c3bc843d02..97bfcf990f 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -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) */
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 0ca46cdb11..dcb227a7ac 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -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
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 152f05694b..c07a827a1a 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -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
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 38c06d4bb7..4af13880a7 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -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);