postgresql: upgrade to 9.4.2

1. remove Backport patches
2. Update the checksume, include CopyRight file, since date in it
is changed
3. remove --without-krb5 configure options, since it become useless
4. Update remove.autoconf.version.check.patch
5. skip to check libperl

Signed-off-by: Roy Li <rongqing.li@windriver.com>
Signed-off-by: Martin Jansa <Martin.Jansa@gmail.com>
This commit is contained in:
Roy Li
2015-06-09 11:07:24 +08:00
committed by Martin Jansa
parent 780333ce0d
commit 13a7f47192
13 changed files with 48 additions and 3184 deletions
@@ -1,605 +0,0 @@
From 12bbce15d93d7692ddff1405aa04b67f8a327f57 Mon Sep 17 00:00:00 2001
From: Noah Misch <noah@leadboat.com>
Date: Mon, 17 Feb 2014 09:33:31 -0500
Subject: [PATCH] Predict integer overflow to avoid buffer overruns.
commit 12bbce15d93d7692ddff1405aa04b67f8a327f57 REL9_2_STABLE
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
Upstream-Status: Backport
Signed-off-by: Kai Kang <kai.kang@windriver.com>
---
contrib/hstore/hstore.h | 15 ++++++++++++---
contrib/hstore/hstore_io.c | 21 +++++++++++++++++++++
contrib/hstore/hstore_op.c | 15 +++++++++++++++
contrib/intarray/_int.h | 2 ++
contrib/intarray/_int_bool.c | 9 +++++++++
contrib/ltree/ltree.h | 3 +++
contrib/ltree/ltree_io.c | 11 +++++++++++
contrib/ltree/ltxtquery_io.c | 13 ++++++++++++-
src/backend/utils/adt/geo_ops.c | 30 ++++++++++++++++++++++++++++--
src/backend/utils/adt/tsquery.c | 7 ++++++-
src/backend/utils/adt/tsquery_util.c | 5 +++++
src/backend/utils/adt/txid.c | 15 +++++----------
src/backend/utils/adt/varbit.c | 32 ++++++++++++++++++++++++++++++--
src/include/tsearch/ts_type.h | 3 +++
src/include/utils/varbit.h | 7 +++++++
15 files changed, 169 insertions(+), 19 deletions(-)
diff --git a/contrib/hstore/hstore.h b/contrib/hstore/hstore.h
index 8906397..4e55f6e 100644
--- a/contrib/hstore/hstore.h
+++ b/contrib/hstore/hstore.h
@@ -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) )
diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c
index dde6c4b..5bcdc95 100644
--- a/contrib/hstore/hstore_io.c
+++ b/contrib/hstore/hstore_io.c
@@ -9,6 +9,7 @@
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "utils/lsyscache.h"
+#include "utils/memutils.h"
#include "utils/typcache.h"
#include "hstore.h"
@@ -437,6 +438,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)
@@ -552,6 +558,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))
@@ -674,6 +687,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)
@@ -805,6 +825,7 @@ hstore_from_record(PG_FUNCTION_ARGS)
my_extra->ncolumns = ncolumns;
}
+ Assert(ncolumns <= MaxTupleAttributeNumber); /* thus, no overflow */
pairs = palloc(ncolumns * sizeof(Pairs));
if (rec)
diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c
index fee2c3c..8de175a 100644
--- a/contrib/hstore/hstore_op.c
+++ b/contrib/hstore/hstore_op.c
@@ -7,6 +7,7 @@
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "utils/builtins.h"
+#include "utils/memutils.h"
#include "hstore.h"
@@ -89,6 +90,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++)
@@ -647,6 +661,7 @@ hstore_slice_to_hstore(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(out);
}
+ /* hstoreArrayToPairs() checked overflow */
out_pairs = palloc(sizeof(Pairs) * nkeys);
bufsiz = 0;
diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h
index 11c0698..755cd9e 100644
--- a/contrib/intarray/_int.h
+++ b/contrib/intarray/_int.h
@@ -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 */
diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c
index 4e63f6d..62294d1 100644
--- a/contrib/intarray/_int_bool.c
+++ b/contrib/intarray/_int_bool.c
@@ -451,6 +451,9 @@ boolop(PG_FUNCTION_ARGS)
static void
findoprnd(ITEM *ptr, int4 *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);
@@ -511,7 +514,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;
diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h
index aec4458..49e9907 100644
--- a/contrib/ltree/ltree.h
+++ b/contrib/ltree/ltree.h
@@ -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(int4))
#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) )
diff --git a/contrib/ltree/ltree_io.c b/contrib/ltree/ltree_io.c
index 3e88b81..d64debb 100644
--- a/contrib/ltree/ltree_io.c
+++ b/contrib/ltree/ltree_io.c
@@ -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)
diff --git a/contrib/ltree/ltxtquery_io.c b/contrib/ltree/ltxtquery_io.c
index 826f4e1..13ea58d 100644
--- a/contrib/ltree/ltxtquery_io.c
+++ b/contrib/ltree/ltxtquery_io.c
@@ -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);
@@ -213,6 +214,9 @@ makepol(QPRS_STATE *state)
int4 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)
@@ -277,6 +281,9 @@ makepol(QPRS_STATE *state)
static void
findoprnd(ITEM *ptr, int4 *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;
@@ -341,8 +348,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;
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c
index ac7b4b8..7ebcaaa 100644
--- a/src/backend/utils/adt/geo_ops.c
+++ b/src/backend/utils/adt/geo_ops.c
@@ -1403,6 +1403,7 @@ path_in(PG_FUNCTION_ARGS)
char *s;
int npts;
int size;
+ int base_size;
int depth = 0;
if ((npts = pair_count(str, ',')) <= 0)
@@ -1421,7 +1422,15 @@ path_in(PG_FUNCTION_ARGS)
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);
SET_VARSIZE(path, size);
@@ -3465,6 +3474,7 @@ poly_in(PG_FUNCTION_ARGS)
POLYGON *poly;
int npts;
int size;
+ int base_size;
int isopen;
char *s;
@@ -3473,7 +3483,15 @@ poly_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
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 */
SET_VARSIZE(poly, size);
@@ -4379,6 +4397,10 @@ path_poly(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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;
poly = (POLYGON *) palloc(size);
@@ -4484,6 +4506,10 @@ poly_path(PG_FUNCTION_ARGS)
int size;
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;
path = (PATH *) palloc(size);
diff --git a/src/backend/utils/adt/tsquery.c b/src/backend/utils/adt/tsquery.c
index 6e1f8cf..1322b5e 100644
--- a/src/backend/utils/adt/tsquery.c
+++ b/src/backend/utils/adt/tsquery.c
@@ -515,8 +515,13 @@ parse_tsquery(char *buf,
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);
+
+ /* Pack the QueryItems in the final TSQuery struct to return to caller */
query = (TSQuery) palloc0(commonlen);
SET_VARSIZE(query, commonlen);
query->size = list_length(state.polstr);
diff --git a/src/backend/utils/adt/tsquery_util.c b/src/backend/utils/adt/tsquery_util.c
index 0724d33..9003702 100644
--- a/src/backend/utils/adt/tsquery_util.c
+++ b/src/backend/utils/adt/tsquery_util.c
@@ -333,6 +333,11 @@ QTN2QT(QTNode *in)
QTN2QTState state;
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);
out = (TSQuery) palloc0(len);
diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c
index 08a8c89..c71daaf 100644
--- a/src/backend/utils/adt/txid.c
+++ b/src/backend/utils/adt/txid.c
@@ -27,6 +27,7 @@
#include "miscadmin.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
+#include "utils/memutils.h"
#include "utils/snapmgr.h"
@@ -66,6 +67,8 @@ typedef struct
#define TXID_SNAPSHOT_SIZE(nxip) \
(offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
+#define TXID_SNAPSHOT_MAX_NXIP \
+ ((MaxAllocSize - offsetof(TxidSnapshot, xip)) / sizeof(txid))
/*
* Epoch values from xact.c
@@ -445,20 +448,12 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
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'.
- */
+ /* load and validate nxip */
nxip = pq_getmsgint(buf, 4);
- avail = buf->len - buf->cursor;
- expect = 8 + 8 + nxip * 8;
- if (nxip < 0 || nxip > avail || expect > avail)
+ if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP)
goto bad_format;
xmin = pq_getmsgint64(buf);
diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index 2bcf5b8..0deefda 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -148,12 +148,22 @@ bit_in(PG_FUNCTION_ARGS)
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);
- /* Determine bitlength from input string */
if (bit_not_hex)
bitlen = slen;
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;
+ }
/*
* Sometimes atttypmod is not supplied. If it is supplied we need to make
@@ -450,12 +460,22 @@ varbit_in(PG_FUNCTION_ARGS)
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);
- /* Determine bitlength from input string */
if (bit_not_hex)
bitlen = slen;
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;
+ }
/*
* Sometimes atttypmod is not supplied. If it is supplied we need to make
@@ -535,6 +555,9 @@ varbit_in(PG_FUNCTION_ARGS)
/*
* varbit_out -
* 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
varbit_out(PG_FUNCTION_ARGS)
@@ -944,6 +967,11 @@ bit_catenate(VarBit *arg1, VarBit *arg2)
bitlen1 = VARBITLEN(arg1);
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);
result = (VarBit *) palloc(bytelen);
diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h
index 3adc336..9ee5610 100644
--- a/src/include/tsearch/ts_type.h
+++ b/src/include/tsearch/ts_type.h
@@ -13,6 +13,7 @@
#define _PG_TSTYPE_H_
#include "fmgr.h"
+#include "utils/memutils.h"
#include "utils/pg_crc.h"
@@ -244,6 +245,8 @@ typedef TSQueryData *TSQuery;
* QueryItems, and lenofoperand is the total length of all operands
*/
#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 */
#define GETQUERY(x) ((QueryItem*)( (char*)(x)+HDRSIZETQ ))
diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h
index 52dca8b..61531a8 100644
--- a/src/include/utils/varbit.h
+++ b/src/include/utils/varbit.h
@@ -15,6 +15,8 @@
#ifndef VARBIT_H
#define VARBIT_H
+#include <limits.h>
+
#include "fmgr.h"
/*
@@ -53,6 +55,11 @@ typedef struct
/* Number of bytes needed to store a bit string of a given length */
#define VARBITTOTALLEN(BITLEN) (((BITLEN) + BITS_PER_BYTE-1)/BITS_PER_BYTE + \
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) */
#define VARBITEND(PTR) (((bits8 *) (PTR)) + VARSIZE(PTR))
/* Mask that will cover exactly one byte, i.e. BITS_PER_BYTE bits */
--
1.7.5.4
@@ -1,273 +0,0 @@
From 15a8f97b9d16aaf659f58c981242b9da591cf24c Mon Sep 17 00:00:00 2001
From: Noah Misch <noah@leadboat.com>
Date: Mon, 17 Feb 2014 09:33:31 -0500
Subject: [PATCH] Shore up ADMIN OPTION restrictions.
commit 15a8f97b9d16aaf659f58c981242b9da591cf24c REL9_2_STABLE
Granting a role without ADMIN OPTION is supposed to prevent the grantee
from adding or removing members from the granted role. Issuing SET ROLE
before the GRANT bypassed that, because the role itself had an implicit
right to add or remove members. Plug that hole by recognizing that
implicit right only when the session user matches the current role.
Additionally, do not recognize it during a security-restricted operation
or during execution of a SECURITY DEFINER function. The restriction on
SECURITY DEFINER is not security-critical. However, it seems best for a
user testing his own SECURITY DEFINER function to see the same behavior
others will see. Back-patch to 8.4 (all supported versions).
The SQL standards do not conflate roles and users as PostgreSQL does;
only SQL roles have members, and only SQL users initiate sessions. An
application using PostgreSQL users and roles as SQL users and roles will
never attempt to grant membership in the role that is the session user,
so the implicit right to add or remove members will never arise.
The security impact was mostly that a role member could revoke access
from others, contrary to the wishes of his own grantor. Unapproved role
member additions are less notable, because the member can still largely
achieve that by creating a view or a SECURITY DEFINER function.
Reviewed by Andres Freund and Tom Lane. Reported, independently, by
Jonas Sundman and Noah Misch.
Security: CVE-2014-0060
Upstream-Status: Backport
Signed-off-by: Kai Kang <kai.kang@windriver.com>
---
doc/src/sgml/ref/grant.sgml | 12 ++++---
src/backend/commands/user.c | 11 ++++++-
src/backend/utils/adt/acl.c | 50 ++++++++++++++++++++++++------
src/test/regress/expected/privileges.out | 36 +++++++++++++++++++++-
src/test/regress/sql/privileges.sql | 29 ++++++++++++++++-
5 files changed, 120 insertions(+), 18 deletions(-)
diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index fb81af4..2b5a843 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -396,11 +396,13 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace
<para>
If <literal>WITH ADMIN OPTION</literal> is specified, the member can
in turn grant membership in the role to others, and revoke membership
- in the role as well. Without the admin option, ordinary users cannot do
- that. However,
- database superusers can grant or revoke membership in any role to anyone.
- Roles having <literal>CREATEROLE</> privilege can grant or revoke
- membership in any role that is not a superuser.
+ in the role as well. Without the admin option, ordinary users cannot
+ do that. A role is not considered to hold <literal>WITH ADMIN
+ OPTION</literal> on itself, but it may grant or revoke membership in
+ itself from a database session where the session user matches the
+ role. Database superusers can grant or revoke membership in any role
+ to anyone. Roles having <literal>CREATEROLE</> privilege can grant
+ or revoke membership in any role that is not a superuser.
</para>
<para>
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index a22092c..39bf172 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -1334,7 +1334,16 @@ AddRoleMems(const char *rolename, Oid roleid,
rolename)));
}
- /* XXX not sure about this check */
+ /*
+ * The role membership grantor of record has little significance at
+ * present. Nonetheless, inasmuch as users might look to it for a crude
+ * audit trail, let only superusers impute the grant to a third party.
+ *
+ * Before lifting this restriction, give the member == role case of
+ * is_admin_of_role() a fresh look. Ensure that the current role cannot
+ * use an explicit grantor specification to take advantage of the session
+ * user's self-admin right.
+ */
if (grantorId != GetUserId() && !superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 1d6ae8b..9a52edb 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -4580,6 +4580,11 @@ pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
{
if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
{
+ /*
+ * XXX For roleid == role_oid, is_admin_of_role() also examines the
+ * session and call stack. That suits two-argument pg_has_role(), but
+ * it gives the three-argument version a lamentable whimsy.
+ */
if (is_admin_of_role(roleid, role_oid))
return ACLCHECK_OK;
}
@@ -4897,11 +4902,9 @@ is_member_of_role_nosuper(Oid member, Oid role)
/*
- * Is member an admin of role (directly or indirectly)? That is, is it
- * a member WITH ADMIN OPTION?
- *
- * We could cache the result as for is_member_of_role, but currently this
- * is not used in any performance-critical paths, so we don't.
+ * Is member an admin of role? That is, is member the role itself (subject to
+ * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
+ * or a superuser?
*/
bool
is_admin_of_role(Oid member, Oid role)
@@ -4910,14 +4913,41 @@ is_admin_of_role(Oid member, Oid role)
List *roles_list;
ListCell *l;
- /* Fast path for simple case */
- if (member == role)
- return true;
-
- /* Superusers have every privilege, so are part of every role */
if (superuser_arg(member))
return true;
+ if (member == role)
+ /*
+ * A role can admin itself when it matches the session user and we're
+ * outside any security-restricted operation, SECURITY DEFINER or
+ * similar context. SQL-standard roles cannot self-admin. However,
+ * SQL-standard users are distinct from roles, and they are not
+ * grantable like roles: PostgreSQL's role-user duality extends the
+ * standard. Checking for a session user match has the effect of
+ * letting a role self-admin only when it's conspicuously behaving
+ * like a user. Note that allowing self-admin under a mere SET ROLE
+ * would make WITH ADMIN OPTION largely irrelevant; any member could
+ * SET ROLE to issue the otherwise-forbidden command.
+ *
+ * Withholding self-admin in a security-restricted operation prevents
+ * object owners from harnessing the session user identity during
+ * administrative maintenance. Suppose Alice owns a database, has
+ * issued "GRANT alice TO bob", and runs a daily ANALYZE. Bob creates
+ * an alice-owned SECURITY DEFINER function that issues "REVOKE alice
+ * FROM carol". If he creates an expression index calling that
+ * function, Alice will attempt the REVOKE during each ANALYZE.
+ * Checking InSecurityRestrictedOperation() thwarts that attack.
+ *
+ * Withholding self-admin in SECURITY DEFINER functions makes their
+ * behavior independent of the calling user. There's no security or
+ * SQL-standard-conformance need for that restriction, though.
+ *
+ * A role cannot have actual WITH ADMIN OPTION on itself, because that
+ * would imply a membership loop. Therefore, we're done either way.
+ */
+ return member == GetSessionUserId() &&
+ !InLocalUserIdChange() && !InSecurityRestrictedOperation();
+
/*
* Find all the roles that member is a member of, including multi-level
* recursion. We build a list in the same way that is_member_of_role does
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index e8930cb..bc6d731 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -32,7 +32,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4;
ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate
NOTICE: role "regressuser2" is already a member of role "regressgroup2"
ALTER GROUP regressgroup2 DROP USER regressuser2;
-ALTER GROUP regressgroup2 ADD USER regressuser4;
+GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION;
-- test owner privileges
SET SESSION AUTHORIZATION regressuser1;
SELECT session_user, current_user;
@@ -929,6 +929,40 @@ SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION')
t
(1 row)
+-- Admin options
+SET SESSION AUTHORIZATION regressuser4;
+CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS
+ 'GRANT regressgroup2 TO regressuser5';
+GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION
+SET ROLE regressgroup2;
+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege
+ERROR: must have admin option on role "regressgroup2"
+SET SESSION AUTHORIZATION regressuser1;
+GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION
+ERROR: must have admin option on role "regressgroup2"
+SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN
+NOTICE: role "regressuser5" is already a member of role "regressgroup2"
+CONTEXT: SQL function "dogrant_ok" statement 1
+ dogrant_ok
+------------
+
+(1 row)
+
+SET ROLE regressgroup2;
+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help
+ERROR: must have admin option on role "regressgroup2"
+SET SESSION AUTHORIZATION regressgroup2;
+GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin
+NOTICE: role "regressuser5" is already a member of role "regressgroup2"
+CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS
+ 'GRANT regressgroup2 TO regressuser5';
+SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER
+ERROR: must have admin option on role "regressgroup2"
+CONTEXT: SQL function "dogrant_fails" statement 1
+DROP FUNCTION dogrant_fails();
+SET SESSION AUTHORIZATION regressuser4;
+DROP FUNCTION dogrant_ok();
+REVOKE regressgroup2 FROM regressuser5;
-- has_sequence_privilege tests
\c -
CREATE SEQUENCE x_seq;
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index d4d328e..5f1018a 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -37,7 +37,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4;
ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate
ALTER GROUP regressgroup2 DROP USER regressuser2;
-ALTER GROUP regressgroup2 ADD USER regressuser4;
+GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION;
-- test owner privileges
@@ -581,6 +581,33 @@ SELECT has_table_privilege('regressuser3', 'atest4', 'SELECT'); -- false
SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true
+-- Admin options
+
+SET SESSION AUTHORIZATION regressuser4;
+CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS
+ 'GRANT regressgroup2 TO regressuser5';
+GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION
+SET ROLE regressgroup2;
+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege
+
+SET SESSION AUTHORIZATION regressuser1;
+GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION
+SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN
+SET ROLE regressgroup2;
+GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help
+
+SET SESSION AUTHORIZATION regressgroup2;
+GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin
+CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS
+ 'GRANT regressgroup2 TO regressuser5';
+SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER
+DROP FUNCTION dogrant_fails();
+
+SET SESSION AUTHORIZATION regressuser4;
+DROP FUNCTION dogrant_ok();
+REVOKE regressgroup2 FROM regressuser5;
+
+
-- has_sequence_privilege tests
\c -
--
1.7.5.4
@@ -1,267 +0,0 @@
From 1d701d28a796ea2d1a4d2be9e9ee06209eaea040 Mon Sep 17 00:00:00 2001
From: Noah Misch <noah@leadboat.com>
Date: Mon, 17 Feb 2014 09:33:31 -0500
Subject: [PATCH] Prevent privilege escalation in explicit calls to PL
validators.
commit 1d701d28a796ea2d1a4d2be9e9ee06209eaea040 REL9_2_STABLE
The primary role of PL validators is to be called implicitly during
CREATE FUNCTION, but they are also normal functions that a user can call
explicitly. Add a permissions check to each validator to ensure that a
user cannot use explicit validator calls to achieve things he could not
otherwise achieve. Back-patch to 8.4 (all supported versions).
Non-core procedural language extensions ought to make the same two-line
change to their own validators.
Andres Freund, reviewed by Tom Lane and Noah Misch.
Security: CVE-2014-0061
Upstream-Status: Backport
Signed-off-by: Kai Kang <kai.kang@windriver.com>
---
doc/src/sgml/plhandler.sgml | 5 ++-
src/backend/catalog/pg_proc.c | 9 ++++
src/backend/commands/functioncmds.c | 1 -
src/backend/utils/fmgr/fmgr.c | 84 +++++++++++++++++++++++++++++++++++
src/include/fmgr.h | 1 +
src/pl/plperl/plperl.c | 4 ++
src/pl/plpgsql/src/pl_handler.c | 3 +
src/pl/plpython/plpy_main.c | 4 ++
8 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/doc/src/sgml/plhandler.sgml b/doc/src/sgml/plhandler.sgml
index 024ef9d..aa4bba3 100644
--- a/doc/src/sgml/plhandler.sgml
+++ b/doc/src/sgml/plhandler.sgml
@@ -178,7 +178,10 @@ CREATE LANGUAGE plsample
or updated a function written in the procedural language.
The passed-in OID is the OID of the function's <classname>pg_proc</>
row. The validator must fetch this row in the usual way, and do
- whatever checking is appropriate. Typical checks include verifying
+ whatever checking is appropriate.
+ First, call <function>CheckFunctionValidatorAccess()</> to diagnose
+ explicit calls to the validator that the user could not achieve through
+ <command>CREATE FUNCTION</>. Typical checks then include verifying
that the function's argument and result types are supported by the
language, and that the function's body is syntactically correct
in the language. If the validator finds the function to be okay,
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 3812408..3124868 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -718,6 +718,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
Datum tmp;
char *prosrc;
+ if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
+ PG_RETURN_VOID();
+
/*
* We do not honor check_function_bodies since it's unlikely the function
* name will be found later if it isn't there now.
@@ -763,6 +766,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
char *prosrc;
char *probin;
+ if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
+ PG_RETURN_VOID();
+
/*
* It'd be most consistent to skip the check if !check_function_bodies,
* but the purpose of that switch is to be helpful for pg_dump loading,
@@ -814,6 +820,9 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
bool haspolyarg;
int i;
+ if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
+ PG_RETURN_VOID();
+
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for function %u", funcoid);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 9ba6dd8..ea74b5e 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -997,7 +997,6 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
prorows);
}
-
/*
* Guts of function deletion.
*
diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
index 2ec63fa..8d6f183 100644
--- a/src/backend/utils/fmgr/fmgr.c
+++ b/src/backend/utils/fmgr/fmgr.c
@@ -24,6 +24,7 @@
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "pgstat.h"
+#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgrtab.h"
#include "utils/guc.h"
@@ -2445,3 +2446,86 @@ get_call_expr_arg_stable(Node *expr, int argnum)
return false;
}
+
+/*-------------------------------------------------------------------------
+ * Support routines for procedural language implementations
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * Verify that a validator is actually associated with the language of a
+ * particular function and that the user has access to both the language and
+ * the function. All validators should call this before doing anything
+ * substantial. Doing so ensures a user cannot achieve anything with explicit
+ * calls to validators that he could not achieve with CREATE FUNCTION or by
+ * simply calling an existing function.
+ *
+ * When this function returns false, callers should skip all validation work
+ * and call PG_RETURN_VOID(). This never happens at present; it is reserved
+ * for future expansion.
+ *
+ * In particular, checking that the validator corresponds to the function's
+ * language allows untrusted language validators to assume they process only
+ * superuser-chosen source code. (Untrusted language call handlers, by
+ * definition, do assume that.) A user lacking the USAGE language privilege
+ * would be unable to reach the validator through CREATE FUNCTION, so we check
+ * that to block explicit calls as well. Checking the EXECUTE privilege on
+ * the function is often superfluous, because most users can clone the
+ * function to get an executable copy. It is meaningful against users with no
+ * database TEMP right and no permanent schema CREATE right, thereby unable to
+ * create any function. Also, if the function tracks persistent state by
+ * function OID or name, validating the original function might permit more
+ * mischief than creating and validating a clone thereof.
+ */
+bool
+CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid)
+{
+ HeapTuple procTup;
+ HeapTuple langTup;
+ Form_pg_proc procStruct;
+ Form_pg_language langStruct;
+ AclResult aclresult;
+
+ /* Get the function's pg_proc entry */
+ procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionOid));
+ if (!HeapTupleIsValid(procTup))
+ elog(ERROR, "cache lookup failed for function %u", functionOid);
+ procStruct = (Form_pg_proc) GETSTRUCT(procTup);
+
+ /*
+ * Fetch pg_language entry to know if this is the correct validation
+ * function for that pg_proc entry.
+ */
+ langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(procStruct->prolang));
+ if (!HeapTupleIsValid(langTup))
+ elog(ERROR, "cache lookup failed for language %u", procStruct->prolang);
+ langStruct = (Form_pg_language) GETSTRUCT(langTup);
+
+ if (langStruct->lanvalidator != validatorOid)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("language validation function %u called for language %u instead of %u",
+ validatorOid, procStruct->prolang,
+ langStruct->lanvalidator)));
+
+ /* first validate that we have permissions to use the language */
+ aclresult = pg_language_aclcheck(procStruct->prolang, GetUserId(),
+ ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
+ NameStr(langStruct->lanname));
+
+ /*
+ * Check whether we are allowed to execute the function itself. If we can
+ * execute it, there should be no possible side-effect of
+ * compiling/validation that execution can't have.
+ */
+ aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_PROC, NameStr(procStruct->proname));
+
+ ReleaseSysCache(procTup);
+ ReleaseSysCache(langTup);
+
+ return true;
+}
diff --git a/src/include/fmgr.h b/src/include/fmgr.h
index 0a25776..f944cc6 100644
--- a/src/include/fmgr.h
+++ b/src/include/fmgr.h
@@ -624,6 +624,7 @@ extern Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
extern Oid get_call_expr_argtype(fmNodePtr expr, int argnum);
extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum);
extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum);
+extern bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid);
/*
* Routines in dfmgr.c
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 7c2aee9..49d50c4 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -1847,6 +1847,9 @@ plperl_validator(PG_FUNCTION_ARGS)
bool istrigger = false;
int i;
+ if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
+ PG_RETURN_VOID();
+
/* Get the new function's pg_proc entry */
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
if (!HeapTupleIsValid(tuple))
@@ -1926,6 +1929,7 @@ PG_FUNCTION_INFO_V1(plperlu_validator);
Datum
plperlu_validator(PG_FUNCTION_ARGS)
{
+ /* call plperl validator with our fcinfo so it gets our oid */
return plperl_validator(fcinfo);
}
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 022ec3f..00b1a6f 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -227,6 +227,9 @@ plpgsql_validator(PG_FUNCTION_ARGS)
bool istrigger = false;
int i;
+ if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
+ PG_RETURN_VOID();
+
/* Get the new function's pg_proc entry */
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid));
if (!HeapTupleIsValid(tuple))
diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c
index c4de762..3847847 100644
--- a/src/pl/plpython/plpy_main.c
+++ b/src/pl/plpython/plpy_main.c
@@ -159,6 +159,9 @@ plpython_validator(PG_FUNCTION_ARGS)
Form_pg_proc procStruct;
bool is_trigger;
+ if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
+ PG_RETURN_VOID();
+
if (!check_function_bodies)
{
PG_RETURN_VOID();
@@ -184,6 +187,7 @@ plpython_validator(PG_FUNCTION_ARGS)
Datum
plpython2_validator(PG_FUNCTION_ARGS)
{
+ /* call plpython validator with our fcinfo so it gets our oid */
return plpython_validator(fcinfo);
}
#endif /* PY_MAJOR_VERSION < 3 */
--
1.7.5.4
@@ -1,465 +0,0 @@
From f416622be81d1320417bbc7892fd562cae0dba72 Mon Sep 17 00:00:00 2001
From: Noah Misch <noah@leadboat.com>
Date: Mon, 17 Feb 2014 09:33:31 -0500
Subject: [PATCH] Fix handling of wide datetime input/output.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
commit f416622be81d1320417bbc7892fd562cae0dba72 REL9_2_STABLE
Many server functions use the MAXDATELEN constant to size a buffer for
parsing or displaying a datetime value. It was much too small for the
longest possible interval output and slightly too small for certain
valid timestamp input, particularly input with a long timezone name.
The long input was rejected needlessly; the long output caused
interval_out() to overrun its buffer. ECPG's pgtypes library has a copy
of the vulnerable functions, which bore the same vulnerabilities along
with some of its own. In contrast to the server, certain long inputs
caused stack overflow rather than failing cleanly. Back-patch to 8.4
(all supported versions).
Reported by Daniel Schüssler, reviewed by Tom Lane.
Security: CVE-2014-0063
Upstream-Status: Backport
Signed-off-by: Kai Kang <kai.kang@windriver.com>
---
src/include/utils/datetime.h | 17 +++++---
src/interfaces/ecpg/pgtypeslib/datetime.c | 4 +-
src/interfaces/ecpg/pgtypeslib/dt.h | 17 +++++---
src/interfaces/ecpg/pgtypeslib/dt_common.c | 44 ++++++++++++++------
src/interfaces/ecpg/pgtypeslib/interval.c | 2 +-
src/interfaces/ecpg/pgtypeslib/timestamp.c | 2 +-
.../ecpg/test/expected/pgtypeslib-dt_test2.c | 22 +++++++---
.../ecpg/test/expected/pgtypeslib-dt_test2.stdout | 19 ++++++++
src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc | 10 ++++
src/test/regress/expected/interval.out | 7 +++
src/test/regress/sql/interval.sql | 2 +
11 files changed, 111 insertions(+), 35 deletions(-)
diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h
index d73cc8d..4b805b6 100644
--- a/src/include/utils/datetime.h
+++ b/src/include/utils/datetime.h
@@ -188,12 +188,17 @@ struct tzEntry;
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_ALL_SECS_M)
-#define MAXDATELEN 63 /* maximum possible length of an input date
- * string (not counting tr. null) */
-#define MAXDATEFIELDS 25 /* maximum possible number of fields in a date
- * string */
-#define TOKMAXLEN 10 /* only this many chars are stored in
- * datetktbl */
+/*
+ * Working buffer size for input and output of interval, timestamp, etc.
+ * Inputs that need more working space will be rejected early. Longer outputs
+ * will overrun buffers, so this must suffice for all possible output. As of
+ * this writing, interval_out() needs the most space at ~90 bytes.
+ */
+#define MAXDATELEN 128
+/* maximum possible number of fields in a date string */
+#define MAXDATEFIELDS 25
+/* only this many chars are stored in datetktbl */
+#define TOKMAXLEN 10
/* keep this struct small; it gets used a lot */
typedef struct
diff --git a/src/interfaces/ecpg/pgtypeslib/datetime.c b/src/interfaces/ecpg/pgtypeslib/datetime.c
index 823626f..4adcd1e 100644
--- a/src/interfaces/ecpg/pgtypeslib/datetime.c
+++ b/src/interfaces/ecpg/pgtypeslib/datetime.c
@@ -61,14 +61,14 @@ PGTYPESdate_from_asc(char *str, char **endptr)
int nf;
char *field[MAXDATEFIELDS];
int ftype[MAXDATEFIELDS];
- char lowstr[MAXDATELEN + 1];
+ char lowstr[MAXDATELEN + MAXDATEFIELDS];
char *realptr;
char **ptr = (endptr != NULL) ? endptr : &realptr;
bool EuroDates = FALSE;
errno = 0;
- if (strlen(str) >= sizeof(lowstr))
+ if (strlen(str) > MAXDATELEN)
{
errno = PGTYPES_DATE_BAD_DATE;
return INT_MIN;
diff --git a/src/interfaces/ecpg/pgtypeslib/dt.h b/src/interfaces/ecpg/pgtypeslib/dt.h
index dfe6f9e..2780593 100644
--- a/src/interfaces/ecpg/pgtypeslib/dt.h
+++ b/src/interfaces/ecpg/pgtypeslib/dt.h
@@ -192,12 +192,17 @@ typedef double fsec_t;
#define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY))
#define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND))
-#define MAXDATELEN 63 /* maximum possible length of an input date
- * string (not counting tr. null) */
-#define MAXDATEFIELDS 25 /* maximum possible number of fields in a date
- * string */
-#define TOKMAXLEN 10 /* only this many chars are stored in
- * datetktbl */
+/*
+ * Working buffer size for input and output of interval, timestamp, etc.
+ * Inputs that need more working space will be rejected early. Longer outputs
+ * will overrun buffers, so this must suffice for all possible output. As of
+ * this writing, PGTYPESinterval_to_asc() needs the most space at ~90 bytes.
+ */
+#define MAXDATELEN 128
+/* maximum possible number of fields in a date string */
+#define MAXDATEFIELDS 25
+/* only this many chars are stored in datetktbl */
+#define TOKMAXLEN 10
/* keep this struct small; it gets used a lot */
typedef struct
diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c
index 6b89e4a..18178dd 100644
--- a/src/interfaces/ecpg/pgtypeslib/dt_common.c
+++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c
@@ -1171,15 +1171,22 @@ DecodeNumberField(int len, char *str, int fmask,
if ((cp = strchr(str, '.')) != NULL)
{
#ifdef HAVE_INT64_TIMESTAMP
- char fstr[MAXDATELEN + 1];
+ char fstr[7];
+ int i;
+
+ cp++;
/*
* OK, we have at most six digits to care about. Let's construct a
- * string and then do the conversion to an integer.
+ * string with those digits, zero-padded on the right, and then do
+ * the conversion to an integer.
+ *
+ * XXX This truncates the seventh digit, unlike rounding it as do
+ * the backend and the !HAVE_INT64_TIMESTAMP case.
*/
- strcpy(fstr, (cp + 1));
- strcpy(fstr + strlen(fstr), "000000");
- *(fstr + 6) = '\0';
+ for (i = 0; i < 6; i++)
+ fstr[i] = *cp != '\0' ? *cp++ : '0';
+ fstr[i] = '\0';
*fsec = strtol(fstr, NULL, 10);
#else
*fsec = strtod(cp, NULL);
@@ -1531,15 +1538,22 @@ DecodeTime(char *str, int *tmask, struct tm * tm, fsec_t *fsec)
else if (*cp == '.')
{
#ifdef HAVE_INT64_TIMESTAMP
- char fstr[MAXDATELEN + 1];
+ char fstr[7];
+ int i;
+
+ cp++;
/*
- * OK, we have at most six digits to work with. Let's construct a
- * string and then do the conversion to an integer.
+ * OK, we have at most six digits to care about. Let's construct a
+ * string with those digits, zero-padded on the right, and then do
+ * the conversion to an integer.
+ *
+ * XXX This truncates the seventh digit, unlike rounding it as do
+ * the backend and the !HAVE_INT64_TIMESTAMP case.
*/
- strncpy(fstr, (cp + 1), 7);
- strcpy(fstr + strlen(fstr), "000000");
- *(fstr + 6) = '\0';
+ for (i = 0; i < 6; i++)
+ fstr[i] = *cp != '\0' ? *cp++ : '0';
+ fstr[i] = '\0';
*fsec = strtol(fstr, &cp, 10);
#else
str = cp;
@@ -1665,6 +1679,9 @@ DecodePosixTimezone(char *str, int *tzp)
* DTK_NUMBER can hold date fields (yy.ddd)
* DTK_STRING can hold months (January) and time zones (PST)
* DTK_DATE can hold Posix time zones (GMT-8)
+ *
+ * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS
+ * bytes of space. On output, field[] entries will point into it.
*/
int
ParseDateTime(char *timestr, char *lowstr,
@@ -1677,7 +1694,10 @@ ParseDateTime(char *timestr, char *lowstr,
/* outer loop through fields */
while (*(*endstr) != '\0')
{
+ /* Record start of current field */
field[nf] = lp;
+ if (nf >= MAXDATEFIELDS)
+ return -1;
/* leading digit? then date or time */
if (isdigit((unsigned char) *(*endstr)))
@@ -1818,8 +1838,6 @@ ParseDateTime(char *timestr, char *lowstr,
/* force in a delimiter after each field */
*lp++ = '\0';
nf++;
- if (nf > MAXDATEFIELDS)
- return -1;
}
*numfields = nf;
diff --git a/src/interfaces/ecpg/pgtypeslib/interval.c b/src/interfaces/ecpg/pgtypeslib/interval.c
index bcc10ee..fdd8f49 100644
--- a/src/interfaces/ecpg/pgtypeslib/interval.c
+++ b/src/interfaces/ecpg/pgtypeslib/interval.c
@@ -1092,7 +1092,7 @@ PGTYPESinterval_from_asc(char *str, char **endptr)
tm->tm_sec = 0;
fsec = 0;
- if (strlen(str) >= sizeof(lowstr))
+ if (strlen(str) > MAXDATELEN)
{
errno = PGTYPES_INTVL_BAD_INTERVAL;
return NULL;
diff --git a/src/interfaces/ecpg/pgtypeslib/timestamp.c b/src/interfaces/ecpg/pgtypeslib/timestamp.c
index 7d3f7c8..4f91e63 100644
--- a/src/interfaces/ecpg/pgtypeslib/timestamp.c
+++ b/src/interfaces/ecpg/pgtypeslib/timestamp.c
@@ -297,7 +297,7 @@ PGTYPEStimestamp_from_asc(char *str, char **endptr)
char *realptr;
char **ptr = (endptr != NULL) ? endptr : &realptr;
- if (strlen(str) >= sizeof(lowstr))
+ if (strlen(str) > MAXDATELEN)
{
errno = PGTYPES_TS_BAD_TIMESTAMP;
return (noresult);
diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
index d3ebb0e..0ba1936 100644
--- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c
@@ -45,6 +45,15 @@ char *dates[] = { "19990108foobar",
"1999.008",
"J2451187",
"January 8, 99 BC",
+ /*
+ * Maximize space usage in ParseDateTime() with 25
+ * (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length.
+ */
+ "........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ /* 26 fields */
+ ".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
NULL };
/* do not conflict with libc "times" symbol */
@@ -52,6 +61,7 @@ static char *times[] = { "0:04",
"1:59 PDT",
"13:24:40 -8:00",
"13:24:40.495+3",
+ "13:24:40.123456789+3",
NULL };
char *intervals[] = { "1 minute",
@@ -73,22 +83,22 @@ main(void)
-#line 52 "dt_test2.pgc"
+#line 62 "dt_test2.pgc"
date date1 ;
-#line 53 "dt_test2.pgc"
+#line 63 "dt_test2.pgc"
timestamp ts1 , ts2 ;
-#line 54 "dt_test2.pgc"
+#line 64 "dt_test2.pgc"
char * text ;
-#line 55 "dt_test2.pgc"
+#line 65 "dt_test2.pgc"
interval * i1 ;
-#line 56 "dt_test2.pgc"
+#line 66 "dt_test2.pgc"
date * dc ;
/* exec sql end declare section */
-#line 57 "dt_test2.pgc"
+#line 67 "dt_test2.pgc"
int i, j;
diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout
index 24e9d26..9a4587b 100644
--- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout
+++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout
@@ -8,85 +8,104 @@ TS[3,0]: 1999-01-08 00:04:00
TS[3,1]: 1999-01-08 01:59:00
TS[3,2]: 1999-01-08 13:24:40
TS[3,3]: 1999-01-08 13:24:40.495
+TS[3,4]: 1999-01-08 13:24:40.123456
Date[4]: 1999-01-08 (N - F)
TS[4,0]: 1999-01-08 00:04:00
TS[4,1]: 1999-01-08 01:59:00
TS[4,2]: 1999-01-08 13:24:40
TS[4,3]: 1999-01-08 13:24:40.495
+TS[4,4]: 1999-01-08 13:24:40.123456
Date[5]: 1999-01-08 (N - F)
TS[5,0]: 1999-01-08 00:04:00
TS[5,1]: 1999-01-08 01:59:00
TS[5,2]: 1999-01-08 13:24:40
TS[5,3]: 1999-01-08 13:24:40.495
+TS[5,4]: 1999-01-08 13:24:40.123456
Date[6]: 1999-01-18 (N - F)
TS[6,0]: 1999-01-18 00:04:00
TS[6,1]: 1999-01-18 01:59:00
TS[6,2]: 1999-01-18 13:24:40
TS[6,3]: 1999-01-18 13:24:40.495
+TS[6,4]: 1999-01-18 13:24:40.123456
Date[7]: 2003-01-02 (N - F)
TS[7,0]: 2003-01-02 00:04:00
TS[7,1]: 2003-01-02 01:59:00
TS[7,2]: 2003-01-02 13:24:40
TS[7,3]: 2003-01-02 13:24:40.495
+TS[7,4]: 2003-01-02 13:24:40.123456
Date[8]: 1999-01-08 (N - F)
TS[8,0]: 1999-01-08 00:04:00
TS[8,1]: 1999-01-08 01:59:00
TS[8,2]: 1999-01-08 13:24:40
TS[8,3]: 1999-01-08 13:24:40.495
+TS[8,4]: 1999-01-08 13:24:40.123456
Date[9]: 1999-01-08 (N - F)
TS[9,0]: 1999-01-08 00:04:00
TS[9,1]: 1999-01-08 01:59:00
TS[9,2]: 1999-01-08 13:24:40
TS[9,3]: 1999-01-08 13:24:40.495
+TS[9,4]: 1999-01-08 13:24:40.123456
Date[10]: 1999-01-08 (N - F)
TS[10,0]: 1999-01-08 00:04:00
TS[10,1]: 1999-01-08 01:59:00
TS[10,2]: 1999-01-08 13:24:40
TS[10,3]: 1999-01-08 13:24:40.495
+TS[10,4]: 1999-01-08 13:24:40.123456
Date[11]: 1999-01-08 (N - F)
TS[11,0]: 1999-01-08 00:04:00
TS[11,1]: 1999-01-08 01:59:00
TS[11,2]: 1999-01-08 13:24:40
TS[11,3]: 1999-01-08 13:24:40.495
+TS[11,4]: 1999-01-08 13:24:40.123456
Date[12]: 1999-01-08 (N - F)
TS[12,0]: 1999-01-08 00:04:00
TS[12,1]: 1999-01-08 01:59:00
TS[12,2]: 1999-01-08 13:24:40
TS[12,3]: 1999-01-08 13:24:40.495
+TS[12,4]: 1999-01-08 13:24:40.123456
Date[13]: 2006-01-08 (N - F)
TS[13,0]: 2006-01-08 00:04:00
TS[13,1]: 2006-01-08 01:59:00
TS[13,2]: 2006-01-08 13:24:40
TS[13,3]: 2006-01-08 13:24:40.495
+TS[13,4]: 2006-01-08 13:24:40.123456
Date[14]: 1999-01-08 (N - F)
TS[14,0]: 1999-01-08 00:04:00
TS[14,1]: 1999-01-08 01:59:00
TS[14,2]: 1999-01-08 13:24:40
TS[14,3]: 1999-01-08 13:24:40.495
+TS[14,4]: 1999-01-08 13:24:40.123456
Date[15]: 1999-01-08 (N - F)
TS[15,0]: 1999-01-08 00:04:00
TS[15,1]: 1999-01-08 01:59:00
TS[15,2]: 1999-01-08 13:24:40
TS[15,3]: 1999-01-08 13:24:40.495
+TS[15,4]: 1999-01-08 13:24:40.123456
Date[16]: 1999-01-08 (N - F)
TS[16,0]: 1999-01-08 00:04:00
TS[16,1]: 1999-01-08 01:59:00
TS[16,2]: 1999-01-08 13:24:40
TS[16,3]: 1999-01-08 13:24:40.495
+TS[16,4]: 1999-01-08 13:24:40.123456
Date[17]: 1999-01-08 (N - F)
TS[17,0]: 1999-01-08 00:04:00
TS[17,1]: 1999-01-08 01:59:00
TS[17,2]: 1999-01-08 13:24:40
TS[17,3]: 1999-01-08 13:24:40.495
+TS[17,4]: 1999-01-08 13:24:40.123456
Date[18]: 1999-01-08 (N - F)
TS[18,0]: 1999-01-08 00:04:00
TS[18,1]: 1999-01-08 01:59:00
TS[18,2]: 1999-01-08 13:24:40
TS[18,3]: 1999-01-08 13:24:40.495
+TS[18,4]: 1999-01-08 13:24:40.123456
Date[19]: 0099-01-08 BC (N - F)
TS[19,0]: 0099-01-08 00:04:00 BC
TS[19,1]: 0099-01-08 01:59:00 BC
TS[19,2]: 0099-01-08 13:24:40 BC
+TS[19,4]: 0099-01-08 13:24:40.123456 BC
+Date[20]: - (N - T)
+Date[21]: - (N - T)
interval[0]: @ 1 min
interval_copy[0]: @ 1 min
interval[1]: @ 1 day 12 hours 59 mins 10 secs
diff --git a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
index 0edf012..a127dd9 100644
--- a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
+++ b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc
@@ -27,6 +27,15 @@ char *dates[] = { "19990108foobar",
"1999.008",
"J2451187",
"January 8, 99 BC",
+ /*
+ * Maximize space usage in ParseDateTime() with 25
+ * (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length.
+ */
+ "........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ /* 26 fields */
+ ".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
NULL };
/* do not conflict with libc "times" symbol */
@@ -34,6 +43,7 @@ static char *times[] = { "0:04",
"1:59 PDT",
"13:24:40 -8:00",
"13:24:40.495+3",
+ "13:24:40.123456789+3",
NULL };
char *intervals[] = { "1 minute",
diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out
index 3bf2211..99fd0ca 100644
--- a/src/test/regress/expected/interval.out
+++ b/src/test/regress/expected/interval.out
@@ -306,6 +306,13 @@ select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31
@ 4541 years 4 mons 4 days 17 mins 31 secs
(1 row)
+-- test long interval output
+select '100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval;
+ interval
+-------------------------------------------------------------------------------------------
+ @ 100000000 years 10 mons -1000000000 days -1000000000 hours -10 mins -10.000001 secs ago
+(1 row)
+
-- test justify_hours() and justify_days()
SELECT justify_hours(interval '6 months 3 days 52 hours 3 minutes 2 seconds') as "6 mons 5 days 4 hours 3 mins 2 seconds";
6 mons 5 days 4 hours 3 mins 2 seconds
diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql
index f1da4c2..7cee286 100644
--- a/src/test/regress/sql/interval.sql
+++ b/src/test/regress/sql/interval.sql
@@ -108,6 +108,8 @@ select avg(f1) from interval_tbl;
-- test long interval input
select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31 seconds'::interval;
+-- test long interval output
+select '100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval;
-- test justify_hours() and justify_days()
--
1.7.5.4
@@ -1,75 +0,0 @@
From 0ae841a98c21c53901d5bc9a9323a8cc800364f6 Mon Sep 17 00:00:00 2001
From: Noah Misch <noah@leadboat.com>
Date: Sat, 14 Jun 2014 10:52:25 -0400
Subject: [PATCH] Make pqsignal() available to pg_regress of ECPG and
isolation suites.
commit 0ae841a98c21c53901d5bc9a9323a8cc800364f6 REL9_2_STABLE
Commit 453a5d91d49e4d35054f92785d830df4067e10c1 made it available to the
src/test/regress build of pg_regress, but all pg_regress builds need the
same treatment. Patch 9.2 through 8.4; in 9.3 and later, pg_regress
gets pqsignal() via libpgport.
Upstream-Status: Backport
Signed-off-by: Kai Kang <kai.kang@windriver.com>
---
src/interfaces/ecpg/test/Makefile | 4 ++--
src/test/isolation/Makefile | 12 +++++++-----
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index e9944c6..4bb9525 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -47,10 +47,10 @@ clean distclean maintainer-clean:
all: pg_regress$(X)
-pg_regress$(X): pg_regress_ecpg.o $(top_builddir)/src/test/regress/pg_regress.o
+pg_regress$(X): pg_regress_ecpg.o $(top_builddir)/src/test/regress/pg_regress.o $(top_builddir)/src/test/regress/pqsignal.o
$(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) $^ $(LIBS) -o $@
-$(top_builddir)/src/test/regress/pg_regress.o:
+$(top_builddir)/src/test/regress/pg_regress.o $(top_builddir)/src/test/regress/pqsignal.o:
$(MAKE) -C $(dir $@) $(notdir $@)
# dependencies ensure that path changes propagate
diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile
index 46ea6f0..e20ba48 100644
--- a/src/test/isolation/Makefile
+++ b/src/test/isolation/Makefile
@@ -15,13 +15,15 @@ OBJS = specparse.o isolationtester.o
all: isolationtester$(X) pg_isolation_regress$(X)
-submake-regress:
+pg_regress.o:
$(MAKE) -C $(top_builddir)/src/test/regress pg_regress.o
-
-pg_regress.o: | submake-regress
rm -f $@ && $(LN_S) $(top_builddir)/src/test/regress/pg_regress.o .
-pg_isolation_regress$(X): isolation_main.o pg_regress.o
+pqsignal.o:
+ $(MAKE) -C $(top_builddir)/src/test/regress pqsignal.o
+ rm -f $@ && $(LN_S) $(top_builddir)/src/test/regress/pqsignal.o .
+
+pg_isolation_regress$(X): isolation_main.o pg_regress.o pqsignal.o
$(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@
isolationtester$(X): $(OBJS) | submake-libpq submake-libpgport
@@ -59,7 +61,7 @@ endif
# so do not clean them here
clean distclean:
rm -f isolationtester$(X) pg_isolation_regress$(X) $(OBJS) isolation_main.o
- rm -f pg_regress.o
+ rm -f pg_regress.o pqsignal.o
rm -rf $(pg_regress_clean_files)
maintainer-clean: distclean
--
1.7.5.4
@@ -1,393 +0,0 @@
From 655b665f745e2e07cf6936c6063b0250f5caa98f Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 17 Feb 2014 11:20:27 -0500
Subject: [PATCH] Prevent potential overruns of fixed-size buffers.
commit 655b665f745e2e07cf6936c6063b0250f5caa98f REL9_2_STABLE
Coverity identified a number of places in which it couldn't prove that a
string being copied into a fixed-size buffer would fit. We believe that
most, perhaps all of these are in fact safe, or are copying data that is
coming from a trusted source so that any overrun is not really a security
issue. Nonetheless it seems prudent to forestall any risk by using
strlcpy() and similar functions.
Fixes by Peter Eisentraut and Jozef Mlich based on Coverity reports.
In addition, fix a potential null-pointer-dereference crash in
contrib/chkpass. The crypt(3) function is defined to return NULL on
failure, but chkpass.c didn't check for that before using the result.
The main practical case in which this could be an issue is if libc is
configured to refuse to execute unapproved hashing algorithms (e.g.,
"FIPS mode"). This ideally should've been a separate commit, but
since it touches code adjacent to one of the buffer overrun changes,
I included it in this commit to avoid last-minute merge issues.
This issue was reported by Honza Horak.
Security: CVE-2014-0065 for buffer overruns, CVE-2014-0066 for crypt()
Upsteam-Status: Backport
Signed-off-by: Kai Kang <kai.kang@windriver.com>
---
contrib/chkpass/chkpass.c | 29 ++++++++++++++++++++++++++---
contrib/pg_standby/pg_standby.c | 2 +-
src/backend/access/transam/xlog.c | 10 +++++-----
src/backend/tsearch/spell.c | 2 +-
src/backend/utils/adt/datetime.c | 11 ++++++-----
src/bin/initdb/findtimezone.c | 4 ++--
src/bin/pg_basebackup/pg_basebackup.c | 8 ++++----
src/interfaces/ecpg/preproc/pgc.l | 2 +-
src/interfaces/libpq/fe-protocol2.c | 2 +-
src/interfaces/libpq/fe-protocol3.c | 2 +-
src/port/exec.c | 4 ++--
src/test/regress/pg_regress.c | 6 +++---
src/timezone/pgtz.c | 2 +-
13 files changed, 54 insertions(+), 30 deletions(-)
diff --git a/contrib/chkpass/chkpass.c b/contrib/chkpass/chkpass.c
index 0c9fec0..1795b8c 100644
--- a/contrib/chkpass/chkpass.c
+++ b/contrib/chkpass/chkpass.c
@@ -70,6 +70,7 @@ chkpass_in(PG_FUNCTION_ARGS)
char *str = PG_GETARG_CSTRING(0);
chkpass *result;
char mysalt[4];
+ char *crypt_output;
static char salt_chars[] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -92,7 +93,15 @@ chkpass_in(PG_FUNCTION_ARGS)
mysalt[1] = salt_chars[random() & 0x3f];
mysalt[2] = 0; /* technically the terminator is not necessary
* but I like to play safe */
- strcpy(result->password, crypt(str, mysalt));
+
+ crypt_output = crypt(str, mysalt);
+ if (crypt_output == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("crypt() failed")));
+
+ strlcpy(result->password, crypt_output, sizeof(result->password));
+
PG_RETURN_POINTER(result);
}
@@ -141,9 +150,16 @@ chkpass_eq(PG_FUNCTION_ARGS)
chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0);
text *a2 = PG_GETARG_TEXT_PP(1);
char str[9];
+ char *crypt_output;
text_to_cstring_buffer(a2, str, sizeof(str));
- PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) == 0);
+ crypt_output = crypt(str, a1->password);
+ if (crypt_output == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("crypt() failed")));
+
+ PG_RETURN_BOOL(strcmp(a1->password, crypt_output) == 0);
}
PG_FUNCTION_INFO_V1(chkpass_ne);
@@ -153,7 +169,14 @@ chkpass_ne(PG_FUNCTION_ARGS)
chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0);
text *a2 = PG_GETARG_TEXT_PP(1);
char str[9];
+ char *crypt_output;
text_to_cstring_buffer(a2, str, sizeof(str));
- PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) != 0);
+ crypt_output = crypt(str, a1->password);
+ if (crypt_output == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("crypt() failed")));
+
+ PG_RETURN_BOOL(strcmp(a1->password, crypt_output) != 0);
}
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c
index 84941ed..0f1e0c1 100644
--- a/contrib/pg_standby/pg_standby.c
+++ b/contrib/pg_standby/pg_standby.c
@@ -338,7 +338,7 @@ SetWALFileNameForCleanup(void)
if (strcmp(restartWALFileName, nextWALFileName) > 0)
return false;
- strcpy(exclusiveCleanupFileName, restartWALFileName);
+ strlcpy(exclusiveCleanupFileName, restartWALFileName, sizeof(exclusiveCleanupFileName));
return true;
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index d639c4a..49bb453 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -3017,7 +3017,7 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname)
xlogfpath, oldpath)));
}
#else
- strncpy(oldpath, xlogfpath, MAXPGPATH);
+ strlcpy(oldpath, xlogfpath, MAXPGPATH);
#endif
if (unlink(oldpath) != 0)
ereport(FATAL,
@@ -5913,7 +5913,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
recordXtime = recordRestorePointData->rp_time;
- strncpy(recordRPName, recordRestorePointData->rp_name, MAXFNAMELEN);
+ strlcpy(recordRPName, recordRestorePointData->rp_name, MAXFNAMELEN);
}
else
return false;
@@ -6008,7 +6008,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis)
}
else
{
- strncpy(recoveryStopName, recordRPName, MAXFNAMELEN);
+ strlcpy(recoveryStopName, recordRPName, MAXFNAMELEN);
ereport(LOG,
(errmsg("recovery stopping at restore point \"%s\", time %s",
@@ -6348,7 +6348,7 @@ StartupXLOG(void)
* see them
*/
XLogCtl->RecoveryTargetTLI = recoveryTargetTLI;
- strncpy(XLogCtl->archiveCleanupCommand,
+ strlcpy(XLogCtl->archiveCleanupCommand,
archiveCleanupCommand ? archiveCleanupCommand : "",
sizeof(XLogCtl->archiveCleanupCommand));
@@ -8760,7 +8760,7 @@ XLogRestorePoint(const char *rpName)
xl_restore_point xlrec;
xlrec.rp_time = GetCurrentTimestamp();
- strncpy(xlrec.rp_name, rpName, MAXFNAMELEN);
+ strlcpy(xlrec.rp_name, rpName, MAXFNAMELEN);
rdata.buffer = InvalidBuffer;
rdata.data = (char *) &xlrec;
diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c
index 449aa6a..4acc33e 100644
--- a/src/backend/tsearch/spell.c
+++ b/src/backend/tsearch/spell.c
@@ -255,7 +255,7 @@ NIAddSpell(IspellDict *Conf, const char *word, const char *flag)
}
Conf->Spell[Conf->nspell] = (SPELL *) tmpalloc(SPELLHDRSZ + strlen(word) + 1);
strcpy(Conf->Spell[Conf->nspell]->word, word);
- strncpy(Conf->Spell[Conf->nspell]->p.flag, flag, MAXFLAGLEN);
+ strlcpy(Conf->Spell[Conf->nspell]->p.flag, flag, MAXFLAGLEN);
Conf->nspell++;
}
diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c
index 4763a6f..4105f17 100644
--- a/src/backend/utils/adt/datetime.c
+++ b/src/backend/utils/adt/datetime.c
@@ -90,10 +90,10 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
* Note that this table must be strictly alphabetically ordered to allow an
* O(ln(N)) search algorithm to be used.
*
- * The text field is NOT guaranteed to be NULL-terminated.
+ * The token field is NOT guaranteed to be NULL-terminated.
*
- * To keep this table reasonably small, we divide the lexval for TZ and DTZ
- * entries by 15 (so they are on 15 minute boundaries) and truncate the text
+ * To keep this table reasonably small, we divide the value for TZ and DTZ
+ * entries by 15 (so they are on 15 minute boundaries) and truncate the token
* field at TOKMAXLEN characters.
* Formerly, we divided by 10 rather than 15 but there are a few time zones
* which are 30 or 45 minutes away from an even hour, most are on an hour
@@ -108,7 +108,7 @@ static datetkn *timezonetktbl = NULL;
static int sztimezonetktbl = 0;
static const datetkn datetktbl[] = {
-/* text, token, lexval */
+ /* token, type, value */
{EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
{DA_D, ADBC, AD}, /* "ad" for years > 0 */
{"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
@@ -188,7 +188,7 @@ static const datetkn datetktbl[] = {
static int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
static datetkn deltatktbl[] = {
- /* text, token, lexval */
+ /* token, type, value */
{"@", IGNORE_DTF, 0}, /* postgres relative prefix */
{DAGO, AGO, 0}, /* "ago" indicates negative time offset */
{"c", UNITS, DTK_CENTURY}, /* "century" relative */
@@ -4201,6 +4201,7 @@ ConvertTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl,
tbl->numabbrevs = n;
for (i = 0; i < n; i++)
{
+ /* do NOT use strlcpy here; token field need not be null-terminated */
strncpy(newtbl[i].token, abbrevs[i].abbrev, TOKMAXLEN);
newtbl[i].type = abbrevs[i].is_dst ? DTZ : TZ;
TOVAL(&newtbl[i], abbrevs[i].offset / MINS_PER_HOUR);
diff --git a/src/bin/initdb/findtimezone.c b/src/bin/initdb/findtimezone.c
index 6d6f96a..6d38151 100644
--- a/src/bin/initdb/findtimezone.c
+++ b/src/bin/initdb/findtimezone.c
@@ -68,7 +68,7 @@ pg_open_tzfile(const char *name, char *canonname)
if (canonname)
strlcpy(canonname, name, TZ_STRLEN_MAX + 1);
- strcpy(fullname, pg_TZDIR());
+ strlcpy(fullname, pg_TZDIR(), sizeof(fullname));
if (strlen(fullname) + 1 + strlen(name) >= MAXPGPATH)
return -1; /* not gonna fit */
strcat(fullname, "/");
@@ -375,7 +375,7 @@ identify_system_timezone(void)
}
/* Search for the best-matching timezone file */
- strcpy(tmptzdir, pg_TZDIR());
+ strlcpy(tmptzdir, pg_TZDIR(), sizeof(tmptzdir));
bestscore = -1;
resultbuf[0] = '\0';
scan_available_timezones(tmptzdir, tmptzdir + strlen(tmptzdir) + 1,
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 9d840a1..26cc758 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -735,9 +735,9 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum)
FILE *file = NULL;
if (PQgetisnull(res, rownum, 0))
- strcpy(current_path, basedir);
+ strlcpy(current_path, basedir, sizeof(current_path));
else
- strcpy(current_path, PQgetvalue(res, rownum, 1));
+ strlcpy(current_path, PQgetvalue(res, rownum, 1), sizeof(current_path));
/*
* Get the COPY data
@@ -1053,7 +1053,7 @@ BaseBackup(void)
progname);
disconnect_and_exit(1);
}
- strcpy(xlogstart, PQgetvalue(res, 0, 0));
+ strlcpy(xlogstart, PQgetvalue(res, 0, 0), sizeof(xlogstart));
if (verbose && includewal)
fprintf(stderr, "transaction log start point: %s\n", xlogstart);
PQclear(res);
@@ -1153,7 +1153,7 @@ BaseBackup(void)
progname);
disconnect_and_exit(1);
}
- strcpy(xlogend, PQgetvalue(res, 0, 0));
+ strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend));
if (verbose && includewal)
fprintf(stderr, "transaction log end point: %s\n", xlogend);
PQclear(res);
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l
index f2e7edd..7ae8556 100644
--- a/src/interfaces/ecpg/preproc/pgc.l
+++ b/src/interfaces/ecpg/preproc/pgc.l
@@ -1315,7 +1315,7 @@ parse_include(void)
yytext[i] = '\0';
memmove(yytext, yytext+1, strlen(yytext));
- strncpy(inc_file, yytext, sizeof(inc_file));
+ strlcpy(inc_file, yytext, sizeof(inc_file));
yyin = fopen(inc_file, "r");
if (!yyin)
{
diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c
index 1ba5885..af4c412 100644
--- a/src/interfaces/libpq/fe-protocol2.c
+++ b/src/interfaces/libpq/fe-protocol2.c
@@ -500,7 +500,7 @@ pqParseInput2(PGconn *conn)
if (!conn->result)
return;
}
- strncpy(conn->result->cmdStatus, conn->workBuffer.data,
+ strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
CMDSTATUS_LEN);
checkXactStatus(conn, conn->workBuffer.data);
conn->asyncStatus = PGASYNC_READY;
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index d289f82..6f8a470 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -206,7 +206,7 @@ pqParseInput3(PGconn *conn)
if (!conn->result)
return;
}
- strncpy(conn->result->cmdStatus, conn->workBuffer.data,
+ strlcpy(conn->result->cmdStatus, conn->workBuffer.data,
CMDSTATUS_LEN);
conn->asyncStatus = PGASYNC_READY;
break;
diff --git a/src/port/exec.c b/src/port/exec.c
index c79e8ba..0726dbe 100644
--- a/src/port/exec.c
+++ b/src/port/exec.c
@@ -66,7 +66,7 @@ validate_exec(const char *path)
if (strlen(path) >= strlen(".exe") &&
pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
{
- strcpy(path_exe, path);
+ strlcpy(path_exe, path, sizeof(path_exe) - 4);
strcat(path_exe, ".exe");
path = path_exe;
}
@@ -275,7 +275,7 @@ resolve_symlinks(char *path)
}
/* must copy final component out of 'path' temporarily */
- strcpy(link_buf, fname);
+ strlcpy(link_buf, fname, sizeof(link_buf));
if (!getcwd(path, MAXPGPATH))
{
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index d991a5c..a6466eb 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -1233,7 +1233,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
*/
platform_expectfile = get_expectfile(testname, resultsfile);
- strcpy(expectfile, default_expectfile);
+ strlcpy(expectfile, default_expectfile, sizeof(expectfile));
if (platform_expectfile)
{
/*
@@ -1288,7 +1288,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
{
/* This diff was a better match than the last one */
best_line_count = l;
- strcpy(best_expect_file, alt_expectfile);
+ strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file));
}
free(alt_expectfile);
}
@@ -1316,7 +1316,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul
{
/* This diff was a better match than the last one */
best_line_count = l;
- strcpy(best_expect_file, default_expectfile);
+ strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file));
}
}
diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c
index d5bc83e..80c5635 100644
--- a/src/timezone/pgtz.c
+++ b/src/timezone/pgtz.c
@@ -83,7 +83,7 @@ pg_open_tzfile(const char *name, char *canonname)
* Loop to split the given name into directory levels; for each level,
* search using scan_directory_ci().
*/
- strcpy(fullname, pg_TZDIR());
+ strlcpy(fullname, pg_TZDIR(), sizeof(fullname));
orignamelen = fullnamelen = strlen(fullname);
fname = name;
for (;;)
--
1.7.5.4
@@ -0,0 +1,31 @@
[PATCH] not check libperl under cross compiling
Upstream-Status: Inappropriate [configuration]
libperl ldflags returned by PGAC_CHECK_PERL_EMBED_LDFLAGS are native,
can not be used to check target library.
postpresql has the dependency on perl, so not need to check libperl
again, like in postgresql-9.2.4
Signed-off-by: Roy Li <rongqing.li@windriver.com>
---
configure.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.in b/configure.in
index ae1a5a0..9a0970d 100644
--- a/configure.in
+++ b/configure.in
@@ -1877,7 +1877,7 @@ if test "$with_tcl" = yes; then
fi
# check for <perl.h>
-if test "$with_perl" = yes; then
+if test "$with_perl" = yes && test "$cross_compiling" = no; then
ac_save_CPPFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS -I$perl_archlibexp/CORE"
AC_CHECK_HEADER(perl.h, [], [AC_MSG_ERROR([header file <perl.h> is required for Perl])],
--
1.9.1
@@ -4,12 +4,13 @@ Index: postgresql-9.2.4/configure.in
+++ postgresql-9.2.4/configure.in
@@ -19,10 +19,6 @@ m4_pattern_forbid(^PGAC_)dnl to catch un
AC_INIT([PostgreSQL], [9.2.4], [pgsql-bugs@postgresql.org])
AC_INIT([PostgreSQL], [9.4.2], [pgsql-bugs@postgresql.org])
-m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.63], [], [m4_fatal([Autoconf version 2.63 is required.
-m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.69], [], [m4_fatal([Autoconf version 2.69 is required.
-Untested combinations of 'autoconf' and PostgreSQL versions are not
-recommended. You can remove the check from 'configure.in' but it is then
-your responsibility whether the result works or not.])])
AC_COPYRIGHT([Copyright (c) 1996-2012, PostgreSQL Global Development Group])
AC_COPYRIGHT([Copyright (c) 1996-2014, PostgreSQL Global Development Group])
AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c])
AC_CONFIG_AUX_DIR(config)
@@ -31,13 +31,6 @@ SRC_URI = "http://ftp.postgresql.org/pub/source/v${PV}/${BP}.tar.bz2 \
file://postgresql-setup \
file://postgresql.service \
file://0001-Use-pkg-config-for-libxml2-detection.patch \
file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \
file://0003-Shore-up-ADMIN-OPTION-restrictions.patch \
file://0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch \
file://0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch \
file://0006-Fix-handling-of-wide-datetime-input-output.patch \
file://0007-Make-pqsignal-available-to-pg_regress-of-ECPG-and-is.patch \
file://0008-Prevent-potential-overruns-of-fixed-size-buffers.patch \
"
LEAD_SONAME = "libpq.so"
@@ -76,7 +69,6 @@ PACKAGECONFIG[perl] = "--with-perl,--without-perl,perl,perl"
EXTRA_OECONF += "--enable-thread-safety --disable-rpath \
--datadir=${datadir}/${BPN} \
--sysconfdir=${sysconfdir}/${BPN} \
--without-krb5 \
"
EXTRA_OECONF_sh4 += "--disable-spinlocks"
EXTRA_OECONF_aarch64 += "--disable-spinlocks"
@@ -1,13 +0,0 @@
require postgresql.inc
LIC_FILES_CHKSUM = "file://COPYRIGHT;md5=ab55a5887d3f8ba77d0fd7db787e4bab"
PR = "${INC_PR}.0"
SRC_URI += "\
file://remove.autoconf.version.check.patch \
file://ecpg-parallel-make-fix.patch \
"
SRC_URI[md5sum] = "6ee5bb53b97da7c6ad9cb0825d3300dd"
SRC_URI[sha256sum] = "d97dd918a88a4449225998f46aafa85216a3f89163a3411830d6890507ffae93"
@@ -0,0 +1,13 @@
require postgresql.inc
LIC_FILES_CHKSUM = "file://COPYRIGHT;md5=7d847a9b446ddfe187acfac664189672"
PR = "${INC_PR}.0"
SRC_URI += "\
file://remove.autoconf.version.check.patch \
file://not-check-libperl.patch \
"
SRC_URI[md5sum] = "b6369156607a4fd88f21af6fec0f30b9"
SRC_URI[sha256sum] = "81fda191c165ba1d25d75cd0166ece5abdcb4a7f5eca01b349371e279ebb4d11"