Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/backend/commands/statscmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ compare_int16(const void *a, const void *b)
* CREATE STATISTICS
*/
ObjectAddress
CreateStatistics(CreateStatsStmt *stmt)
CreateStatistics(CreateStatsStmt *stmt, bool check_rights)
{
int16 attnums[STATS_MAX_DIMENSIONS];
int nattnums = 0;
Expand Down Expand Up @@ -176,6 +176,21 @@ CreateStatistics(CreateStatsStmt *stmt)
}
namestrcpy(&stxname, namestr);

/*
* Check we have creation rights in target namespace. Skip check if
* caller doesn't want it.
*/
if (check_rights)
{
AclResult aclresult;

aclresult = object_aclcheck(NamespaceRelationId, namespaceId,
GetUserId(), ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, OBJECT_SCHEMA,
get_namespace_name(namespaceId));
}

/*
* Deal with the possibility that the statistics object already exists.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/backend/commands/tablecmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -11038,7 +11038,7 @@ ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
Assert(stmt->transformed);

HOLD_DISPATCH();
address = CreateStatistics(stmt);
address = CreateStatistics(stmt, !is_rebuild);
RESUME_DISPATCH();

return address;
Expand Down
2 changes: 1 addition & 1 deletion src/backend/tcop/utility.c
Original file line number Diff line number Diff line change
Expand Up @@ -2538,7 +2538,7 @@ ProcessUtilitySlow(ParseState *pstate,
/* Run parse analysis ... */
stmt = transformStatsStmt(relid, stmt, queryString);

address = CreateStatistics(stmt);
address = CreateStatistics(stmt, true);
}
break;

Expand Down
2 changes: 1 addition & 1 deletion src/include/commands/defrem.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ extern void RemoveOperatorById(Oid operOid);
extern ObjectAddress AlterOperator(AlterOperatorStmt *stmt);

/* commands/statscmds.c */
extern ObjectAddress CreateStatistics(CreateStatsStmt *stmt);
extern ObjectAddress CreateStatistics(CreateStatsStmt *stmt, bool check_rights);
extern ObjectAddress AlterStatistics(AlterStatsStmt *stmt);
extern void RemoveStatisticsById(Oid statsOid);
extern void RemoveStatisticsDataById(Oid statsOid, bool inh);
Expand Down
17 changes: 16 additions & 1 deletion src/interfaces/libpq/fe-connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <limits.h>
#include <netdb.h>
#include <time.h>
#include <unistd.h>
Expand Down Expand Up @@ -1075,7 +1076,7 @@ parse_comma_separated_list(char **startptr, bool *more)
char *p;
char *s = *startptr;
char *e;
int len;
size_t len;

/*
* Search for the end of the current element; a comma or end-of-string
Expand Down Expand Up @@ -5594,7 +5595,21 @@ ldapServiceLookup(const char *purl, PQconninfoOption *options,
/* concatenate values into a single string with newline terminators */
size = 1; /* for the trailing null */
for (i = 0; values[i] != NULL; i++)
{
if (values[i]->bv_len >= INT_MAX ||
size > (INT_MAX - (values[i]->bv_len + 1)))
{
libpq_append_error(errorMessage,
"connection info string size exceeds the maximum allowed (%d)",
INT_MAX);
ldap_value_free_len(values);
ldap_unbind(ld);
return 3;
}

size += values[i]->bv_len + 1;
}

if ((result = malloc(size)) == NULL)
{
libpq_append_error(errorMessage, "out of memory");
Expand Down
103 changes: 87 additions & 16 deletions src/interfaces/libpq/fe-exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,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;
Expand Down Expand Up @@ -624,8 +624,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;
Expand Down Expand Up @@ -1292,7 +1297,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)
goto fail;

Expand Down Expand Up @@ -4166,6 +4171,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
Expand All @@ -4178,9 +4204,9 @@ 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 input_len = strlen(str);
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 ? '"' : '\'';
bool validated_mb = false;
Expand Down Expand Up @@ -4245,10 +4271,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)
{
Expand Down Expand Up @@ -4321,6 +4358,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 *
Expand Down Expand Up @@ -4386,30 +4429,51 @@ 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
{
vp = from;
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;
}
}
}

Expand Down Expand Up @@ -4470,6 +4534,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 *
Expand Down
61 changes: 56 additions & 5 deletions src/interfaces/libpq/fe-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,16 @@ PQprint(FILE *fout, const PGresult *res, const PQprintOpt *po)
} screen_size;
#endif

/*
* Quick sanity check on po->fieldSep, since we make heavy use of int
* math throughout.
*/
if (fs_len < strlen(po->fieldSep))
{
fprintf(stderr, libpq_gettext("overlong field separator\n"));
goto exit;
}

nTups = PQntuples(res);
fieldNames = (const char **) calloc(nFields, sizeof(char *));
fieldNotNum = (unsigned char *) calloc(nFields, 1);
Expand Down Expand Up @@ -402,7 +412,7 @@ do_field(const PQprintOpt *po, const PGresult *res,
{
if (plen > fieldMax[j])
fieldMax[j] = plen;
if (!(fields[i * nFields + j] = (char *) malloc(plen + 1)))
if (!(fields[i * nFields + j] = (char *) malloc((size_t) plen + 1)))
{
fprintf(stderr, libpq_gettext("out of memory\n"));
return false;
Expand Down Expand Up @@ -452,6 +462,27 @@ do_field(const PQprintOpt *po, const PGresult *res,
}


/*
* 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;
}


static char *
do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
const char **fieldNames, unsigned char *fieldNotNum,
Expand All @@ -464,15 +495,31 @@ do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
fputs("<tr>", fout);
else
{
int tot = 0;
size_t tot = 0;
int n = 0;
char *p = NULL;

/* Calculate the border size, checking for overflow. */
for (; n < nFields; n++)
tot += fieldMax[n] + fs_len + (po->standard ? 2 : 0);
{
/* Field plus separator, plus 2 extra '-' in standard format. */
if (add_size_overflow(tot, fieldMax[n], &tot) ||
add_size_overflow(tot, fs_len, &tot) ||
(po->standard && add_size_overflow(tot, 2, &tot)))
goto overflow;
}
if (po->standard)
tot += fs_len * 2 + 2;
border = malloc(tot + 1);
{
/* An extra separator at the front and back. */
if (add_size_overflow(tot, fs_len, &tot) ||
add_size_overflow(tot, fs_len, &tot) ||
add_size_overflow(tot, 2, &tot))
goto overflow;
}
if (add_size_overflow(tot, 1, &tot)) /* terminator */
goto overflow;

border = malloc(tot);
if (!border)
{
fprintf(stderr, libpq_gettext("out of memory\n"));
Expand Down Expand Up @@ -535,6 +582,10 @@ do_header(FILE *fout, const PQprintOpt *po, const int nFields, int *fieldMax,
else
fprintf(fout, "\n%s\n", border);
return border;

overflow:
fprintf(stderr, libpq_gettext("header size exceeds the maximum allowed\n"));
return NULL;
}


Expand Down
Loading
Loading