Skip to content

Commit 98be8a6

Browse files
committed
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
1 parent d0ed1a6 commit 98be8a6

File tree

12 files changed

+121
-16
lines changed

12 files changed

+121
-16
lines changed

contrib/intarray/_int.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#define ___INT_H__
66

77
#include "utils/array.h"
8+
#include "utils/memutils.h"
89

910
/* number ranges for compression */
1011
#define MAXNUMRANGE 100
@@ -142,6 +143,7 @@ typedef struct
142143

143144
#define HDRSIZEQT (VARHDRSZ + sizeof(int4))
144145
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) )
146+
#define QUERYTYPEMAXITEMS ((MaxAllocSize - HDRSIZEQT) / sizeof(ITEM))
145147
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
146148

147149
#define END 0

contrib/intarray/_int_bool.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,9 @@ boolop(PG_FUNCTION_ARGS)
416416
static void
417417
findoprnd(ITEM *ptr, int4 *pos)
418418
{
419+
/* since this function recurses, it could be driven to stack overflow. */
420+
check_stack_depth();
421+
419422
#ifdef BS_DEBUG
420423
elog(DEBUG3, (ptr[*pos].type == OPR) ?
421424
"%d %c" : "%d %d", *pos, ptr[*pos].val);
@@ -476,7 +479,13 @@ bqarr_in(PG_FUNCTION_ARGS)
476479
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
477480
errmsg("empty query")));
478481

482+
if (state.num > QUERYTYPEMAXITEMS)
483+
ereport(ERROR,
484+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
485+
errmsg("number of query items (%d) exceeds the maximum allowed (%d)",
486+
state.num, (int) QUERYTYPEMAXITEMS)));
479487
commonlen = COMPUTESIZE(state.num);
488+
480489
query = (QUERYTYPE *) palloc(commonlen);
481490
SET_VARSIZE(query, commonlen);
482491
query->size = state.num;

contrib/ltree/ltree.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "postgres.h"
77
#include "fmgr.h"
88
#include "tsearch/ts_locale.h"
9+
#include "utils/memutils.h"
910

1011
typedef struct
1112
{
@@ -112,6 +113,8 @@ typedef struct
112113

113114
#define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int4))
114115
#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + (size) * sizeof(ITEM) + (lenofoperand) )
116+
#define LTXTQUERY_TOO_BIG(size,lenofoperand) \
117+
((size) > (MaxAllocSize - HDRSIZEQT - (lenofoperand)) / sizeof(ITEM))
115118
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
116119
#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) )
117120

contrib/ltree/ltree_io.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <ctype.h>
99

1010
#include "ltree.h"
11+
#include "utils/memutils.h"
1112
#include "crc32.h"
1213

1314
PG_FUNCTION_INFO_V1(ltree_in);
@@ -64,6 +65,11 @@ ltree_in(PG_FUNCTION_ARGS)
6465
ptr += charlen;
6566
}
6667

68+
if (num + 1 > MaxAllocSize / sizeof(nodeitem))
69+
ereport(ERROR,
70+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
71+
errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
72+
num + 1, (int) (MaxAllocSize / sizeof(nodeitem)))));
6773
list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1));
6874
ptr = buf;
6975
while (*ptr)
@@ -228,6 +234,11 @@ lquery_in(PG_FUNCTION_ARGS)
228234
}
229235

230236
num++;
237+
if (num > MaxAllocSize / ITEMSIZE)
238+
ereport(ERROR,
239+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
240+
errmsg("number of levels (%d) exceeds the maximum allowed (%d)",
241+
num, (int) (MaxAllocSize / ITEMSIZE))));
231242
curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num);
232243
ptr = buf;
233244
while (*ptr)

contrib/ltree/ltxtquery_io.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "crc32.h"
1111
#include "ltree.h"
12+
#include "miscadmin.h"
1213

1314
PG_FUNCTION_INFO_V1(ltxtq_in);
1415
Datum ltxtq_in(PG_FUNCTION_ARGS);
@@ -213,6 +214,9 @@ makepol(QPRS_STATE *state)
213214
int4 lenstack = 0;
214215
uint16 flag = 0;
215216

217+
/* since this function recurses, it could be driven to stack overflow */
218+
check_stack_depth();
219+
216220
while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END)
217221
{
218222
switch (type)
@@ -277,6 +281,9 @@ makepol(QPRS_STATE *state)
277281
static void
278282
findoprnd(ITEM *ptr, int4 *pos)
279283
{
284+
/* since this function recurses, it could be driven to stack overflow. */
285+
check_stack_depth();
286+
280287
if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE)
281288
{
282289
ptr[*pos].left = 0;
@@ -341,8 +348,12 @@ queryin(char *buf)
341348
errmsg("syntax error"),
342349
errdetail("Empty query.")));
343350

344-
/* make finish struct */
351+
if (LTXTQUERY_TOO_BIG(state.num, state.sumlen))
352+
ereport(ERROR,
353+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
354+
errmsg("ltxtquery is too large")));
345355
commonlen = COMPUTESIZE(state.num, state.sumlen);
356+
346357
query = (ltxtquery *) palloc(commonlen);
347358
SET_VARSIZE(query, commonlen);
348359
query->size = state.num;

src/backend/utils/adt/geo_ops.c

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,6 +1401,7 @@ path_in(PG_FUNCTION_ARGS)
14011401
char *s;
14021402
int npts;
14031403
int size;
1404+
int base_size;
14041405
int depth = 0;
14051406

14061407
if ((npts = pair_count(str, ',')) <= 0)
@@ -1419,7 +1420,15 @@ path_in(PG_FUNCTION_ARGS)
14191420
depth++;
14201421
}
14211422

1422-
size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts;
1423+
base_size = sizeof(path->p[0]) * npts;
1424+
size = offsetof(PATH, p[0]) + base_size;
1425+
1426+
/* Check for integer overflow */
1427+
if (base_size / npts != sizeof(path->p[0]) || size <= base_size)
1428+
ereport(ERROR,
1429+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1430+
errmsg("too many points requested")));
1431+
14231432
path = (PATH *) palloc(size);
14241433

14251434
SET_VARSIZE(path, size);
@@ -3439,6 +3448,7 @@ poly_in(PG_FUNCTION_ARGS)
34393448
POLYGON *poly;
34403449
int npts;
34413450
int size;
3451+
int base_size;
34423452
int isopen;
34433453
char *s;
34443454

@@ -3447,7 +3457,15 @@ poly_in(PG_FUNCTION_ARGS)
34473457
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
34483458
errmsg("invalid input syntax for type polygon: \"%s\"", str)));
34493459

3450-
size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * npts;
3460+
base_size = sizeof(poly->p[0]) * npts;
3461+
size = offsetof(POLYGON, p[0]) + base_size;
3462+
3463+
/* Check for integer overflow */
3464+
if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
3465+
ereport(ERROR,
3466+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3467+
errmsg("too many points requested")));
3468+
34513469
poly = (POLYGON *) palloc0(size); /* zero any holes */
34523470

34533471
SET_VARSIZE(poly, size);
@@ -4216,6 +4234,10 @@ path_poly(PG_FUNCTION_ARGS)
42164234
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
42174235
errmsg("open path cannot be converted to polygon")));
42184236

4237+
/*
4238+
* Never overflows: the old size fit in MaxAllocSize, and the new size is
4239+
* just a small constant larger.
4240+
*/
42194241
size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * path->npts;
42204242
poly = (POLYGON *) palloc(size);
42214243

@@ -4321,6 +4343,10 @@ poly_path(PG_FUNCTION_ARGS)
43214343
int size;
43224344
int i;
43234345

4346+
/*
4347+
* Never overflows: the old size fit in MaxAllocSize, and the new size is
4348+
* smaller by a small constant.
4349+
*/
43244350
size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * poly->npts;
43254351
path = (PATH *) palloc(size);
43264352

src/backend/utils/adt/tsquery.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -517,8 +517,13 @@ parse_tsquery(char *buf,
517517
return query;
518518
}
519519

520-
/* Pack the QueryItems in the final TSQuery struct to return to caller */
520+
if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen))
521+
ereport(ERROR,
522+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
523+
errmsg("tsquery is too large")));
521524
commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen);
525+
526+
/* Pack the QueryItems in the final TSQuery struct to return to caller */
522527
query = (TSQuery) palloc0(commonlen);
523528
SET_VARSIZE(query, commonlen);
524529
query->size = list_length(state.polstr);

src/backend/utils/adt/tsquery_util.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,11 @@ QTN2QT(QTNode *in)
334334
QTN2QTState state;
335335

336336
cntsize(in, &sumlen, &nnode);
337+
338+
if (TSQUERY_TOO_BIG(nnode, sumlen))
339+
ereport(ERROR,
340+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
341+
errmsg("tsquery is too large")));
337342
len = COMPUTESIZE(nnode, sumlen);
338343

339344
out = (TSQuery) palloc0(len);

src/backend/utils/adt/txid.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "funcapi.h"
2727
#include "libpq/pqformat.h"
2828
#include "utils/builtins.h"
29+
#include "utils/memutils.h"
2930
#include "utils/snapmgr.h"
3031

3132

@@ -70,6 +71,8 @@ typedef struct
7071

7172
#define TXID_SNAPSHOT_SIZE(nxip) \
7273
(offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
74+
#define TXID_SNAPSHOT_MAX_NXIP \
75+
((MaxAllocSize - offsetof(TxidSnapshot, xip)) / sizeof(txid))
7376

7477
/*
7578
* Epoch values from xact.c
@@ -445,20 +448,12 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
445448
txid last = 0;
446449
int nxip;
447450
int i;
448-
int avail;
449-
int expect;
450451
txid xmin,
451452
xmax;
452453

453-
/*
454-
* load nxip and check for nonsense.
455-
*
456-
* (nxip > avail) check is against int overflows in 'expect'.
457-
*/
454+
/* load and validate nxip */
458455
nxip = pq_getmsgint(buf, 4);
459-
avail = buf->len - buf->cursor;
460-
expect = 8 + 8 + nxip * 8;
461-
if (nxip < 0 || nxip > avail || expect > avail)
456+
if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP)
462457
goto bad_format;
463458

464459
xmin = pq_getmsgint64(buf);

src/backend/utils/adt/varbit.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,22 @@ bit_in(PG_FUNCTION_ARGS)
138138
sp = input_string;
139139
}
140140

141+
/*
142+
* Determine bitlength from input string. MaxAllocSize ensures a regular
143+
* input is small enough, but we must check hex input.
144+
*/
141145
slen = strlen(sp);
142-
/* Determine bitlength from input string */
143146
if (bit_not_hex)
144147
bitlen = slen;
145148
else
149+
{
150+
if (slen > VARBITMAXLEN / 4)
151+
ereport(ERROR,
152+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
153+
errmsg("bit string length exceeds the maximum allowed (%d)",
154+
VARBITMAXLEN)));
146155
bitlen = slen * 4;
156+
}
147157

148158
/*
149159
* Sometimes atttypmod is not supplied. If it is supplied we need to make
@@ -436,12 +446,22 @@ varbit_in(PG_FUNCTION_ARGS)
436446
sp = input_string;
437447
}
438448

449+
/*
450+
* Determine bitlength from input string. MaxAllocSize ensures a regular
451+
* input is small enough, but we must check hex input.
452+
*/
439453
slen = strlen(sp);
440-
/* Determine bitlength from input string */
441454
if (bit_not_hex)
442455
bitlen = slen;
443456
else
457+
{
458+
if (slen > VARBITMAXLEN / 4)
459+
ereport(ERROR,
460+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
461+
errmsg("bit string length exceeds the maximum allowed (%d)",
462+
VARBITMAXLEN)));
444463
bitlen = slen * 4;
464+
}
445465

446466
/*
447467
* Sometimes atttypmod is not supplied. If it is supplied we need to make
@@ -520,6 +540,9 @@ varbit_in(PG_FUNCTION_ARGS)
520540

521541
/* varbit_out -
522542
* Prints the string as bits to preserve length accurately
543+
*
544+
* XXX varbit_recv() and hex input to varbit_in() can load a value that this
545+
* cannot emit. Consider using hex output for such values.
523546
*/
524547
Datum
525548
varbit_out(PG_FUNCTION_ARGS)
@@ -886,6 +909,11 @@ bitcat(PG_FUNCTION_ARGS)
886909
bitlen1 = VARBITLEN(arg1);
887910
bitlen2 = VARBITLEN(arg2);
888911

912+
if (bitlen1 > VARBITMAXLEN - bitlen2)
913+
ereport(ERROR,
914+
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
915+
errmsg("bit string length exceeds the maximum allowed (%d)",
916+
VARBITMAXLEN)));
889917
bytelen = VARBITTOTALLEN(bitlen1 + bitlen2);
890918

891919
result = (VarBit *) palloc(bytelen);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy