summaryrefslogtreecommitdiff
path: root/src/interfaces/libpq/fe-exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/libpq/fe-exec.c')
-rw-r--r--src/interfaces/libpq/fe-exec.c101
1 files changed, 86 insertions, 15 deletions
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 0b1e37ec30b..dcc8a447d66 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -511,7 +511,7 @@ PQsetvalue(PGresult *res, int tup_num, int field_num, char *value, int len)
}
else
{
- attval->value = (char *) pqResultAlloc(res, len + 1, true);
+ attval->value = (char *) pqResultAlloc(res, (size_t) len + 1, true);
if (!attval->value)
goto fail;
attval->len = len;
@@ -603,8 +603,13 @@ pqResultAlloc(PGresult *res, size_t nBytes, bool isBinary)
*/
if (nBytes >= PGRESULT_SEP_ALLOC_THRESHOLD)
{
- size_t alloc_size = nBytes + PGRESULT_BLOCK_OVERHEAD;
+ size_t alloc_size;
+ /* Don't wrap around with overly large requests. */
+ if (nBytes > SIZE_MAX - PGRESULT_BLOCK_OVERHEAD)
+ return NULL;
+
+ alloc_size = nBytes + PGRESULT_BLOCK_OVERHEAD;
block = (PGresult_data *) malloc(alloc_size);
if (!block)
return NULL;
@@ -1274,7 +1279,7 @@ pqRowProcessor(PGconn *conn, const char **errmsgp)
bool isbinary = (res->attDescs[i].format != 0);
char *val;
- val = (char *) pqResultAlloc(res, clen + 1, isbinary);
+ val = (char *) pqResultAlloc(res, (size_t) clen + 1, isbinary);
if (val == NULL)
return 0;
@@ -4216,6 +4221,27 @@ PQescapeString(char *to, const char *from, size_t length)
/*
+ * Frontend version of the backend's add_size(), intended to be API-compatible
+ * with the pg_add_*_overflow() helpers. Stores the result into *dst on success.
+ * Returns true instead if the addition overflows.
+ *
+ * TODO: move to common/int.h
+ */
+static bool
+add_size_overflow(size_t s1, size_t s2, size_t *dst)
+{
+ size_t result;
+
+ result = s1 + s2;
+ if (result < s1 || result < s2)
+ return true;
+
+ *dst = result;
+ return false;
+}
+
+
+/*
* Escape arbitrary strings. If as_ident is true, we escape the result
* as an identifier; if false, as a literal. The result is returned in
* a newly allocated buffer. If we fail due to an encoding violation or out
@@ -4227,8 +4253,8 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
const char *s;
char *result;
char *rp;
- int num_quotes = 0; /* single or double, depending on as_ident */
- int num_backslashes = 0;
+ size_t num_quotes = 0; /* single or double, depending on as_ident */
+ size_t num_backslashes = 0;
size_t input_len = strnlen(str, len);
size_t result_size;
char quote_char = as_ident ? '"' : '\'';
@@ -4294,10 +4320,21 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
}
}
- /* Allocate output buffer. */
- result_size = input_len + num_quotes + 3; /* two quotes, plus a NUL */
+ /*
+ * Allocate output buffer. Protect against overflow, in case the caller
+ * has allocated a large fraction of the available size_t.
+ */
+ if (add_size_overflow(input_len, num_quotes, &result_size) ||
+ add_size_overflow(result_size, 3, &result_size)) /* two quotes plus a NUL */
+ goto overflow;
+
if (!as_ident && num_backslashes > 0)
- result_size += num_backslashes + 2;
+ {
+ if (add_size_overflow(result_size, num_backslashes, &result_size) ||
+ add_size_overflow(result_size, 2, &result_size)) /* for " E" prefix */
+ goto overflow;
+ }
+
result = rp = (char *) malloc(result_size);
if (rp == NULL)
{
@@ -4370,6 +4407,12 @@ PQescapeInternal(PGconn *conn, const char *str, size_t len, bool as_ident)
*rp = '\0';
return result;
+
+overflow:
+ libpq_append_conn_error(conn,
+ "escaped string size exceeds the maximum allowed (%zu)",
+ SIZE_MAX);
+ return NULL;
}
char *
@@ -4435,16 +4478,25 @@ PQescapeByteaInternal(PGconn *conn,
unsigned char *result;
size_t i;
size_t len;
- size_t bslash_len = (std_strings ? 1 : 2);
+ const size_t bslash_len = (std_strings ? 1 : 2);
/*
- * empty string has 1 char ('\0')
+ * Calculate the escaped length, watching for overflow as we do with
+ * PQescapeInternal(). The following code relies on a small constant
+ * bslash_len so that small additions and multiplications don't need their
+ * own overflow checks.
+ *
+ * Start with the empty string, which has 1 char ('\0').
*/
len = 1;
if (use_hex)
{
- len += bslash_len + 1 + 2 * from_length;
+ /* We prepend "\x" and double each input character. */
+ if (add_size_overflow(len, bslash_len + 1, &len) ||
+ add_size_overflow(len, from_length, &len) ||
+ add_size_overflow(len, from_length, &len))
+ goto overflow;
}
else
{
@@ -4452,13 +4504,25 @@ PQescapeByteaInternal(PGconn *conn,
for (i = from_length; i > 0; i--, vp++)
{
if (*vp < 0x20 || *vp > 0x7e)
- len += bslash_len + 3;
+ {
+ if (add_size_overflow(len, bslash_len + 3, &len)) /* octal "\ooo" */
+ goto overflow;
+ }
else if (*vp == '\'')
- len += 2;
+ {
+ if (add_size_overflow(len, 2, &len)) /* double each quote */
+ goto overflow;
+ }
else if (*vp == '\\')
- len += bslash_len + bslash_len;
+ {
+ if (add_size_overflow(len, bslash_len * 2, &len)) /* double each backslash */
+ goto overflow;
+ }
else
- len++;
+ {
+ if (add_size_overflow(len, 1, &len))
+ goto overflow;
+ }
}
}
@@ -4519,6 +4583,13 @@ PQescapeByteaInternal(PGconn *conn,
*rp = '\0';
return result;
+
+overflow:
+ if (conn)
+ libpq_append_conn_error(conn,
+ "escaped bytea size exceeds the maximum allowed (%zu)",
+ SIZE_MAX);
+ return NULL;
}
unsigned char *