mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	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
This commit is contained in:
		@@ -49,9 +49,12 @@ typedef struct
 | 
			
		||||
} HStore;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * it's not possible to get more than 2^28 items into an hstore,
 | 
			
		||||
 * so we reserve the top few bits of the size field. See hstore_compat.c
 | 
			
		||||
 * for one reason why.	Some bits are left for future use here.
 | 
			
		||||
 * It's not possible to get more than 2^28 items into an hstore, so we reserve
 | 
			
		||||
 * the top few bits of the size field.  See hstore_compat.c for one reason
 | 
			
		||||
 * 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
 | 
			
		||||
 | 
			
		||||
@@ -59,6 +62,12 @@ typedef struct
 | 
			
		||||
#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 CALCDATASIZE(x, lenstr) ( (x) * 2 * sizeof(HEntry) + HSHRDSIZE + (lenstr) )
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@
 | 
			
		||||
#include "utils/builtins.h"
 | 
			
		||||
#include "utils/json.h"
 | 
			
		||||
#include "utils/lsyscache.h"
 | 
			
		||||
#include "utils/memutils.h"
 | 
			
		||||
#include "utils/typcache.h"
 | 
			
		||||
 | 
			
		||||
#include "hstore.h"
 | 
			
		||||
@@ -439,6 +440,11 @@ hstore_recv(PG_FUNCTION_ARGS)
 | 
			
		||||
		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));
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < pcount; ++i)
 | 
			
		||||
@@ -554,6 +560,13 @@ hstore_from_arrays(PG_FUNCTION_ARGS)
 | 
			
		||||
					  TEXTOID, -1, false, 'i',
 | 
			
		||||
					  &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 */
 | 
			
		||||
 | 
			
		||||
	if (PG_ARGISNULL(1))
 | 
			
		||||
@@ -676,6 +689,13 @@ hstore_from_array(PG_FUNCTION_ARGS)
 | 
			
		||||
 | 
			
		||||
	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));
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < count; ++i)
 | 
			
		||||
@@ -807,6 +827,7 @@ hstore_from_record(PG_FUNCTION_ARGS)
 | 
			
		||||
		my_extra->ncolumns = ncolumns;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Assert(ncolumns <= MaxTupleAttributeNumber);		/* thus, no overflow */
 | 
			
		||||
	pairs = palloc(ncolumns * sizeof(Pairs));
 | 
			
		||||
 | 
			
		||||
	if (rec)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
#include "catalog/pg_type.h"
 | 
			
		||||
#include "funcapi.h"
 | 
			
		||||
#include "utils/builtins.h"
 | 
			
		||||
#include "utils/memutils.h"
 | 
			
		||||
 | 
			
		||||
#include "hstore.h"
 | 
			
		||||
 | 
			
		||||
@@ -90,6 +91,19 @@ hstoreArrayToPairs(ArrayType *a, int *npairs)
 | 
			
		||||
		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);
 | 
			
		||||
 | 
			
		||||
	for (i = 0, j = 0; i < key_count; i++)
 | 
			
		||||
@@ -648,6 +662,7 @@ hstore_slice_to_hstore(PG_FUNCTION_ARGS)
 | 
			
		||||
		PG_RETURN_POINTER(out);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* hstoreArrayToPairs() checked overflow */
 | 
			
		||||
	out_pairs = palloc(sizeof(Pairs) * nkeys);
 | 
			
		||||
	bufsiz = 0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#define ___INT_H__
 | 
			
		||||
 | 
			
		||||
#include "utils/array.h"
 | 
			
		||||
#include "utils/memutils.h"
 | 
			
		||||
 | 
			
		||||
/* number ranges for compression */
 | 
			
		||||
#define MAXNUMRANGE 100
 | 
			
		||||
@@ -137,6 +138,7 @@ typedef struct QUERYTYPE
 | 
			
		||||
 | 
			
		||||
#define HDRSIZEQT	offsetof(QUERYTYPE, items)
 | 
			
		||||
#define COMPUTESIZE(size)	( HDRSIZEQT + (size) * sizeof(ITEM) )
 | 
			
		||||
#define QUERYTYPEMAXITEMS	((MaxAllocSize - HDRSIZEQT) / sizeof(ITEM))
 | 
			
		||||
#define GETQUERY(x)  ( (x)->items )
 | 
			
		||||
 | 
			
		||||
/* "type" codes for ITEM */
 | 
			
		||||
 
 | 
			
		||||
@@ -448,6 +448,9 @@ boolop(PG_FUNCTION_ARGS)
 | 
			
		||||
static void
 | 
			
		||||
findoprnd(ITEM *ptr, int32 *pos)
 | 
			
		||||
{
 | 
			
		||||
	/* since this function recurses, it could be driven to stack overflow. */
 | 
			
		||||
	check_stack_depth();
 | 
			
		||||
 | 
			
		||||
#ifdef BS_DEBUG
 | 
			
		||||
	elog(DEBUG3, (ptr[*pos].type == OPR) ?
 | 
			
		||||
		 "%d  %c" : "%d  %d", *pos, ptr[*pos].val);
 | 
			
		||||
@@ -508,7 +511,13 @@ bqarr_in(PG_FUNCTION_ARGS)
 | 
			
		||||
				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 | 
			
		||||
				 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);
 | 
			
		||||
 | 
			
		||||
	query = (QUERYTYPE *) palloc(commonlen);
 | 
			
		||||
	SET_VARSIZE(query, commonlen);
 | 
			
		||||
	query->size = state.num;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
 | 
			
		||||
#include "fmgr.h"
 | 
			
		||||
#include "tsearch/ts_locale.h"
 | 
			
		||||
#include "utils/memutils.h"
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
@@ -111,6 +112,8 @@ typedef struct
 | 
			
		||||
 | 
			
		||||
#define HDRSIZEQT		MAXALIGN(VARHDRSZ + sizeof(int32))
 | 
			
		||||
#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 GETOPERAND(x)	( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) )
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
 | 
			
		||||
#include "ltree.h"
 | 
			
		||||
#include "utils/memutils.h"
 | 
			
		||||
#include "crc32.h"
 | 
			
		||||
 | 
			
		||||
PG_FUNCTION_INFO_V1(ltree_in);
 | 
			
		||||
@@ -64,6 +65,11 @@ ltree_in(PG_FUNCTION_ARGS)
 | 
			
		||||
		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));
 | 
			
		||||
	ptr = buf;
 | 
			
		||||
	while (*ptr)
 | 
			
		||||
@@ -228,6 +234,11 @@ lquery_in(PG_FUNCTION_ARGS)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
	ptr = buf;
 | 
			
		||||
	while (*ptr)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
 | 
			
		||||
#include "crc32.h"
 | 
			
		||||
#include "ltree.h"
 | 
			
		||||
#include "miscadmin.h"
 | 
			
		||||
 | 
			
		||||
PG_FUNCTION_INFO_V1(ltxtq_in);
 | 
			
		||||
Datum		ltxtq_in(PG_FUNCTION_ARGS);
 | 
			
		||||
@@ -212,6 +213,9 @@ makepol(QPRS_STATE *state)
 | 
			
		||||
	int32		lenstack = 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)
 | 
			
		||||
	{
 | 
			
		||||
		switch (type)
 | 
			
		||||
@@ -276,6 +280,9 @@ makepol(QPRS_STATE *state)
 | 
			
		||||
static void
 | 
			
		||||
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)
 | 
			
		||||
	{
 | 
			
		||||
		ptr[*pos].left = 0;
 | 
			
		||||
@@ -340,8 +347,12 @@ queryin(char *buf)
 | 
			
		||||
				 errmsg("syntax error"),
 | 
			
		||||
				 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);
 | 
			
		||||
 | 
			
		||||
	query = (ltxtquery *) palloc(commonlen);
 | 
			
		||||
	SET_VARSIZE(query, commonlen);
 | 
			
		||||
	query->size = state.num;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user