Code: txid_snapshot_recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	TxidSnapshot *snap;
 	txid		last = 0;
 	int			nxip;
 	int			i;
	int			avail;
	int			expect;
 	txid		xmin,
 				xmax;
 
	/*
	 * load nxip and check for nonsense.
	 *
	 * (nxip > avail) check is against int overflows in 'expect'.
	 */
 	nxip = pq_getmsgint(buf, 4);
	avail = buf->len - buf->cursor;
	expect = 8 + 8 + nxip * 8;
	if (nxip < 0 || nxip > avail || expect > avail)
 		goto bad_format;
 
 	xmin = pq_getmsgint64(buf);
	xmax = pq_getmsgint64(buf);
	if (xmin == 0 || xmax == 0 || xmin > xmax || xmax > MAX_TXID)
		goto bad_format;

	snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
	snap->xmin = xmin;
	snap->xmax = xmax;
	snap->nxip = nxip;
	SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip));

	for (i = 0; i < nxip; i++)
	{
		txid		cur = pq_getmsgint64(buf);

		if (cur <= last || cur < xmin || cur >= xmax)
			goto bad_format;
		snap->xip[i] = cur;
		last = cur;
	}
	PG_RETURN_POINTER(snap);

bad_format:
	elog(ERROR, "invalid snapshot data");
	return (Datum) NULL;
}

Commit Message: 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
CWE ID: CWE-189
txid_snapshot_recv(PG_FUNCTION_ARGS)
{
	StringInfo	buf = (StringInfo) PG_GETARG_POINTER(0);
	TxidSnapshot *snap;
 	txid		last = 0;
 	int			nxip;
 	int			i;
 	txid		xmin,
 				xmax;
 
	/* load and validate nxip */
 	nxip = pq_getmsgint(buf, 4);
	if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP)
 		goto bad_format;
 
 	xmin = pq_getmsgint64(buf);
	xmax = pq_getmsgint64(buf);
	if (xmin == 0 || xmax == 0 || xmin > xmax || xmax > MAX_TXID)
		goto bad_format;

	snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
	snap->xmin = xmin;
	snap->xmax = xmax;
	snap->nxip = nxip;
	SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip));

	for (i = 0; i < nxip; i++)
	{
		txid		cur = pq_getmsgint64(buf);

		if (cur <= last || cur < xmin || cur >= xmax)
			goto bad_format;
		snap->xip[i] = cur;
		last = cur;
	}
	PG_RETURN_POINTER(snap);

bad_format:
	elog(ERROR, "invalid snapshot data");
	return (Datum) NULL;
}
