Commit 31400a67 authored by Noah Misch's avatar Noah Misch

Predict integer overflow to avoid buffer overruns.

Several functions, mostly type input functions, calculated an allocation
size such that the calculation wrapped to a small positive value when
arguments implied a sufficiently-large requirement.  Writes past the end
of the inadvertent small allocation followed shortly thereafter.
Coverity identified the path_in() vulnerability; code inspection led to
the rest.  In passing, add check_stack_depth() to prevent stack overflow
in related functions.

Back-patch to 8.4 (all supported versions).  The non-comment hstore
changes touch code that did not exist in 8.4, so that part stops at 9.0.

Noah Misch and Heikki Linnakangas, reviewed by Tom Lane.

Security: CVE-2014-0064
parent 4318daec
...@@ -49,9 +49,12 @@ typedef struct ...@@ -49,9 +49,12 @@ typedef struct
} HStore; } HStore;
/* /*
* it's not possible to get more than 2^28 items into an hstore, * It's not possible to get more than 2^28 items into an hstore, so we reserve
* so we reserve the top few bits of the size field. See hstore_compat.c * the top few bits of the size field. See hstore_compat.c for one reason
* for one reason why. Some bits are left for future use here. * why. Some bits are left for future use here. MaxAllocSize makes the
* practical count limit slightly more than 2^28 / 3, or INT_MAX / 24, the
* limit for an hstore full of 4-byte keys and null values. Therefore, we
* don't explicitly check the format-imposed limit.
*/ */
#define HS_FLAG_NEWVERSION 0x80000000 #define HS_FLAG_NEWVERSION 0x80000000
...@@ -59,6 +62,12 @@ typedef struct ...@@ -59,6 +62,12 @@ typedef struct
#define HS_SETCOUNT(hsp_,c_) ((hsp_)->size_ = (c_) | HS_FLAG_NEWVERSION) #define HS_SETCOUNT(hsp_,c_) ((hsp_)->size_ = (c_) | HS_FLAG_NEWVERSION)
/*
* "x" comes from an existing HS_COUNT() (as discussed, <= INT_MAX/24) or a
* Pairs array length (due to MaxAllocSize, <= INT_MAX/40). "lenstr" is no
* more than INT_MAX, that extreme case arising in hstore_from_arrays().
* Therefore, this calculation is limited to about INT_MAX / 5 + INT_MAX.
*/
#define HSHRDSIZE (sizeof(HStore)) #define HSHRDSIZE (sizeof(HStore))
#define CALCDATASIZE(x, lenstr) ( (x) * 2 * sizeof(HEntry) + HSHRDSIZE + (lenstr) ) #define CALCDATASIZE(x, lenstr) ( (x) * 2 * sizeof(HEntry) + HSHRDSIZE + (lenstr) )
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/json.h" #include "utils/json.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/typcache.h" #include "utils/typcache.h"
#include "hstore.h" #include "hstore.h"
...@@ -439,6 +440,11 @@ hstore_recv(PG_FUNCTION_ARGS) ...@@ -439,6 +440,11 @@ hstore_recv(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
if (pcount < 0 || pcount > MaxAllocSize / sizeof(Pairs))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
pcount, (int) (MaxAllocSize / sizeof(Pairs)))));
pairs = palloc(pcount * sizeof(Pairs)); pairs = palloc(pcount * sizeof(Pairs));
for (i = 0; i < pcount; ++i) for (i = 0; i < pcount; ++i)
...@@ -554,6 +560,13 @@ hstore_from_arrays(PG_FUNCTION_ARGS) ...@@ -554,6 +560,13 @@ hstore_from_arrays(PG_FUNCTION_ARGS)
TEXTOID, -1, false, 'i', TEXTOID, -1, false, 'i',
&key_datums, &key_nulls, &key_count); &key_datums, &key_nulls, &key_count);
/* see discussion in hstoreArrayToPairs() */
if (key_count > MaxAllocSize / sizeof(Pairs))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
key_count, (int) (MaxAllocSize / sizeof(Pairs)))));
/* value_array might be NULL */ /* value_array might be NULL */
if (PG_ARGISNULL(1)) if (PG_ARGISNULL(1))
...@@ -676,6 +689,13 @@ hstore_from_array(PG_FUNCTION_ARGS) ...@@ -676,6 +689,13 @@ hstore_from_array(PG_FUNCTION_ARGS)
count = in_count / 2; count = in_count / 2;
/* see discussion in hstoreArrayToPairs() */
if (count > MaxAllocSize / sizeof(Pairs))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
count, (int) (MaxAllocSize / sizeof(Pairs)))));
pairs = palloc(count * sizeof(Pairs)); pairs = palloc(count * sizeof(Pairs));
for (i = 0; i < count; ++i) for (i = 0; i < count; ++i)
...@@ -807,6 +827,7 @@ hstore_from_record(PG_FUNCTION_ARGS) ...@@ -807,6 +827,7 @@ hstore_from_record(PG_FUNCTION_ARGS)
my_extra->ncolumns = ncolumns; my_extra->ncolumns = ncolumns;
} }
Assert(ncolumns <= MaxTupleAttributeNumber); /* thus, no overflow */
pairs = palloc(ncolumns * sizeof(Pairs)); pairs = palloc(ncolumns * sizeof(Pairs));
if (rec) if (rec)
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "funcapi.h" #include "funcapi.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/memutils.h"
#include "hstore.h" #include "hstore.h"
...@@ -90,6 +91,19 @@ hstoreArrayToPairs(ArrayType *a, int *npairs) ...@@ -90,6 +91,19 @@ hstoreArrayToPairs(ArrayType *a, int *npairs)
return NULL; return NULL;
} }
/*
* A text array uses at least eight bytes per element, so any overflow in
* "key_count * sizeof(Pairs)" is small enough for palloc() to catch.
* However, credible improvements to the array format could invalidate
* that assumption. Therefore, use an explicit check rather than relying
* on palloc() to complain.
*/
if (key_count > MaxAllocSize / sizeof(Pairs))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of pairs (%d) exceeds the maximum allowed (%d)",
key_count, (int) (MaxAllocSize / sizeof(Pairs)))));
key_pairs = palloc(sizeof(Pairs) * key_count); key_pairs = palloc(sizeof(Pairs) * key_count);
for (i = 0, j = 0; i < key_count; i++) for (i = 0, j = 0; i < key_count; i++)
...@@ -648,6 +662,7 @@ hstore_slice_to_hstore(PG_FUNCTION_ARGS) ...@@ -648,6 +662,7 @@ hstore_slice_to_hstore(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
/* hstoreArrayToPairs() checked overflow */
out_pairs = palloc(sizeof(Pairs) * nkeys); out_pairs = palloc(sizeof(Pairs) * nkeys);
bufsiz = 0; bufsiz = 0;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#define ___INT_H__ #define ___INT_H__
#include "utils/array.h" #include "utils/array.h"
#include "utils/memutils.h"
/* number ranges for compression */ /* number ranges for compression */
#define MAXNUMRANGE 100 #define MAXNUMRANGE 100
...@@ -137,6 +138,7 @@ typedef struct QUERYTYPE ...@@ -137,6 +138,7 @@ typedef struct QUERYTYPE
#define HDRSIZEQT offsetof(QUERYTYPE, items) #define HDRSIZEQT offsetof(QUERYTYPE, items)
#define COMPUTESIZE(size) ( HDRSIZEQT + (size) * sizeof(ITEM) ) #define COMPUTESIZE(size) ( HDRSIZEQT + (size) * sizeof(ITEM) )
#define QUERYTYPEMAXITEMS ((MaxAllocSize - HDRSIZEQT) / sizeof(ITEM))
#define GETQUERY(x) ( (x)->items ) #define GETQUERY(x) ( (x)->items )
/* "type" codes for ITEM */ /* "type" codes for ITEM */
......
...@@ -448,6 +448,9 @@ boolop(PG_FUNCTION_ARGS) ...@@ -448,6 +448,9 @@ boolop(PG_FUNCTION_ARGS)
static void static void
findoprnd(ITEM *ptr, int32 *pos) findoprnd(ITEM *ptr, int32 *pos)
{ {
/* since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
#ifdef BS_DEBUG #ifdef BS_DEBUG
elog(DEBUG3, (ptr[*pos].type == OPR) ? elog(DEBUG3, (ptr[*pos].type == OPR) ?
"%d %c" : "%d %d", *pos, ptr[*pos].val); "%d %c" : "%d %d", *pos, ptr[*pos].val);
...@@ -508,7 +511,13 @@ bqarr_in(PG_FUNCTION_ARGS) ...@@ -508,7 +511,13 @@ bqarr_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("empty query"))); errmsg("empty query")));
if (state.num > QUERYTYPEMAXITEMS)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
state.num, (int) QUERYTYPEMAXITEMS)));
commonlen = COMPUTESIZE(state.num); commonlen = COMPUTESIZE(state.num);
query = (QUERYTYPE *) palloc(commonlen); query = (QUERYTYPE *) palloc(commonlen);
SET_VARSIZE(query, commonlen); SET_VARSIZE(query, commonlen);
query->size = state.num; query->size = state.num;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "fmgr.h" #include "fmgr.h"
#include "tsearch/ts_locale.h" #include "tsearch/ts_locale.h"
#include "utils/memutils.h"
typedef struct typedef struct
{ {
...@@ -111,6 +112,8 @@ typedef struct ...@@ -111,6 +112,8 @@ typedef struct
#define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int32)) #define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int32))
#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + (size) * sizeof(ITEM) + (lenofoperand) ) #define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + (size) * sizeof(ITEM) + (lenofoperand) )
#define LTXTQUERY_TOO_BIG(size,lenofoperand) \
((size) > (MaxAllocSize - HDRSIZEQT - (lenofoperand)) / sizeof(ITEM))
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) #define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) ) #define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) )
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <ctype.h> #include <ctype.h>
#include "ltree.h" #include "ltree.h"
#include "utils/memutils.h"
#include "crc32.h" #include "crc32.h"
PG_FUNCTION_INFO_V1(ltree_in); PG_FUNCTION_INFO_V1(ltree_in);
...@@ -64,6 +65,11 @@ ltree_in(PG_FUNCTION_ARGS) ...@@ -64,6 +65,11 @@ ltree_in(PG_FUNCTION_ARGS)
ptr += charlen; ptr += charlen;
} }
if (num + 1 > MaxAllocSize / sizeof(nodeitem))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
num + 1, (int) (MaxAllocSize / sizeof(nodeitem)))));
list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1)); list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
ptr = buf; ptr = buf;
while (*ptr) while (*ptr)
...@@ -228,6 +234,11 @@ lquery_in(PG_FUNCTION_ARGS) ...@@ -228,6 +234,11 @@ lquery_in(PG_FUNCTION_ARGS)
} }
num++; num++;
if (num > MaxAllocSize / ITEMSIZE)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
num, (int) (MaxAllocSize / ITEMSIZE))));
curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num); curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
ptr = buf; ptr = buf;
while (*ptr) while (*ptr)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "crc32.h" #include "crc32.h"
#include "ltree.h" #include "ltree.h"
#include "miscadmin.h"
PG_FUNCTION_INFO_V1(ltxtq_in); PG_FUNCTION_INFO_V1(ltxtq_in);
Datum ltxtq_in(PG_FUNCTION_ARGS); Datum ltxtq_in(PG_FUNCTION_ARGS);
...@@ -212,6 +213,9 @@ makepol(QPRS_STATE *state) ...@@ -212,6 +213,9 @@ makepol(QPRS_STATE *state)
int32 lenstack = 0; int32 lenstack = 0;
uint16 flag = 0; uint16 flag = 0;
/* since this function recurses, it could be driven to stack overflow */
check_stack_depth();
while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END) while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END)
{ {
switch (type) switch (type)
...@@ -276,6 +280,9 @@ makepol(QPRS_STATE *state) ...@@ -276,6 +280,9 @@ makepol(QPRS_STATE *state)
static void static void
findoprnd(ITEM *ptr, int32 *pos) findoprnd(ITEM *ptr, int32 *pos)
{ {
/* since this function recurses, it could be driven to stack overflow. */
check_stack_depth();
if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE) if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE)
{ {
ptr[*pos].left = 0; ptr[*pos].left = 0;
...@@ -340,8 +347,12 @@ queryin(char *buf) ...@@ -340,8 +347,12 @@ queryin(char *buf)
errmsg("syntax error"), errmsg("syntax error"),
errdetail("Empty query."))); errdetail("Empty query.")));
/* make finish struct */ if (LTXTQUERY_TOO_BIG(state.num, state.sumlen))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("ltxtquery is too large")));
commonlen = COMPUTESIZE(state.num, state.sumlen); commonlen = COMPUTESIZE(state.num, state.sumlen);
query = (ltxtquery *) palloc(commonlen); query = (ltxtquery *) palloc(commonlen);
SET_VARSIZE(query, commonlen); SET_VARSIZE(query, commonlen);
query->size = state.num; query->size = state.num;
......
...@@ -1366,6 +1366,7 @@ path_in(PG_FUNCTION_ARGS) ...@@ -1366,6 +1366,7 @@ path_in(PG_FUNCTION_ARGS)
char *s; char *s;
int npts; int npts;
int size; int size;
int base_size;
int depth = 0; int depth = 0;
if ((npts = pair_count(str, ',')) <= 0) if ((npts = pair_count(str, ',')) <= 0)
...@@ -1384,7 +1385,15 @@ path_in(PG_FUNCTION_ARGS) ...@@ -1384,7 +1385,15 @@ path_in(PG_FUNCTION_ARGS)
depth++; depth++;
} }
size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts; base_size = sizeof(path->p[0]) * npts;
size = offsetof(PATH, p[0]) + base_size;
/* Check for integer overflow */
if (base_size / npts != sizeof(path->p[0]) || size <= base_size)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("too many points requested")));
path = (PATH *) palloc(size); path = (PATH *) palloc(size);
SET_VARSIZE(path, size); SET_VARSIZE(path, size);
...@@ -3429,6 +3438,7 @@ poly_in(PG_FUNCTION_ARGS) ...@@ -3429,6 +3438,7 @@ poly_in(PG_FUNCTION_ARGS)
POLYGON *poly; POLYGON *poly;
int npts; int npts;
int size; int size;
int base_size;
int isopen; int isopen;
char *s; char *s;
...@@ -3437,7 +3447,15 @@ poly_in(PG_FUNCTION_ARGS) ...@@ -3437,7 +3447,15 @@ poly_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type polygon: \"%s\"", str))); errmsg("invalid input syntax for type polygon: \"%s\"", str)));
size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * npts; base_size = sizeof(poly->p[0]) * npts;
size = offsetof(POLYGON, p[0]) + base_size;
/* Check for integer overflow */
if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("too many points requested")));
poly = (POLYGON *) palloc0(size); /* zero any holes */ poly = (POLYGON *) palloc0(size); /* zero any holes */
SET_VARSIZE(poly, size); SET_VARSIZE(poly, size);
...@@ -4343,6 +4361,10 @@ path_poly(PG_FUNCTION_ARGS) ...@@ -4343,6 +4361,10 @@ path_poly(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("open path cannot be converted to polygon"))); errmsg("open path cannot be converted to polygon")));
/*
* Never overflows: the old size fit in MaxAllocSize, and the new size is
* just a small constant larger.
*/
size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * path->npts; size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * path->npts;
poly = (POLYGON *) palloc(size); poly = (POLYGON *) palloc(size);
...@@ -4448,6 +4470,10 @@ poly_path(PG_FUNCTION_ARGS) ...@@ -4448,6 +4470,10 @@ poly_path(PG_FUNCTION_ARGS)
int size; int size;
int i; int i;
/*
* Never overflows: the old size fit in MaxAllocSize, and the new size is
* smaller by a small constant.
*/
size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * poly->npts; size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * poly->npts;
path = (PATH *) palloc(size); path = (PATH *) palloc(size);
......
...@@ -514,8 +514,13 @@ parse_tsquery(char *buf, ...@@ -514,8 +514,13 @@ parse_tsquery(char *buf,
return query; return query;
} }
/* Pack the QueryItems in the final TSQuery struct to return to caller */ if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("tsquery is too large")));
commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen); commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
/* Pack the QueryItems in the final TSQuery struct to return to caller */
query = (TSQuery) palloc0(commonlen); query = (TSQuery) palloc0(commonlen);
SET_VARSIZE(query, commonlen); SET_VARSIZE(query, commonlen);
query->size = list_length(state.polstr); query->size = list_length(state.polstr);
......
...@@ -333,6 +333,11 @@ QTN2QT(QTNode *in) ...@@ -333,6 +333,11 @@ QTN2QT(QTNode *in)
QTN2QTState state; QTN2QTState state;
cntsize(in, &sumlen, &nnode); cntsize(in, &sumlen, &nnode);
if (TSQUERY_TOO_BIG(nnode, sumlen))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("tsquery is too large")));
len = COMPUTESIZE(nnode, sumlen); len = COMPUTESIZE(nnode, sumlen);
out = (TSQuery) palloc0(len); out = (TSQuery) palloc0(len);
......
...@@ -26,7 +26,9 @@ ...@@ -26,7 +26,9 @@
#include "funcapi.h" #include "funcapi.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
#include "postmaster/postmaster.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h" #include "utils/snapmgr.h"
...@@ -66,6 +68,8 @@ typedef struct ...@@ -66,6 +68,8 @@ typedef struct
#define TXID_SNAPSHOT_SIZE(nxip) \ #define TXID_SNAPSHOT_SIZE(nxip) \
(offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip)) (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
#define TXID_SNAPSHOT_MAX_NXIP \
((MaxAllocSize - offsetof(TxidSnapshot, xip)) / sizeof(txid))
/* /*
* Epoch values from xact.c * Epoch values from xact.c
...@@ -368,6 +372,13 @@ txid_current_snapshot(PG_FUNCTION_ARGS) ...@@ -368,6 +372,13 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
load_xid_epoch(&state); load_xid_epoch(&state);
/*
* Compile-time limits on the procarray (MAX_BACKENDS processes plus
* MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
*/
StaticAssertStmt(MAX_BACKENDS * 2 <= TXID_SNAPSHOT_MAX_NXIP,
"possible overflow in txid_current_snapshot()");
/* allocate */ /* allocate */
nxip = cur->xcnt; nxip = cur->xcnt;
size = TXID_SNAPSHOT_SIZE(nxip); size = TXID_SNAPSHOT_SIZE(nxip);
...@@ -445,20 +456,12 @@ txid_snapshot_recv(PG_FUNCTION_ARGS) ...@@ -445,20 +456,12 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
txid last = 0; txid last = 0;
int nxip; int nxip;
int i; int i;
int avail;
int expect;
txid xmin, txid xmin,
xmax; xmax;
/* /* load and validate nxip */
* load nxip and check for nonsense.
*
* (nxip > avail) check is against int overflows in 'expect'.
*/
nxip = pq_getmsgint(buf, 4); nxip = pq_getmsgint(buf, 4);
avail = buf->len - buf->cursor; if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP)
expect = 8 + 8 + nxip * 8;
if (nxip < 0 || nxip > avail || expect > avail)
goto bad_format; goto bad_format;
xmin = pq_getmsgint64(buf); xmin = pq_getmsgint64(buf);
......
...@@ -148,12 +148,22 @@ bit_in(PG_FUNCTION_ARGS) ...@@ -148,12 +148,22 @@ bit_in(PG_FUNCTION_ARGS)
sp = input_string; sp = input_string;
} }
/*
* Determine bitlength from input string. MaxAllocSize ensures a regular
* input is small enough, but we must check hex input.
*/
slen = strlen(sp); slen = strlen(sp);
/* Determine bitlength from input string */
if (bit_not_hex) if (bit_not_hex)
bitlen = slen; bitlen = slen;
else else
{
if (slen > VARBITMAXLEN / 4)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("bit string length exceeds the maximum allowed (%d)",
VARBITMAXLEN)));
bitlen = slen * 4; bitlen = slen * 4;
}
/* /*
* Sometimes atttypmod is not supplied. If it is supplied we need to make * Sometimes atttypmod is not supplied. If it is supplied we need to make
...@@ -450,12 +460,22 @@ varbit_in(PG_FUNCTION_ARGS) ...@@ -450,12 +460,22 @@ varbit_in(PG_FUNCTION_ARGS)
sp = input_string; sp = input_string;
} }
/*
* Determine bitlength from input string. MaxAllocSize ensures a regular
* input is small enough, but we must check hex input.
*/
slen = strlen(sp); slen = strlen(sp);
/* Determine bitlength from input string */
if (bit_not_hex) if (bit_not_hex)
bitlen = slen; bitlen = slen;
else else
{
if (slen > VARBITMAXLEN / 4)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("bit string length exceeds the maximum allowed (%d)",
VARBITMAXLEN)));
bitlen = slen * 4; bitlen = slen * 4;
}
/* /*
* Sometimes atttypmod is not supplied. If it is supplied we need to make * Sometimes atttypmod is not supplied. If it is supplied we need to make
...@@ -535,6 +555,9 @@ varbit_in(PG_FUNCTION_ARGS) ...@@ -535,6 +555,9 @@ varbit_in(PG_FUNCTION_ARGS)
/* /*
* varbit_out - * varbit_out -
* Prints the string as bits to preserve length accurately * Prints the string as bits to preserve length accurately
*
* XXX varbit_recv() and hex input to varbit_in() can load a value that this
* cannot emit. Consider using hex output for such values.
*/ */
Datum Datum
varbit_out(PG_FUNCTION_ARGS) varbit_out(PG_FUNCTION_ARGS)
...@@ -944,6 +967,11 @@ bit_catenate(VarBit *arg1, VarBit *arg2) ...@@ -944,6 +967,11 @@ bit_catenate(VarBit *arg1, VarBit *arg2)
bitlen1 = VARBITLEN(arg1); bitlen1 = VARBITLEN(arg1);
bitlen2 = VARBITLEN(arg2); bitlen2 = VARBITLEN(arg2);
if (bitlen1 > VARBITMAXLEN - bitlen2)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("bit string length exceeds the maximum allowed (%d)",
VARBITMAXLEN)));
bytelen = VARBITTOTALLEN(bitlen1 + bitlen2); bytelen = VARBITTOTALLEN(bitlen1 + bitlen2);
result = (VarBit *) palloc(bytelen); result = (VarBit *) palloc(bytelen);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#define _PG_TSTYPE_H_ #define _PG_TSTYPE_H_
#include "fmgr.h" #include "fmgr.h"
#include "utils/memutils.h"
#include "utils/pg_crc.h" #include "utils/pg_crc.h"
...@@ -244,6 +245,8 @@ typedef TSQueryData *TSQuery; ...@@ -244,6 +245,8 @@ typedef TSQueryData *TSQuery;
* QueryItems, and lenofoperand is the total length of all operands * QueryItems, and lenofoperand is the total length of all operands
*/ */
#define COMPUTESIZE(size, lenofoperand) ( HDRSIZETQ + (size) * sizeof(QueryItem) + (lenofoperand) ) #define COMPUTESIZE(size, lenofoperand) ( HDRSIZETQ + (size) * sizeof(QueryItem) + (lenofoperand) )
#define TSQUERY_TOO_BIG(size, lenofoperand) \
((size) > (MaxAllocSize - HDRSIZETQ - (lenofoperand)) / sizeof(QueryItem))
/* Returns a pointer to the first QueryItem in a TSQuery */ /* Returns a pointer to the first QueryItem in a TSQuery */
#define GETQUERY(x) ((QueryItem*)( (char*)(x)+HDRSIZETQ )) #define GETQUERY(x) ((QueryItem*)( (char*)(x)+HDRSIZETQ ))
......
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
#ifndef VARBIT_H #ifndef VARBIT_H
#define VARBIT_H #define VARBIT_H
#include <limits.h>
#include "fmgr.h" #include "fmgr.h"
/* /*
...@@ -53,6 +55,11 @@ typedef struct ...@@ -53,6 +55,11 @@ typedef struct
/* Number of bytes needed to store a bit string of a given length */ /* Number of bytes needed to store a bit string of a given length */
#define VARBITTOTALLEN(BITLEN) (((BITLEN) + BITS_PER_BYTE-1)/BITS_PER_BYTE + \ #define VARBITTOTALLEN(BITLEN) (((BITLEN) + BITS_PER_BYTE-1)/BITS_PER_BYTE + \
VARHDRSZ + VARBITHDRSZ) VARHDRSZ + VARBITHDRSZ)
/*
* Maximum number of bits. Several code sites assume no overflow from
* computing bitlen + X; VARBITTOTALLEN() has the largest such X.
*/
#define VARBITMAXLEN (INT_MAX - BITS_PER_BYTE + 1)
/* pointer beyond the end of the bit string (like end() in STL containers) */ /* pointer beyond the end of the bit string (like end() in STL containers) */
#define VARBITEND(PTR) (((bits8 *) (PTR)) + VARSIZE(PTR)) #define VARBITEND(PTR) (((bits8 *) (PTR)) + VARSIZE(PTR))
/* Mask that will cover exactly one byte, i.e. BITS_PER_BYTE bits */ /* Mask that will cover exactly one byte, i.e. BITS_PER_BYTE bits */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment