diff options
author | Tudor Florea <tudor.florea@enea.com> | 2015-10-08 22:51:41 +0200 |
---|---|---|
committer | Tudor Florea <tudor.florea@enea.com> | 2015-10-08 22:51:41 +0200 |
commit | 1219bf8a90a7bf8cd3a5363551ef635d51e8fc8e (patch) | |
tree | a21a5fc103bb3bd65ecd85ed22be5228fc54e447 /meta-oe/recipes-support/postgresql | |
download | meta-openembedded-1219bf8a90a7bf8cd3a5363551ef635d51e8fc8e.tar.gz |
initial commit for Enea Linux 5.0 arm
Signed-off-by: Tudor Florea <tudor.florea@enea.com>
Diffstat (limited to 'meta-oe/recipes-support/postgresql')
18 files changed, 3970 insertions, 0 deletions
diff --git a/meta-oe/recipes-support/postgresql/files/0001-Use-pkg-config-for-libxml2-detection.patch b/meta-oe/recipes-support/postgresql/files/0001-Use-pkg-config-for-libxml2-detection.patch new file mode 100644 index 000000000..d08ec6af1 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0001-Use-pkg-config-for-libxml2-detection.patch | |||
@@ -0,0 +1,43 @@ | |||
1 | From d52e330be895bb8c5f0fb3e2884766acbd942a85 Mon Sep 17 00:00:00 2001 | ||
2 | From: Philip Balister <philip@balister.org> | ||
3 | Date: Tue, 1 Jul 2014 09:40:44 -0400 | ||
4 | Subject: [PATCH] Use pkg-config for libxml2 detection. | ||
5 | |||
6 | Upstream-Status: Inappropriate [configuration] | ||
7 | |||
8 | xml2-config does not work. Use pkgconfig to set CPPFLAGS and LIBS. | ||
9 | |||
10 | Signed-off-by: Philip Balister <philip@balister.org> | ||
11 | --- | ||
12 | configure.in | 15 ++------------- | ||
13 | 1 file changed, 2 insertions(+), 13 deletions(-) | ||
14 | |||
15 | diff --git a/configure.in b/configure.in | ||
16 | index f8bf466..1f4fabf 100644 | ||
17 | --- a/configure.in | ||
18 | +++ b/configure.in | ||
19 | @@ -734,19 +734,8 @@ PGAC_ARG_BOOL(with, libxml, no, [build with XML support], | ||
20 | [AC_DEFINE([USE_LIBXML], 1, [Define to 1 to build with XML support. (--with-libxml)])]) | ||
21 | |||
22 | if test "$with_libxml" = yes ; then | ||
23 | - AC_CHECK_PROGS(XML2_CONFIG, xml2-config) | ||
24 | - if test -n "$XML2_CONFIG"; then | ||
25 | - for pgac_option in `$XML2_CONFIG --cflags`; do | ||
26 | - case $pgac_option in | ||
27 | - -I*|-D*) CPPFLAGS="$CPPFLAGS $pgac_option";; | ||
28 | - esac | ||
29 | - done | ||
30 | - for pgac_option in `$XML2_CONFIG --libs`; do | ||
31 | - case $pgac_option in | ||
32 | - -L*) LDFLAGS="$LDFLAGS $pgac_option";; | ||
33 | - esac | ||
34 | - done | ||
35 | - fi | ||
36 | + CPPFLAGS="$CPPFLAGS `pkg-config --short-errors --print-errors --cflags "libxml-2.0" 2>&1`" | ||
37 | + LIBS="`pkg-config --short-errors --print-errors --libs "libxml-2.0" 2>&1` $LIBS" | ||
38 | fi | ||
39 | |||
40 | AC_SUBST(with_libxml) | ||
41 | -- | ||
42 | 1.8.3.1 | ||
43 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch b/meta-oe/recipes-support/postgresql/files/0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch new file mode 100644 index 000000000..c8b4c80aa --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch | |||
@@ -0,0 +1,605 @@ | |||
1 | From 12bbce15d93d7692ddff1405aa04b67f8a327f57 Mon Sep 17 00:00:00 2001 | ||
2 | From: Noah Misch <noah@leadboat.com> | ||
3 | Date: Mon, 17 Feb 2014 09:33:31 -0500 | ||
4 | Subject: [PATCH] Predict integer overflow to avoid buffer overruns. | ||
5 | |||
6 | commit 12bbce15d93d7692ddff1405aa04b67f8a327f57 REL9_2_STABLE | ||
7 | |||
8 | Several functions, mostly type input functions, calculated an allocation | ||
9 | size such that the calculation wrapped to a small positive value when | ||
10 | arguments implied a sufficiently-large requirement. Writes past the end | ||
11 | of the inadvertent small allocation followed shortly thereafter. | ||
12 | Coverity identified the path_in() vulnerability; code inspection led to | ||
13 | the rest. In passing, add check_stack_depth() to prevent stack overflow | ||
14 | in related functions. | ||
15 | |||
16 | Back-patch to 8.4 (all supported versions). The non-comment hstore | ||
17 | changes touch code that did not exist in 8.4, so that part stops at 9.0. | ||
18 | |||
19 | Noah Misch and Heikki Linnakangas, reviewed by Tom Lane. | ||
20 | |||
21 | Security: CVE-2014-0064 | ||
22 | |||
23 | Upstream-Status: Backport | ||
24 | |||
25 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
26 | --- | ||
27 | contrib/hstore/hstore.h | 15 ++++++++++++--- | ||
28 | contrib/hstore/hstore_io.c | 21 +++++++++++++++++++++ | ||
29 | contrib/hstore/hstore_op.c | 15 +++++++++++++++ | ||
30 | contrib/intarray/_int.h | 2 ++ | ||
31 | contrib/intarray/_int_bool.c | 9 +++++++++ | ||
32 | contrib/ltree/ltree.h | 3 +++ | ||
33 | contrib/ltree/ltree_io.c | 11 +++++++++++ | ||
34 | contrib/ltree/ltxtquery_io.c | 13 ++++++++++++- | ||
35 | src/backend/utils/adt/geo_ops.c | 30 ++++++++++++++++++++++++++++-- | ||
36 | src/backend/utils/adt/tsquery.c | 7 ++++++- | ||
37 | src/backend/utils/adt/tsquery_util.c | 5 +++++ | ||
38 | src/backend/utils/adt/txid.c | 15 +++++---------- | ||
39 | src/backend/utils/adt/varbit.c | 32 ++++++++++++++++++++++++++++++-- | ||
40 | src/include/tsearch/ts_type.h | 3 +++ | ||
41 | src/include/utils/varbit.h | 7 +++++++ | ||
42 | 15 files changed, 169 insertions(+), 19 deletions(-) | ||
43 | |||
44 | diff --git a/contrib/hstore/hstore.h b/contrib/hstore/hstore.h | ||
45 | index 8906397..4e55f6e 100644 | ||
46 | --- a/contrib/hstore/hstore.h | ||
47 | +++ b/contrib/hstore/hstore.h | ||
48 | @@ -49,9 +49,12 @@ typedef struct | ||
49 | } HStore; | ||
50 | |||
51 | /* | ||
52 | - * it's not possible to get more than 2^28 items into an hstore, | ||
53 | - * so we reserve the top few bits of the size field. See hstore_compat.c | ||
54 | - * for one reason why. Some bits are left for future use here. | ||
55 | + * It's not possible to get more than 2^28 items into an hstore, so we reserve | ||
56 | + * the top few bits of the size field. See hstore_compat.c for one reason | ||
57 | + * why. Some bits are left for future use here. MaxAllocSize makes the | ||
58 | + * practical count limit slightly more than 2^28 / 3, or INT_MAX / 24, the | ||
59 | + * limit for an hstore full of 4-byte keys and null values. Therefore, we | ||
60 | + * don't explicitly check the format-imposed limit. | ||
61 | */ | ||
62 | #define HS_FLAG_NEWVERSION 0x80000000 | ||
63 | |||
64 | @@ -59,6 +62,12 @@ typedef struct | ||
65 | #define HS_SETCOUNT(hsp_,c_) ((hsp_)->size_ = (c_) | HS_FLAG_NEWVERSION) | ||
66 | |||
67 | |||
68 | +/* | ||
69 | + * "x" comes from an existing HS_COUNT() (as discussed, <= INT_MAX/24) or a | ||
70 | + * Pairs array length (due to MaxAllocSize, <= INT_MAX/40). "lenstr" is no | ||
71 | + * more than INT_MAX, that extreme case arising in hstore_from_arrays(). | ||
72 | + * Therefore, this calculation is limited to about INT_MAX / 5 + INT_MAX. | ||
73 | + */ | ||
74 | #define HSHRDSIZE (sizeof(HStore)) | ||
75 | #define CALCDATASIZE(x, lenstr) ( (x) * 2 * sizeof(HEntry) + HSHRDSIZE + (lenstr) ) | ||
76 | |||
77 | diff --git a/contrib/hstore/hstore_io.c b/contrib/hstore/hstore_io.c | ||
78 | index dde6c4b..5bcdc95 100644 | ||
79 | --- a/contrib/hstore/hstore_io.c | ||
80 | +++ b/contrib/hstore/hstore_io.c | ||
81 | @@ -9,6 +9,7 @@ | ||
82 | #include "funcapi.h" | ||
83 | #include "libpq/pqformat.h" | ||
84 | #include "utils/lsyscache.h" | ||
85 | +#include "utils/memutils.h" | ||
86 | #include "utils/typcache.h" | ||
87 | |||
88 | #include "hstore.h" | ||
89 | @@ -437,6 +438,11 @@ hstore_recv(PG_FUNCTION_ARGS) | ||
90 | PG_RETURN_POINTER(out); | ||
91 | } | ||
92 | |||
93 | + if (pcount < 0 || pcount > MaxAllocSize / sizeof(Pairs)) | ||
94 | + ereport(ERROR, | ||
95 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
96 | + errmsg("number of pairs (%d) exceeds the maximum allowed (%d)", | ||
97 | + pcount, (int) (MaxAllocSize / sizeof(Pairs))))); | ||
98 | pairs = palloc(pcount * sizeof(Pairs)); | ||
99 | |||
100 | for (i = 0; i < pcount; ++i) | ||
101 | @@ -552,6 +558,13 @@ hstore_from_arrays(PG_FUNCTION_ARGS) | ||
102 | TEXTOID, -1, false, 'i', | ||
103 | &key_datums, &key_nulls, &key_count); | ||
104 | |||
105 | + /* see discussion in hstoreArrayToPairs() */ | ||
106 | + if (key_count > MaxAllocSize / sizeof(Pairs)) | ||
107 | + ereport(ERROR, | ||
108 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
109 | + errmsg("number of pairs (%d) exceeds the maximum allowed (%d)", | ||
110 | + key_count, (int) (MaxAllocSize / sizeof(Pairs))))); | ||
111 | + | ||
112 | /* value_array might be NULL */ | ||
113 | |||
114 | if (PG_ARGISNULL(1)) | ||
115 | @@ -674,6 +687,13 @@ hstore_from_array(PG_FUNCTION_ARGS) | ||
116 | |||
117 | count = in_count / 2; | ||
118 | |||
119 | + /* see discussion in hstoreArrayToPairs() */ | ||
120 | + if (count > MaxAllocSize / sizeof(Pairs)) | ||
121 | + ereport(ERROR, | ||
122 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
123 | + errmsg("number of pairs (%d) exceeds the maximum allowed (%d)", | ||
124 | + count, (int) (MaxAllocSize / sizeof(Pairs))))); | ||
125 | + | ||
126 | pairs = palloc(count * sizeof(Pairs)); | ||
127 | |||
128 | for (i = 0; i < count; ++i) | ||
129 | @@ -805,6 +825,7 @@ hstore_from_record(PG_FUNCTION_ARGS) | ||
130 | my_extra->ncolumns = ncolumns; | ||
131 | } | ||
132 | |||
133 | + Assert(ncolumns <= MaxTupleAttributeNumber); /* thus, no overflow */ | ||
134 | pairs = palloc(ncolumns * sizeof(Pairs)); | ||
135 | |||
136 | if (rec) | ||
137 | diff --git a/contrib/hstore/hstore_op.c b/contrib/hstore/hstore_op.c | ||
138 | index fee2c3c..8de175a 100644 | ||
139 | --- a/contrib/hstore/hstore_op.c | ||
140 | +++ b/contrib/hstore/hstore_op.c | ||
141 | @@ -7,6 +7,7 @@ | ||
142 | #include "catalog/pg_type.h" | ||
143 | #include "funcapi.h" | ||
144 | #include "utils/builtins.h" | ||
145 | +#include "utils/memutils.h" | ||
146 | |||
147 | #include "hstore.h" | ||
148 | |||
149 | @@ -89,6 +90,19 @@ hstoreArrayToPairs(ArrayType *a, int *npairs) | ||
150 | return NULL; | ||
151 | } | ||
152 | |||
153 | + /* | ||
154 | + * A text array uses at least eight bytes per element, so any overflow in | ||
155 | + * "key_count * sizeof(Pairs)" is small enough for palloc() to catch. | ||
156 | + * However, credible improvements to the array format could invalidate | ||
157 | + * that assumption. Therefore, use an explicit check rather than relying | ||
158 | + * on palloc() to complain. | ||
159 | + */ | ||
160 | + if (key_count > MaxAllocSize / sizeof(Pairs)) | ||
161 | + ereport(ERROR, | ||
162 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
163 | + errmsg("number of pairs (%d) exceeds the maximum allowed (%d)", | ||
164 | + key_count, (int) (MaxAllocSize / sizeof(Pairs))))); | ||
165 | + | ||
166 | key_pairs = palloc(sizeof(Pairs) * key_count); | ||
167 | |||
168 | for (i = 0, j = 0; i < key_count; i++) | ||
169 | @@ -647,6 +661,7 @@ hstore_slice_to_hstore(PG_FUNCTION_ARGS) | ||
170 | PG_RETURN_POINTER(out); | ||
171 | } | ||
172 | |||
173 | + /* hstoreArrayToPairs() checked overflow */ | ||
174 | out_pairs = palloc(sizeof(Pairs) * nkeys); | ||
175 | bufsiz = 0; | ||
176 | |||
177 | diff --git a/contrib/intarray/_int.h b/contrib/intarray/_int.h | ||
178 | index 11c0698..755cd9e 100644 | ||
179 | --- a/contrib/intarray/_int.h | ||
180 | +++ b/contrib/intarray/_int.h | ||
181 | @@ -5,6 +5,7 @@ | ||
182 | #define ___INT_H__ | ||
183 | |||
184 | #include "utils/array.h" | ||
185 | +#include "utils/memutils.h" | ||
186 | |||
187 | /* number ranges for compression */ | ||
188 | #define MAXNUMRANGE 100 | ||
189 | @@ -137,6 +138,7 @@ typedef struct QUERYTYPE | ||
190 | |||
191 | #define HDRSIZEQT offsetof(QUERYTYPE, items) | ||
192 | #define COMPUTESIZE(size) ( HDRSIZEQT + (size) * sizeof(ITEM) ) | ||
193 | +#define QUERYTYPEMAXITEMS ((MaxAllocSize - HDRSIZEQT) / sizeof(ITEM)) | ||
194 | #define GETQUERY(x) ( (x)->items ) | ||
195 | |||
196 | /* "type" codes for ITEM */ | ||
197 | diff --git a/contrib/intarray/_int_bool.c b/contrib/intarray/_int_bool.c | ||
198 | index 4e63f6d..62294d1 100644 | ||
199 | --- a/contrib/intarray/_int_bool.c | ||
200 | +++ b/contrib/intarray/_int_bool.c | ||
201 | @@ -451,6 +451,9 @@ boolop(PG_FUNCTION_ARGS) | ||
202 | static void | ||
203 | findoprnd(ITEM *ptr, int4 *pos) | ||
204 | { | ||
205 | + /* since this function recurses, it could be driven to stack overflow. */ | ||
206 | + check_stack_depth(); | ||
207 | + | ||
208 | #ifdef BS_DEBUG | ||
209 | elog(DEBUG3, (ptr[*pos].type == OPR) ? | ||
210 | "%d %c" : "%d %d", *pos, ptr[*pos].val); | ||
211 | @@ -511,7 +514,13 @@ bqarr_in(PG_FUNCTION_ARGS) | ||
212 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||
213 | errmsg("empty query"))); | ||
214 | |||
215 | + if (state.num > QUERYTYPEMAXITEMS) | ||
216 | + ereport(ERROR, | ||
217 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
218 | + errmsg("number of query items (%d) exceeds the maximum allowed (%d)", | ||
219 | + state.num, (int) QUERYTYPEMAXITEMS))); | ||
220 | commonlen = COMPUTESIZE(state.num); | ||
221 | + | ||
222 | query = (QUERYTYPE *) palloc(commonlen); | ||
223 | SET_VARSIZE(query, commonlen); | ||
224 | query->size = state.num; | ||
225 | diff --git a/contrib/ltree/ltree.h b/contrib/ltree/ltree.h | ||
226 | index aec4458..49e9907 100644 | ||
227 | --- a/contrib/ltree/ltree.h | ||
228 | +++ b/contrib/ltree/ltree.h | ||
229 | @@ -5,6 +5,7 @@ | ||
230 | |||
231 | #include "fmgr.h" | ||
232 | #include "tsearch/ts_locale.h" | ||
233 | +#include "utils/memutils.h" | ||
234 | |||
235 | typedef struct | ||
236 | { | ||
237 | @@ -111,6 +112,8 @@ typedef struct | ||
238 | |||
239 | #define HDRSIZEQT MAXALIGN(VARHDRSZ + sizeof(int4)) | ||
240 | #define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + (size) * sizeof(ITEM) + (lenofoperand) ) | ||
241 | +#define LTXTQUERY_TOO_BIG(size,lenofoperand) \ | ||
242 | + ((size) > (MaxAllocSize - HDRSIZEQT - (lenofoperand)) / sizeof(ITEM)) | ||
243 | #define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) | ||
244 | #define GETOPERAND(x) ( (char*)GETQUERY(x) + ((ltxtquery*)x)->size * sizeof(ITEM) ) | ||
245 | |||
246 | diff --git a/contrib/ltree/ltree_io.c b/contrib/ltree/ltree_io.c | ||
247 | index 3e88b81..d64debb 100644 | ||
248 | --- a/contrib/ltree/ltree_io.c | ||
249 | +++ b/contrib/ltree/ltree_io.c | ||
250 | @@ -8,6 +8,7 @@ | ||
251 | #include <ctype.h> | ||
252 | |||
253 | #include "ltree.h" | ||
254 | +#include "utils/memutils.h" | ||
255 | #include "crc32.h" | ||
256 | |||
257 | PG_FUNCTION_INFO_V1(ltree_in); | ||
258 | @@ -64,6 +65,11 @@ ltree_in(PG_FUNCTION_ARGS) | ||
259 | ptr += charlen; | ||
260 | } | ||
261 | |||
262 | + if (num + 1 > MaxAllocSize / sizeof(nodeitem)) | ||
263 | + ereport(ERROR, | ||
264 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
265 | + errmsg("number of levels (%d) exceeds the maximum allowed (%d)", | ||
266 | + num + 1, (int) (MaxAllocSize / sizeof(nodeitem))))); | ||
267 | list = lptr = (nodeitem *) palloc(sizeof(nodeitem) * (num + 1)); | ||
268 | ptr = buf; | ||
269 | while (*ptr) | ||
270 | @@ -228,6 +234,11 @@ lquery_in(PG_FUNCTION_ARGS) | ||
271 | } | ||
272 | |||
273 | num++; | ||
274 | + if (num > MaxAllocSize / ITEMSIZE) | ||
275 | + ereport(ERROR, | ||
276 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
277 | + errmsg("number of levels (%d) exceeds the maximum allowed (%d)", | ||
278 | + num, (int) (MaxAllocSize / ITEMSIZE)))); | ||
279 | curqlevel = tmpql = (lquery_level *) palloc0(ITEMSIZE * num); | ||
280 | ptr = buf; | ||
281 | while (*ptr) | ||
282 | diff --git a/contrib/ltree/ltxtquery_io.c b/contrib/ltree/ltxtquery_io.c | ||
283 | index 826f4e1..13ea58d 100644 | ||
284 | --- a/contrib/ltree/ltxtquery_io.c | ||
285 | +++ b/contrib/ltree/ltxtquery_io.c | ||
286 | @@ -9,6 +9,7 @@ | ||
287 | |||
288 | #include "crc32.h" | ||
289 | #include "ltree.h" | ||
290 | +#include "miscadmin.h" | ||
291 | |||
292 | PG_FUNCTION_INFO_V1(ltxtq_in); | ||
293 | Datum ltxtq_in(PG_FUNCTION_ARGS); | ||
294 | @@ -213,6 +214,9 @@ makepol(QPRS_STATE *state) | ||
295 | int4 lenstack = 0; | ||
296 | uint16 flag = 0; | ||
297 | |||
298 | + /* since this function recurses, it could be driven to stack overflow */ | ||
299 | + check_stack_depth(); | ||
300 | + | ||
301 | while ((type = gettoken_query(state, &val, &lenval, &strval, &flag)) != END) | ||
302 | { | ||
303 | switch (type) | ||
304 | @@ -277,6 +281,9 @@ makepol(QPRS_STATE *state) | ||
305 | static void | ||
306 | findoprnd(ITEM *ptr, int4 *pos) | ||
307 | { | ||
308 | + /* since this function recurses, it could be driven to stack overflow. */ | ||
309 | + check_stack_depth(); | ||
310 | + | ||
311 | if (ptr[*pos].type == VAL || ptr[*pos].type == VALTRUE) | ||
312 | { | ||
313 | ptr[*pos].left = 0; | ||
314 | @@ -341,8 +348,12 @@ queryin(char *buf) | ||
315 | errmsg("syntax error"), | ||
316 | errdetail("Empty query."))); | ||
317 | |||
318 | - /* make finish struct */ | ||
319 | + if (LTXTQUERY_TOO_BIG(state.num, state.sumlen)) | ||
320 | + ereport(ERROR, | ||
321 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
322 | + errmsg("ltxtquery is too large"))); | ||
323 | commonlen = COMPUTESIZE(state.num, state.sumlen); | ||
324 | + | ||
325 | query = (ltxtquery *) palloc(commonlen); | ||
326 | SET_VARSIZE(query, commonlen); | ||
327 | query->size = state.num; | ||
328 | diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c | ||
329 | index ac7b4b8..7ebcaaa 100644 | ||
330 | --- a/src/backend/utils/adt/geo_ops.c | ||
331 | +++ b/src/backend/utils/adt/geo_ops.c | ||
332 | @@ -1403,6 +1403,7 @@ path_in(PG_FUNCTION_ARGS) | ||
333 | char *s; | ||
334 | int npts; | ||
335 | int size; | ||
336 | + int base_size; | ||
337 | int depth = 0; | ||
338 | |||
339 | if ((npts = pair_count(str, ',')) <= 0) | ||
340 | @@ -1421,7 +1422,15 @@ path_in(PG_FUNCTION_ARGS) | ||
341 | depth++; | ||
342 | } | ||
343 | |||
344 | - size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts; | ||
345 | + base_size = sizeof(path->p[0]) * npts; | ||
346 | + size = offsetof(PATH, p[0]) + base_size; | ||
347 | + | ||
348 | + /* Check for integer overflow */ | ||
349 | + if (base_size / npts != sizeof(path->p[0]) || size <= base_size) | ||
350 | + ereport(ERROR, | ||
351 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
352 | + errmsg("too many points requested"))); | ||
353 | + | ||
354 | path = (PATH *) palloc(size); | ||
355 | |||
356 | SET_VARSIZE(path, size); | ||
357 | @@ -3465,6 +3474,7 @@ poly_in(PG_FUNCTION_ARGS) | ||
358 | POLYGON *poly; | ||
359 | int npts; | ||
360 | int size; | ||
361 | + int base_size; | ||
362 | int isopen; | ||
363 | char *s; | ||
364 | |||
365 | @@ -3473,7 +3483,15 @@ poly_in(PG_FUNCTION_ARGS) | ||
366 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), | ||
367 | errmsg("invalid input syntax for type polygon: \"%s\"", str))); | ||
368 | |||
369 | - size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * npts; | ||
370 | + base_size = sizeof(poly->p[0]) * npts; | ||
371 | + size = offsetof(POLYGON, p[0]) + base_size; | ||
372 | + | ||
373 | + /* Check for integer overflow */ | ||
374 | + if (base_size / npts != sizeof(poly->p[0]) || size <= base_size) | ||
375 | + ereport(ERROR, | ||
376 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
377 | + errmsg("too many points requested"))); | ||
378 | + | ||
379 | poly = (POLYGON *) palloc0(size); /* zero any holes */ | ||
380 | |||
381 | SET_VARSIZE(poly, size); | ||
382 | @@ -4379,6 +4397,10 @@ path_poly(PG_FUNCTION_ARGS) | ||
383 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||
384 | errmsg("open path cannot be converted to polygon"))); | ||
385 | |||
386 | + /* | ||
387 | + * Never overflows: the old size fit in MaxAllocSize, and the new size is | ||
388 | + * just a small constant larger. | ||
389 | + */ | ||
390 | size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * path->npts; | ||
391 | poly = (POLYGON *) palloc(size); | ||
392 | |||
393 | @@ -4484,6 +4506,10 @@ poly_path(PG_FUNCTION_ARGS) | ||
394 | int size; | ||
395 | int i; | ||
396 | |||
397 | + /* | ||
398 | + * Never overflows: the old size fit in MaxAllocSize, and the new size is | ||
399 | + * smaller by a small constant. | ||
400 | + */ | ||
401 | size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * poly->npts; | ||
402 | path = (PATH *) palloc(size); | ||
403 | |||
404 | diff --git a/src/backend/utils/adt/tsquery.c b/src/backend/utils/adt/tsquery.c | ||
405 | index 6e1f8cf..1322b5e 100644 | ||
406 | --- a/src/backend/utils/adt/tsquery.c | ||
407 | +++ b/src/backend/utils/adt/tsquery.c | ||
408 | @@ -515,8 +515,13 @@ parse_tsquery(char *buf, | ||
409 | return query; | ||
410 | } | ||
411 | |||
412 | - /* Pack the QueryItems in the final TSQuery struct to return to caller */ | ||
413 | + if (TSQUERY_TOO_BIG(list_length(state.polstr), state.sumlen)) | ||
414 | + ereport(ERROR, | ||
415 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
416 | + errmsg("tsquery is too large"))); | ||
417 | commonlen = COMPUTESIZE(list_length(state.polstr), state.sumlen); | ||
418 | + | ||
419 | + /* Pack the QueryItems in the final TSQuery struct to return to caller */ | ||
420 | query = (TSQuery) palloc0(commonlen); | ||
421 | SET_VARSIZE(query, commonlen); | ||
422 | query->size = list_length(state.polstr); | ||
423 | diff --git a/src/backend/utils/adt/tsquery_util.c b/src/backend/utils/adt/tsquery_util.c | ||
424 | index 0724d33..9003702 100644 | ||
425 | --- a/src/backend/utils/adt/tsquery_util.c | ||
426 | +++ b/src/backend/utils/adt/tsquery_util.c | ||
427 | @@ -333,6 +333,11 @@ QTN2QT(QTNode *in) | ||
428 | QTN2QTState state; | ||
429 | |||
430 | cntsize(in, &sumlen, &nnode); | ||
431 | + | ||
432 | + if (TSQUERY_TOO_BIG(nnode, sumlen)) | ||
433 | + ereport(ERROR, | ||
434 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
435 | + errmsg("tsquery is too large"))); | ||
436 | len = COMPUTESIZE(nnode, sumlen); | ||
437 | |||
438 | out = (TSQuery) palloc0(len); | ||
439 | diff --git a/src/backend/utils/adt/txid.c b/src/backend/utils/adt/txid.c | ||
440 | index 08a8c89..c71daaf 100644 | ||
441 | --- a/src/backend/utils/adt/txid.c | ||
442 | +++ b/src/backend/utils/adt/txid.c | ||
443 | @@ -27,6 +27,7 @@ | ||
444 | #include "miscadmin.h" | ||
445 | #include "libpq/pqformat.h" | ||
446 | #include "utils/builtins.h" | ||
447 | +#include "utils/memutils.h" | ||
448 | #include "utils/snapmgr.h" | ||
449 | |||
450 | |||
451 | @@ -66,6 +67,8 @@ typedef struct | ||
452 | |||
453 | #define TXID_SNAPSHOT_SIZE(nxip) \ | ||
454 | (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip)) | ||
455 | +#define TXID_SNAPSHOT_MAX_NXIP \ | ||
456 | + ((MaxAllocSize - offsetof(TxidSnapshot, xip)) / sizeof(txid)) | ||
457 | |||
458 | /* | ||
459 | * Epoch values from xact.c | ||
460 | @@ -445,20 +448,12 @@ txid_snapshot_recv(PG_FUNCTION_ARGS) | ||
461 | txid last = 0; | ||
462 | int nxip; | ||
463 | int i; | ||
464 | - int avail; | ||
465 | - int expect; | ||
466 | txid xmin, | ||
467 | xmax; | ||
468 | |||
469 | - /* | ||
470 | - * load nxip and check for nonsense. | ||
471 | - * | ||
472 | - * (nxip > avail) check is against int overflows in 'expect'. | ||
473 | - */ | ||
474 | + /* load and validate nxip */ | ||
475 | nxip = pq_getmsgint(buf, 4); | ||
476 | - avail = buf->len - buf->cursor; | ||
477 | - expect = 8 + 8 + nxip * 8; | ||
478 | - if (nxip < 0 || nxip > avail || expect > avail) | ||
479 | + if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP) | ||
480 | goto bad_format; | ||
481 | |||
482 | xmin = pq_getmsgint64(buf); | ||
483 | diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c | ||
484 | index 2bcf5b8..0deefda 100644 | ||
485 | --- a/src/backend/utils/adt/varbit.c | ||
486 | +++ b/src/backend/utils/adt/varbit.c | ||
487 | @@ -148,12 +148,22 @@ bit_in(PG_FUNCTION_ARGS) | ||
488 | sp = input_string; | ||
489 | } | ||
490 | |||
491 | + /* | ||
492 | + * Determine bitlength from input string. MaxAllocSize ensures a regular | ||
493 | + * input is small enough, but we must check hex input. | ||
494 | + */ | ||
495 | slen = strlen(sp); | ||
496 | - /* Determine bitlength from input string */ | ||
497 | if (bit_not_hex) | ||
498 | bitlen = slen; | ||
499 | else | ||
500 | + { | ||
501 | + if (slen > VARBITMAXLEN / 4) | ||
502 | + ereport(ERROR, | ||
503 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
504 | + errmsg("bit string length exceeds the maximum allowed (%d)", | ||
505 | + VARBITMAXLEN))); | ||
506 | bitlen = slen * 4; | ||
507 | + } | ||
508 | |||
509 | /* | ||
510 | * Sometimes atttypmod is not supplied. If it is supplied we need to make | ||
511 | @@ -450,12 +460,22 @@ varbit_in(PG_FUNCTION_ARGS) | ||
512 | sp = input_string; | ||
513 | } | ||
514 | |||
515 | + /* | ||
516 | + * Determine bitlength from input string. MaxAllocSize ensures a regular | ||
517 | + * input is small enough, but we must check hex input. | ||
518 | + */ | ||
519 | slen = strlen(sp); | ||
520 | - /* Determine bitlength from input string */ | ||
521 | if (bit_not_hex) | ||
522 | bitlen = slen; | ||
523 | else | ||
524 | + { | ||
525 | + if (slen > VARBITMAXLEN / 4) | ||
526 | + ereport(ERROR, | ||
527 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
528 | + errmsg("bit string length exceeds the maximum allowed (%d)", | ||
529 | + VARBITMAXLEN))); | ||
530 | bitlen = slen * 4; | ||
531 | + } | ||
532 | |||
533 | /* | ||
534 | * Sometimes atttypmod is not supplied. If it is supplied we need to make | ||
535 | @@ -535,6 +555,9 @@ varbit_in(PG_FUNCTION_ARGS) | ||
536 | /* | ||
537 | * varbit_out - | ||
538 | * Prints the string as bits to preserve length accurately | ||
539 | + * | ||
540 | + * XXX varbit_recv() and hex input to varbit_in() can load a value that this | ||
541 | + * cannot emit. Consider using hex output for such values. | ||
542 | */ | ||
543 | Datum | ||
544 | varbit_out(PG_FUNCTION_ARGS) | ||
545 | @@ -944,6 +967,11 @@ bit_catenate(VarBit *arg1, VarBit *arg2) | ||
546 | bitlen1 = VARBITLEN(arg1); | ||
547 | bitlen2 = VARBITLEN(arg2); | ||
548 | |||
549 | + if (bitlen1 > VARBITMAXLEN - bitlen2) | ||
550 | + ereport(ERROR, | ||
551 | + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), | ||
552 | + errmsg("bit string length exceeds the maximum allowed (%d)", | ||
553 | + VARBITMAXLEN))); | ||
554 | bytelen = VARBITTOTALLEN(bitlen1 + bitlen2); | ||
555 | |||
556 | result = (VarBit *) palloc(bytelen); | ||
557 | diff --git a/src/include/tsearch/ts_type.h b/src/include/tsearch/ts_type.h | ||
558 | index 3adc336..9ee5610 100644 | ||
559 | --- a/src/include/tsearch/ts_type.h | ||
560 | +++ b/src/include/tsearch/ts_type.h | ||
561 | @@ -13,6 +13,7 @@ | ||
562 | #define _PG_TSTYPE_H_ | ||
563 | |||
564 | #include "fmgr.h" | ||
565 | +#include "utils/memutils.h" | ||
566 | #include "utils/pg_crc.h" | ||
567 | |||
568 | |||
569 | @@ -244,6 +245,8 @@ typedef TSQueryData *TSQuery; | ||
570 | * QueryItems, and lenofoperand is the total length of all operands | ||
571 | */ | ||
572 | #define COMPUTESIZE(size, lenofoperand) ( HDRSIZETQ + (size) * sizeof(QueryItem) + (lenofoperand) ) | ||
573 | +#define TSQUERY_TOO_BIG(size, lenofoperand) \ | ||
574 | + ((size) > (MaxAllocSize - HDRSIZETQ - (lenofoperand)) / sizeof(QueryItem)) | ||
575 | |||
576 | /* Returns a pointer to the first QueryItem in a TSQuery */ | ||
577 | #define GETQUERY(x) ((QueryItem*)( (char*)(x)+HDRSIZETQ )) | ||
578 | diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h | ||
579 | index 52dca8b..61531a8 100644 | ||
580 | --- a/src/include/utils/varbit.h | ||
581 | +++ b/src/include/utils/varbit.h | ||
582 | @@ -15,6 +15,8 @@ | ||
583 | #ifndef VARBIT_H | ||
584 | #define VARBIT_H | ||
585 | |||
586 | +#include <limits.h> | ||
587 | + | ||
588 | #include "fmgr.h" | ||
589 | |||
590 | /* | ||
591 | @@ -53,6 +55,11 @@ typedef struct | ||
592 | /* Number of bytes needed to store a bit string of a given length */ | ||
593 | #define VARBITTOTALLEN(BITLEN) (((BITLEN) + BITS_PER_BYTE-1)/BITS_PER_BYTE + \ | ||
594 | VARHDRSZ + VARBITHDRSZ) | ||
595 | +/* | ||
596 | + * Maximum number of bits. Several code sites assume no overflow from | ||
597 | + * computing bitlen + X; VARBITTOTALLEN() has the largest such X. | ||
598 | + */ | ||
599 | +#define VARBITMAXLEN (INT_MAX - BITS_PER_BYTE + 1) | ||
600 | /* pointer beyond the end of the bit string (like end() in STL containers) */ | ||
601 | #define VARBITEND(PTR) (((bits8 *) (PTR)) + VARSIZE(PTR)) | ||
602 | /* Mask that will cover exactly one byte, i.e. BITS_PER_BYTE bits */ | ||
603 | -- | ||
604 | 1.7.5.4 | ||
605 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch b/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch new file mode 100644 index 000000000..abbe14249 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0003-Shore-up-ADMIN-OPTION-restrictions.patch | |||
@@ -0,0 +1,273 @@ | |||
1 | From 15a8f97b9d16aaf659f58c981242b9da591cf24c Mon Sep 17 00:00:00 2001 | ||
2 | From: Noah Misch <noah@leadboat.com> | ||
3 | Date: Mon, 17 Feb 2014 09:33:31 -0500 | ||
4 | Subject: [PATCH] Shore up ADMIN OPTION restrictions. | ||
5 | |||
6 | commit 15a8f97b9d16aaf659f58c981242b9da591cf24c REL9_2_STABLE | ||
7 | |||
8 | Granting a role without ADMIN OPTION is supposed to prevent the grantee | ||
9 | from adding or removing members from the granted role. Issuing SET ROLE | ||
10 | before the GRANT bypassed that, because the role itself had an implicit | ||
11 | right to add or remove members. Plug that hole by recognizing that | ||
12 | implicit right only when the session user matches the current role. | ||
13 | Additionally, do not recognize it during a security-restricted operation | ||
14 | or during execution of a SECURITY DEFINER function. The restriction on | ||
15 | SECURITY DEFINER is not security-critical. However, it seems best for a | ||
16 | user testing his own SECURITY DEFINER function to see the same behavior | ||
17 | others will see. Back-patch to 8.4 (all supported versions). | ||
18 | |||
19 | The SQL standards do not conflate roles and users as PostgreSQL does; | ||
20 | only SQL roles have members, and only SQL users initiate sessions. An | ||
21 | application using PostgreSQL users and roles as SQL users and roles will | ||
22 | never attempt to grant membership in the role that is the session user, | ||
23 | so the implicit right to add or remove members will never arise. | ||
24 | |||
25 | The security impact was mostly that a role member could revoke access | ||
26 | from others, contrary to the wishes of his own grantor. Unapproved role | ||
27 | member additions are less notable, because the member can still largely | ||
28 | achieve that by creating a view or a SECURITY DEFINER function. | ||
29 | |||
30 | Reviewed by Andres Freund and Tom Lane. Reported, independently, by | ||
31 | Jonas Sundman and Noah Misch. | ||
32 | |||
33 | Security: CVE-2014-0060 | ||
34 | |||
35 | |||
36 | Upstream-Status: Backport | ||
37 | |||
38 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
39 | --- | ||
40 | doc/src/sgml/ref/grant.sgml | 12 ++++--- | ||
41 | src/backend/commands/user.c | 11 ++++++- | ||
42 | src/backend/utils/adt/acl.c | 50 ++++++++++++++++++++++++------ | ||
43 | src/test/regress/expected/privileges.out | 36 +++++++++++++++++++++- | ||
44 | src/test/regress/sql/privileges.sql | 29 ++++++++++++++++- | ||
45 | 5 files changed, 120 insertions(+), 18 deletions(-) | ||
46 | |||
47 | diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml | ||
48 | index fb81af4..2b5a843 100644 | ||
49 | --- a/doc/src/sgml/ref/grant.sgml | ||
50 | +++ b/doc/src/sgml/ref/grant.sgml | ||
51 | @@ -396,11 +396,13 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace | ||
52 | <para> | ||
53 | If <literal>WITH ADMIN OPTION</literal> is specified, the member can | ||
54 | in turn grant membership in the role to others, and revoke membership | ||
55 | - in the role as well. Without the admin option, ordinary users cannot do | ||
56 | - that. However, | ||
57 | - database superusers can grant or revoke membership in any role to anyone. | ||
58 | - Roles having <literal>CREATEROLE</> privilege can grant or revoke | ||
59 | - membership in any role that is not a superuser. | ||
60 | + in the role as well. Without the admin option, ordinary users cannot | ||
61 | + do that. A role is not considered to hold <literal>WITH ADMIN | ||
62 | + OPTION</literal> on itself, but it may grant or revoke membership in | ||
63 | + itself from a database session where the session user matches the | ||
64 | + role. Database superusers can grant or revoke membership in any role | ||
65 | + to anyone. Roles having <literal>CREATEROLE</> privilege can grant | ||
66 | + or revoke membership in any role that is not a superuser. | ||
67 | </para> | ||
68 | |||
69 | <para> | ||
70 | diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c | ||
71 | index a22092c..39bf172 100644 | ||
72 | --- a/src/backend/commands/user.c | ||
73 | +++ b/src/backend/commands/user.c | ||
74 | @@ -1334,7 +1334,16 @@ AddRoleMems(const char *rolename, Oid roleid, | ||
75 | rolename))); | ||
76 | } | ||
77 | |||
78 | - /* XXX not sure about this check */ | ||
79 | + /* | ||
80 | + * The role membership grantor of record has little significance at | ||
81 | + * present. Nonetheless, inasmuch as users might look to it for a crude | ||
82 | + * audit trail, let only superusers impute the grant to a third party. | ||
83 | + * | ||
84 | + * Before lifting this restriction, give the member == role case of | ||
85 | + * is_admin_of_role() a fresh look. Ensure that the current role cannot | ||
86 | + * use an explicit grantor specification to take advantage of the session | ||
87 | + * user's self-admin right. | ||
88 | + */ | ||
89 | if (grantorId != GetUserId() && !superuser()) | ||
90 | ereport(ERROR, | ||
91 | (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), | ||
92 | diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c | ||
93 | index 1d6ae8b..9a52edb 100644 | ||
94 | --- a/src/backend/utils/adt/acl.c | ||
95 | +++ b/src/backend/utils/adt/acl.c | ||
96 | @@ -4580,6 +4580,11 @@ pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode) | ||
97 | { | ||
98 | if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE)) | ||
99 | { | ||
100 | + /* | ||
101 | + * XXX For roleid == role_oid, is_admin_of_role() also examines the | ||
102 | + * session and call stack. That suits two-argument pg_has_role(), but | ||
103 | + * it gives the three-argument version a lamentable whimsy. | ||
104 | + */ | ||
105 | if (is_admin_of_role(roleid, role_oid)) | ||
106 | return ACLCHECK_OK; | ||
107 | } | ||
108 | @@ -4897,11 +4902,9 @@ is_member_of_role_nosuper(Oid member, Oid role) | ||
109 | |||
110 | |||
111 | /* | ||
112 | - * Is member an admin of role (directly or indirectly)? That is, is it | ||
113 | - * a member WITH ADMIN OPTION? | ||
114 | - * | ||
115 | - * We could cache the result as for is_member_of_role, but currently this | ||
116 | - * is not used in any performance-critical paths, so we don't. | ||
117 | + * Is member an admin of role? That is, is member the role itself (subject to | ||
118 | + * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION, | ||
119 | + * or a superuser? | ||
120 | */ | ||
121 | bool | ||
122 | is_admin_of_role(Oid member, Oid role) | ||
123 | @@ -4910,14 +4913,41 @@ is_admin_of_role(Oid member, Oid role) | ||
124 | List *roles_list; | ||
125 | ListCell *l; | ||
126 | |||
127 | - /* Fast path for simple case */ | ||
128 | - if (member == role) | ||
129 | - return true; | ||
130 | - | ||
131 | - /* Superusers have every privilege, so are part of every role */ | ||
132 | if (superuser_arg(member)) | ||
133 | return true; | ||
134 | |||
135 | + if (member == role) | ||
136 | + /* | ||
137 | + * A role can admin itself when it matches the session user and we're | ||
138 | + * outside any security-restricted operation, SECURITY DEFINER or | ||
139 | + * similar context. SQL-standard roles cannot self-admin. However, | ||
140 | + * SQL-standard users are distinct from roles, and they are not | ||
141 | + * grantable like roles: PostgreSQL's role-user duality extends the | ||
142 | + * standard. Checking for a session user match has the effect of | ||
143 | + * letting a role self-admin only when it's conspicuously behaving | ||
144 | + * like a user. Note that allowing self-admin under a mere SET ROLE | ||
145 | + * would make WITH ADMIN OPTION largely irrelevant; any member could | ||
146 | + * SET ROLE to issue the otherwise-forbidden command. | ||
147 | + * | ||
148 | + * Withholding self-admin in a security-restricted operation prevents | ||
149 | + * object owners from harnessing the session user identity during | ||
150 | + * administrative maintenance. Suppose Alice owns a database, has | ||
151 | + * issued "GRANT alice TO bob", and runs a daily ANALYZE. Bob creates | ||
152 | + * an alice-owned SECURITY DEFINER function that issues "REVOKE alice | ||
153 | + * FROM carol". If he creates an expression index calling that | ||
154 | + * function, Alice will attempt the REVOKE during each ANALYZE. | ||
155 | + * Checking InSecurityRestrictedOperation() thwarts that attack. | ||
156 | + * | ||
157 | + * Withholding self-admin in SECURITY DEFINER functions makes their | ||
158 | + * behavior independent of the calling user. There's no security or | ||
159 | + * SQL-standard-conformance need for that restriction, though. | ||
160 | + * | ||
161 | + * A role cannot have actual WITH ADMIN OPTION on itself, because that | ||
162 | + * would imply a membership loop. Therefore, we're done either way. | ||
163 | + */ | ||
164 | + return member == GetSessionUserId() && | ||
165 | + !InLocalUserIdChange() && !InSecurityRestrictedOperation(); | ||
166 | + | ||
167 | /* | ||
168 | * Find all the roles that member is a member of, including multi-level | ||
169 | * recursion. We build a list in the same way that is_member_of_role does | ||
170 | diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out | ||
171 | index e8930cb..bc6d731 100644 | ||
172 | --- a/src/test/regress/expected/privileges.out | ||
173 | +++ b/src/test/regress/expected/privileges.out | ||
174 | @@ -32,7 +32,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4; | ||
175 | ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate | ||
176 | NOTICE: role "regressuser2" is already a member of role "regressgroup2" | ||
177 | ALTER GROUP regressgroup2 DROP USER regressuser2; | ||
178 | -ALTER GROUP regressgroup2 ADD USER regressuser4; | ||
179 | +GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION; | ||
180 | -- test owner privileges | ||
181 | SET SESSION AUTHORIZATION regressuser1; | ||
182 | SELECT session_user, current_user; | ||
183 | @@ -929,6 +929,40 @@ SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION') | ||
184 | t | ||
185 | (1 row) | ||
186 | |||
187 | +-- Admin options | ||
188 | +SET SESSION AUTHORIZATION regressuser4; | ||
189 | +CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS | ||
190 | + 'GRANT regressgroup2 TO regressuser5'; | ||
191 | +GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION | ||
192 | +SET ROLE regressgroup2; | ||
193 | +GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege | ||
194 | +ERROR: must have admin option on role "regressgroup2" | ||
195 | +SET SESSION AUTHORIZATION regressuser1; | ||
196 | +GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION | ||
197 | +ERROR: must have admin option on role "regressgroup2" | ||
198 | +SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN | ||
199 | +NOTICE: role "regressuser5" is already a member of role "regressgroup2" | ||
200 | +CONTEXT: SQL function "dogrant_ok" statement 1 | ||
201 | + dogrant_ok | ||
202 | +------------ | ||
203 | + | ||
204 | +(1 row) | ||
205 | + | ||
206 | +SET ROLE regressgroup2; | ||
207 | +GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help | ||
208 | +ERROR: must have admin option on role "regressgroup2" | ||
209 | +SET SESSION AUTHORIZATION regressgroup2; | ||
210 | +GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin | ||
211 | +NOTICE: role "regressuser5" is already a member of role "regressgroup2" | ||
212 | +CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS | ||
213 | + 'GRANT regressgroup2 TO regressuser5'; | ||
214 | +SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER | ||
215 | +ERROR: must have admin option on role "regressgroup2" | ||
216 | +CONTEXT: SQL function "dogrant_fails" statement 1 | ||
217 | +DROP FUNCTION dogrant_fails(); | ||
218 | +SET SESSION AUTHORIZATION regressuser4; | ||
219 | +DROP FUNCTION dogrant_ok(); | ||
220 | +REVOKE regressgroup2 FROM regressuser5; | ||
221 | -- has_sequence_privilege tests | ||
222 | \c - | ||
223 | CREATE SEQUENCE x_seq; | ||
224 | diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql | ||
225 | index d4d328e..5f1018a 100644 | ||
226 | --- a/src/test/regress/sql/privileges.sql | ||
227 | +++ b/src/test/regress/sql/privileges.sql | ||
228 | @@ -37,7 +37,7 @@ ALTER GROUP regressgroup1 ADD USER regressuser4; | ||
229 | |||
230 | ALTER GROUP regressgroup2 ADD USER regressuser2; -- duplicate | ||
231 | ALTER GROUP regressgroup2 DROP USER regressuser2; | ||
232 | -ALTER GROUP regressgroup2 ADD USER regressuser4; | ||
233 | +GRANT regressgroup2 TO regressuser4 WITH ADMIN OPTION; | ||
234 | |||
235 | -- test owner privileges | ||
236 | |||
237 | @@ -581,6 +581,33 @@ SELECT has_table_privilege('regressuser3', 'atest4', 'SELECT'); -- false | ||
238 | SELECT has_table_privilege('regressuser1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true | ||
239 | |||
240 | |||
241 | +-- Admin options | ||
242 | + | ||
243 | +SET SESSION AUTHORIZATION regressuser4; | ||
244 | +CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS | ||
245 | + 'GRANT regressgroup2 TO regressuser5'; | ||
246 | +GRANT regressgroup2 TO regressuser5; -- ok: had ADMIN OPTION | ||
247 | +SET ROLE regressgroup2; | ||
248 | +GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE suspended privilege | ||
249 | + | ||
250 | +SET SESSION AUTHORIZATION regressuser1; | ||
251 | +GRANT regressgroup2 TO regressuser5; -- fails: no ADMIN OPTION | ||
252 | +SELECT dogrant_ok(); -- ok: SECURITY DEFINER conveys ADMIN | ||
253 | +SET ROLE regressgroup2; | ||
254 | +GRANT regressgroup2 TO regressuser5; -- fails: SET ROLE did not help | ||
255 | + | ||
256 | +SET SESSION AUTHORIZATION regressgroup2; | ||
257 | +GRANT regressgroup2 TO regressuser5; -- ok: a role can self-admin | ||
258 | +CREATE FUNCTION dogrant_fails() RETURNS void LANGUAGE sql SECURITY DEFINER AS | ||
259 | + 'GRANT regressgroup2 TO regressuser5'; | ||
260 | +SELECT dogrant_fails(); -- fails: no self-admin in SECURITY DEFINER | ||
261 | +DROP FUNCTION dogrant_fails(); | ||
262 | + | ||
263 | +SET SESSION AUTHORIZATION regressuser4; | ||
264 | +DROP FUNCTION dogrant_ok(); | ||
265 | +REVOKE regressgroup2 FROM regressuser5; | ||
266 | + | ||
267 | + | ||
268 | -- has_sequence_privilege tests | ||
269 | \c - | ||
270 | |||
271 | -- | ||
272 | 1.7.5.4 | ||
273 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch b/meta-oe/recipes-support/postgresql/files/0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch new file mode 100644 index 000000000..cc2183a2a --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch | |||
@@ -0,0 +1,267 @@ | |||
1 | From 1d701d28a796ea2d1a4d2be9e9ee06209eaea040 Mon Sep 17 00:00:00 2001 | ||
2 | From: Noah Misch <noah@leadboat.com> | ||
3 | Date: Mon, 17 Feb 2014 09:33:31 -0500 | ||
4 | Subject: [PATCH] Prevent privilege escalation in explicit calls to PL | ||
5 | validators. | ||
6 | |||
7 | commit 1d701d28a796ea2d1a4d2be9e9ee06209eaea040 REL9_2_STABLE | ||
8 | |||
9 | The primary role of PL validators is to be called implicitly during | ||
10 | CREATE FUNCTION, but they are also normal functions that a user can call | ||
11 | explicitly. Add a permissions check to each validator to ensure that a | ||
12 | user cannot use explicit validator calls to achieve things he could not | ||
13 | otherwise achieve. Back-patch to 8.4 (all supported versions). | ||
14 | Non-core procedural language extensions ought to make the same two-line | ||
15 | change to their own validators. | ||
16 | |||
17 | Andres Freund, reviewed by Tom Lane and Noah Misch. | ||
18 | |||
19 | Security: CVE-2014-0061 | ||
20 | |||
21 | Upstream-Status: Backport | ||
22 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
23 | --- | ||
24 | doc/src/sgml/plhandler.sgml | 5 ++- | ||
25 | src/backend/catalog/pg_proc.c | 9 ++++ | ||
26 | src/backend/commands/functioncmds.c | 1 - | ||
27 | src/backend/utils/fmgr/fmgr.c | 84 +++++++++++++++++++++++++++++++++++ | ||
28 | src/include/fmgr.h | 1 + | ||
29 | src/pl/plperl/plperl.c | 4 ++ | ||
30 | src/pl/plpgsql/src/pl_handler.c | 3 + | ||
31 | src/pl/plpython/plpy_main.c | 4 ++ | ||
32 | 8 files changed, 109 insertions(+), 2 deletions(-) | ||
33 | |||
34 | diff --git a/doc/src/sgml/plhandler.sgml b/doc/src/sgml/plhandler.sgml | ||
35 | index 024ef9d..aa4bba3 100644 | ||
36 | --- a/doc/src/sgml/plhandler.sgml | ||
37 | +++ b/doc/src/sgml/plhandler.sgml | ||
38 | @@ -178,7 +178,10 @@ CREATE LANGUAGE plsample | ||
39 | or updated a function written in the procedural language. | ||
40 | The passed-in OID is the OID of the function's <classname>pg_proc</> | ||
41 | row. The validator must fetch this row in the usual way, and do | ||
42 | - whatever checking is appropriate. Typical checks include verifying | ||
43 | + whatever checking is appropriate. | ||
44 | + First, call <function>CheckFunctionValidatorAccess()</> to diagnose | ||
45 | + explicit calls to the validator that the user could not achieve through | ||
46 | + <command>CREATE FUNCTION</>. Typical checks then include verifying | ||
47 | that the function's argument and result types are supported by the | ||
48 | language, and that the function's body is syntactically correct | ||
49 | in the language. If the validator finds the function to be okay, | ||
50 | diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c | ||
51 | index 3812408..3124868 100644 | ||
52 | --- a/src/backend/catalog/pg_proc.c | ||
53 | +++ b/src/backend/catalog/pg_proc.c | ||
54 | @@ -718,6 +718,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS) | ||
55 | Datum tmp; | ||
56 | char *prosrc; | ||
57 | |||
58 | + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) | ||
59 | + PG_RETURN_VOID(); | ||
60 | + | ||
61 | /* | ||
62 | * We do not honor check_function_bodies since it's unlikely the function | ||
63 | * name will be found later if it isn't there now. | ||
64 | @@ -763,6 +766,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS) | ||
65 | char *prosrc; | ||
66 | char *probin; | ||
67 | |||
68 | + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) | ||
69 | + PG_RETURN_VOID(); | ||
70 | + | ||
71 | /* | ||
72 | * It'd be most consistent to skip the check if !check_function_bodies, | ||
73 | * but the purpose of that switch is to be helpful for pg_dump loading, | ||
74 | @@ -814,6 +820,9 @@ fmgr_sql_validator(PG_FUNCTION_ARGS) | ||
75 | bool haspolyarg; | ||
76 | int i; | ||
77 | |||
78 | + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) | ||
79 | + PG_RETURN_VOID(); | ||
80 | + | ||
81 | tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); | ||
82 | if (!HeapTupleIsValid(tuple)) | ||
83 | elog(ERROR, "cache lookup failed for function %u", funcoid); | ||
84 | diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c | ||
85 | index 9ba6dd8..ea74b5e 100644 | ||
86 | --- a/src/backend/commands/functioncmds.c | ||
87 | +++ b/src/backend/commands/functioncmds.c | ||
88 | @@ -997,7 +997,6 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) | ||
89 | prorows); | ||
90 | } | ||
91 | |||
92 | - | ||
93 | /* | ||
94 | * Guts of function deletion. | ||
95 | * | ||
96 | diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c | ||
97 | index 2ec63fa..8d6f183 100644 | ||
98 | --- a/src/backend/utils/fmgr/fmgr.c | ||
99 | +++ b/src/backend/utils/fmgr/fmgr.c | ||
100 | @@ -24,6 +24,7 @@ | ||
101 | #include "miscadmin.h" | ||
102 | #include "nodes/nodeFuncs.h" | ||
103 | #include "pgstat.h" | ||
104 | +#include "utils/acl.h" | ||
105 | #include "utils/builtins.h" | ||
106 | #include "utils/fmgrtab.h" | ||
107 | #include "utils/guc.h" | ||
108 | @@ -2445,3 +2446,86 @@ get_call_expr_arg_stable(Node *expr, int argnum) | ||
109 | |||
110 | return false; | ||
111 | } | ||
112 | + | ||
113 | +/*------------------------------------------------------------------------- | ||
114 | + * Support routines for procedural language implementations | ||
115 | + *------------------------------------------------------------------------- | ||
116 | + */ | ||
117 | + | ||
118 | +/* | ||
119 | + * Verify that a validator is actually associated with the language of a | ||
120 | + * particular function and that the user has access to both the language and | ||
121 | + * the function. All validators should call this before doing anything | ||
122 | + * substantial. Doing so ensures a user cannot achieve anything with explicit | ||
123 | + * calls to validators that he could not achieve with CREATE FUNCTION or by | ||
124 | + * simply calling an existing function. | ||
125 | + * | ||
126 | + * When this function returns false, callers should skip all validation work | ||
127 | + * and call PG_RETURN_VOID(). This never happens at present; it is reserved | ||
128 | + * for future expansion. | ||
129 | + * | ||
130 | + * In particular, checking that the validator corresponds to the function's | ||
131 | + * language allows untrusted language validators to assume they process only | ||
132 | + * superuser-chosen source code. (Untrusted language call handlers, by | ||
133 | + * definition, do assume that.) A user lacking the USAGE language privilege | ||
134 | + * would be unable to reach the validator through CREATE FUNCTION, so we check | ||
135 | + * that to block explicit calls as well. Checking the EXECUTE privilege on | ||
136 | + * the function is often superfluous, because most users can clone the | ||
137 | + * function to get an executable copy. It is meaningful against users with no | ||
138 | + * database TEMP right and no permanent schema CREATE right, thereby unable to | ||
139 | + * create any function. Also, if the function tracks persistent state by | ||
140 | + * function OID or name, validating the original function might permit more | ||
141 | + * mischief than creating and validating a clone thereof. | ||
142 | + */ | ||
143 | +bool | ||
144 | +CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid) | ||
145 | +{ | ||
146 | + HeapTuple procTup; | ||
147 | + HeapTuple langTup; | ||
148 | + Form_pg_proc procStruct; | ||
149 | + Form_pg_language langStruct; | ||
150 | + AclResult aclresult; | ||
151 | + | ||
152 | + /* Get the function's pg_proc entry */ | ||
153 | + procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionOid)); | ||
154 | + if (!HeapTupleIsValid(procTup)) | ||
155 | + elog(ERROR, "cache lookup failed for function %u", functionOid); | ||
156 | + procStruct = (Form_pg_proc) GETSTRUCT(procTup); | ||
157 | + | ||
158 | + /* | ||
159 | + * Fetch pg_language entry to know if this is the correct validation | ||
160 | + * function for that pg_proc entry. | ||
161 | + */ | ||
162 | + langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(procStruct->prolang)); | ||
163 | + if (!HeapTupleIsValid(langTup)) | ||
164 | + elog(ERROR, "cache lookup failed for language %u", procStruct->prolang); | ||
165 | + langStruct = (Form_pg_language) GETSTRUCT(langTup); | ||
166 | + | ||
167 | + if (langStruct->lanvalidator != validatorOid) | ||
168 | + ereport(ERROR, | ||
169 | + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), | ||
170 | + errmsg("language validation function %u called for language %u instead of %u", | ||
171 | + validatorOid, procStruct->prolang, | ||
172 | + langStruct->lanvalidator))); | ||
173 | + | ||
174 | + /* first validate that we have permissions to use the language */ | ||
175 | + aclresult = pg_language_aclcheck(procStruct->prolang, GetUserId(), | ||
176 | + ACL_USAGE); | ||
177 | + if (aclresult != ACLCHECK_OK) | ||
178 | + aclcheck_error(aclresult, ACL_KIND_LANGUAGE, | ||
179 | + NameStr(langStruct->lanname)); | ||
180 | + | ||
181 | + /* | ||
182 | + * Check whether we are allowed to execute the function itself. If we can | ||
183 | + * execute it, there should be no possible side-effect of | ||
184 | + * compiling/validation that execution can't have. | ||
185 | + */ | ||
186 | + aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE); | ||
187 | + if (aclresult != ACLCHECK_OK) | ||
188 | + aclcheck_error(aclresult, ACL_KIND_PROC, NameStr(procStruct->proname)); | ||
189 | + | ||
190 | + ReleaseSysCache(procTup); | ||
191 | + ReleaseSysCache(langTup); | ||
192 | + | ||
193 | + return true; | ||
194 | +} | ||
195 | diff --git a/src/include/fmgr.h b/src/include/fmgr.h | ||
196 | index 0a25776..f944cc6 100644 | ||
197 | --- a/src/include/fmgr.h | ||
198 | +++ b/src/include/fmgr.h | ||
199 | @@ -624,6 +624,7 @@ extern Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum); | ||
200 | extern Oid get_call_expr_argtype(fmNodePtr expr, int argnum); | ||
201 | extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum); | ||
202 | extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum); | ||
203 | +extern bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid); | ||
204 | |||
205 | /* | ||
206 | * Routines in dfmgr.c | ||
207 | diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c | ||
208 | index 7c2aee9..49d50c4 100644 | ||
209 | --- a/src/pl/plperl/plperl.c | ||
210 | +++ b/src/pl/plperl/plperl.c | ||
211 | @@ -1847,6 +1847,9 @@ plperl_validator(PG_FUNCTION_ARGS) | ||
212 | bool istrigger = false; | ||
213 | int i; | ||
214 | |||
215 | + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) | ||
216 | + PG_RETURN_VOID(); | ||
217 | + | ||
218 | /* Get the new function's pg_proc entry */ | ||
219 | tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); | ||
220 | if (!HeapTupleIsValid(tuple)) | ||
221 | @@ -1926,6 +1929,7 @@ PG_FUNCTION_INFO_V1(plperlu_validator); | ||
222 | Datum | ||
223 | plperlu_validator(PG_FUNCTION_ARGS) | ||
224 | { | ||
225 | + /* call plperl validator with our fcinfo so it gets our oid */ | ||
226 | return plperl_validator(fcinfo); | ||
227 | } | ||
228 | |||
229 | diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c | ||
230 | index 022ec3f..00b1a6f 100644 | ||
231 | --- a/src/pl/plpgsql/src/pl_handler.c | ||
232 | +++ b/src/pl/plpgsql/src/pl_handler.c | ||
233 | @@ -227,6 +227,9 @@ plpgsql_validator(PG_FUNCTION_ARGS) | ||
234 | bool istrigger = false; | ||
235 | int i; | ||
236 | |||
237 | + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) | ||
238 | + PG_RETURN_VOID(); | ||
239 | + | ||
240 | /* Get the new function's pg_proc entry */ | ||
241 | tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcoid)); | ||
242 | if (!HeapTupleIsValid(tuple)) | ||
243 | diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c | ||
244 | index c4de762..3847847 100644 | ||
245 | --- a/src/pl/plpython/plpy_main.c | ||
246 | +++ b/src/pl/plpython/plpy_main.c | ||
247 | @@ -159,6 +159,9 @@ plpython_validator(PG_FUNCTION_ARGS) | ||
248 | Form_pg_proc procStruct; | ||
249 | bool is_trigger; | ||
250 | |||
251 | + if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid)) | ||
252 | + PG_RETURN_VOID(); | ||
253 | + | ||
254 | if (!check_function_bodies) | ||
255 | { | ||
256 | PG_RETURN_VOID(); | ||
257 | @@ -184,6 +187,7 @@ plpython_validator(PG_FUNCTION_ARGS) | ||
258 | Datum | ||
259 | plpython2_validator(PG_FUNCTION_ARGS) | ||
260 | { | ||
261 | + /* call plpython validator with our fcinfo so it gets our oid */ | ||
262 | return plpython_validator(fcinfo); | ||
263 | } | ||
264 | #endif /* PY_MAJOR_VERSION < 3 */ | ||
265 | -- | ||
266 | 1.7.5.4 | ||
267 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch b/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch new file mode 100644 index 000000000..f1aa21250 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch | |||
@@ -0,0 +1,1082 @@ | |||
1 | From 820ab11fbfd508fc75a39c43ad2c1b3e79c4982b Mon Sep 17 00:00:00 2001 | ||
2 | From: Robert Haas <rhaas@postgresql.org> | ||
3 | Date: Mon, 17 Feb 2014 09:33:31 -0500 | ||
4 | Subject: [PATCH] Avoid repeated name lookups during table and index DDL. | ||
5 | |||
6 | commit 820ab11fbfd508fc75a39c43ad2c1b3e79c4982b REL9_2_STABLE | ||
7 | |||
8 | If the name lookups come to different conclusions due to concurrent | ||
9 | activity, we might perform some parts of the DDL on a different table | ||
10 | than other parts. At least in the case of CREATE INDEX, this can be | ||
11 | used to cause the permissions checks to be performed against a | ||
12 | different table than the index creation, allowing for a privilege | ||
13 | escalation attack. | ||
14 | |||
15 | This changes the calling convention for DefineIndex, CreateTrigger, | ||
16 | transformIndexStmt, transformAlterTableStmt, CheckIndexCompatible | ||
17 | (in 9.2 and newer), and AlterTable (in 9.1 and older). In addition, | ||
18 | CheckRelationOwnership is removed in 9.2 and newer and the calling | ||
19 | convention is changed in older branches. A field has also been added | ||
20 | to the Constraint node (FkConstraint in 8.4). Third-party code calling | ||
21 | these functions or using the Constraint node will require updating. | ||
22 | |||
23 | Report by Andres Freund. Patch by Robert Haas and Andres Freund, | ||
24 | reviewed by Tom Lane. | ||
25 | |||
26 | Security: CVE-2014-0062 | ||
27 | |||
28 | Upstream-Status: Backport | ||
29 | |||
30 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
31 | --- | ||
32 | src/backend/bootstrap/bootparse.y | 17 ++++- | ||
33 | src/backend/catalog/index.c | 10 +-- | ||
34 | src/backend/catalog/pg_constraint.c | 19 +++++ | ||
35 | src/backend/commands/indexcmds.c | 22 ++++-- | ||
36 | src/backend/commands/tablecmds.c | 137 +++++++++++++++++++++++++---------- | ||
37 | src/backend/commands/trigger.c | 28 ++++++-- | ||
38 | src/backend/nodes/copyfuncs.c | 1 + | ||
39 | src/backend/nodes/equalfuncs.c | 1 + | ||
40 | src/backend/nodes/outfuncs.c | 1 + | ||
41 | src/backend/parser/parse_utilcmd.c | 64 ++++++----------- | ||
42 | src/backend/tcop/utility.c | 73 +++++++------------ | ||
43 | src/include/catalog/pg_constraint.h | 1 + | ||
44 | src/include/commands/defrem.h | 4 +- | ||
45 | src/include/commands/tablecmds.h | 2 + | ||
46 | src/include/commands/trigger.h | 2 +- | ||
47 | src/include/nodes/parsenodes.h | 2 + | ||
48 | src/include/parser/parse_utilcmd.h | 5 +- | ||
49 | src/include/tcop/utility.h | 2 - | ||
50 | 18 files changed, 234 insertions(+), 157 deletions(-) | ||
51 | |||
52 | diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y | ||
53 | index f4a1b8f..eeffb0f 100644 | ||
54 | --- a/src/backend/bootstrap/bootparse.y | ||
55 | +++ b/src/backend/bootstrap/bootparse.y | ||
56 | @@ -27,6 +27,7 @@ | ||
57 | #include "bootstrap/bootstrap.h" | ||
58 | #include "catalog/catalog.h" | ||
59 | #include "catalog/heap.h" | ||
60 | +#include "catalog/namespace.h" | ||
61 | #include "catalog/pg_am.h" | ||
62 | #include "catalog/pg_attribute.h" | ||
63 | #include "catalog/pg_authid.h" | ||
64 | @@ -281,6 +282,7 @@ Boot_DeclareIndexStmt: | ||
65 | XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN | ||
66 | { | ||
67 | IndexStmt *stmt = makeNode(IndexStmt); | ||
68 | + Oid relationId; | ||
69 | |||
70 | do_start(); | ||
71 | |||
72 | @@ -302,7 +304,12 @@ Boot_DeclareIndexStmt: | ||
73 | stmt->initdeferred = false; | ||
74 | stmt->concurrent = false; | ||
75 | |||
76 | - DefineIndex(stmt, | ||
77 | + /* locks and races need not concern us in bootstrap mode */ | ||
78 | + relationId = RangeVarGetRelid(stmt->relation, NoLock, | ||
79 | + false); | ||
80 | + | ||
81 | + DefineIndex(relationId, | ||
82 | + stmt, | ||
83 | $4, | ||
84 | false, | ||
85 | false, | ||
86 | @@ -316,6 +323,7 @@ Boot_DeclareUniqueIndexStmt: | ||
87 | XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN | ||
88 | { | ||
89 | IndexStmt *stmt = makeNode(IndexStmt); | ||
90 | + Oid relationId; | ||
91 | |||
92 | do_start(); | ||
93 | |||
94 | @@ -337,7 +345,12 @@ Boot_DeclareUniqueIndexStmt: | ||
95 | stmt->initdeferred = false; | ||
96 | stmt->concurrent = false; | ||
97 | |||
98 | - DefineIndex(stmt, | ||
99 | + /* locks and races need not concern us in bootstrap mode */ | ||
100 | + relationId = RangeVarGetRelid(stmt->relation, NoLock, | ||
101 | + false); | ||
102 | + | ||
103 | + DefineIndex(relationId, | ||
104 | + stmt, | ||
105 | $5, | ||
106 | false, | ||
107 | false, | ||
108 | diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c | ||
109 | index 7d6346a..ca8acf3 100644 | ||
110 | --- a/src/backend/catalog/index.c | ||
111 | +++ b/src/backend/catalog/index.c | ||
112 | @@ -1202,18 +1202,13 @@ index_constraint_create(Relation heapRelation, | ||
113 | */ | ||
114 | if (deferrable) | ||
115 | { | ||
116 | - RangeVar *heapRel; | ||
117 | CreateTrigStmt *trigger; | ||
118 | |||
119 | - heapRel = makeRangeVar(get_namespace_name(namespaceId), | ||
120 | - pstrdup(RelationGetRelationName(heapRelation)), | ||
121 | - -1); | ||
122 | - | ||
123 | trigger = makeNode(CreateTrigStmt); | ||
124 | trigger->trigname = (constraintType == CONSTRAINT_PRIMARY) ? | ||
125 | "PK_ConstraintTrigger" : | ||
126 | "Unique_ConstraintTrigger"; | ||
127 | - trigger->relation = heapRel; | ||
128 | + trigger->relation = NULL; | ||
129 | trigger->funcname = SystemFuncName("unique_key_recheck"); | ||
130 | trigger->args = NIL; | ||
131 | trigger->row = true; | ||
132 | @@ -1226,7 +1221,8 @@ index_constraint_create(Relation heapRelation, | ||
133 | trigger->initdeferred = initdeferred; | ||
134 | trigger->constrrel = NULL; | ||
135 | |||
136 | - (void) CreateTrigger(trigger, NULL, conOid, indexRelationId, true); | ||
137 | + (void) CreateTrigger(trigger, NULL, RelationGetRelid(heapRelation), | ||
138 | + InvalidOid, conOid, indexRelationId, true); | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c | ||
143 | index 107a780..08a94cf 100644 | ||
144 | --- a/src/backend/catalog/pg_constraint.c | ||
145 | +++ b/src/backend/catalog/pg_constraint.c | ||
146 | @@ -746,6 +746,25 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | + * get_constraint_relation_oids | ||
151 | + * Find the IDs of the relations to which a constraint refers. | ||
152 | + */ | ||
153 | +void | ||
154 | +get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid) | ||
155 | +{ | ||
156 | + HeapTuple tup; | ||
157 | + Form_pg_constraint con; | ||
158 | + | ||
159 | + tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraint_oid)); | ||
160 | + if (!HeapTupleIsValid(tup)) /* should not happen */ | ||
161 | + elog(ERROR, "cache lookup failed for constraint %u", constraint_oid); | ||
162 | + con = (Form_pg_constraint) GETSTRUCT(tup); | ||
163 | + *conrelid = con->conrelid; | ||
164 | + *confrelid = con->confrelid; | ||
165 | + ReleaseSysCache(tup); | ||
166 | +} | ||
167 | + | ||
168 | +/* | ||
169 | * get_relation_constraint_oid | ||
170 | * Find a constraint on the specified relation with the specified name. | ||
171 | * Returns constraint's OID. | ||
172 | diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c | ||
173 | index f3ee278..ec5fb0d 100644 | ||
174 | --- a/src/backend/commands/indexcmds.c | ||
175 | +++ b/src/backend/commands/indexcmds.c | ||
176 | @@ -111,7 +111,6 @@ static void RangeVarCallbackForReindexIndex(const RangeVar *relation, | ||
177 | */ | ||
178 | bool | ||
179 | CheckIndexCompatible(Oid oldId, | ||
180 | - RangeVar *heapRelation, | ||
181 | char *accessMethodName, | ||
182 | List *attributeList, | ||
183 | List *exclusionOpNames) | ||
184 | @@ -139,7 +138,7 @@ CheckIndexCompatible(Oid oldId, | ||
185 | Datum d; | ||
186 | |||
187 | /* Caller should already have the relation locked in some way. */ | ||
188 | - relationId = RangeVarGetRelid(heapRelation, NoLock, false); | ||
189 | + relationId = IndexGetRelation(oldId, false); | ||
190 | |||
191 | /* | ||
192 | * We can pretend isconstraint = false unconditionally. It only serves to | ||
193 | @@ -279,6 +278,8 @@ CheckIndexCompatible(Oid oldId, | ||
194 | * DefineIndex | ||
195 | * Creates a new index. | ||
196 | * | ||
197 | + * 'relationId': the OID of the heap relation on which the index is to be | ||
198 | + * created | ||
199 | * 'stmt': IndexStmt describing the properties of the new index. | ||
200 | * 'indexRelationId': normally InvalidOid, but during bootstrap can be | ||
201 | * nonzero to specify a preselected OID for the index. | ||
202 | @@ -292,7 +293,8 @@ CheckIndexCompatible(Oid oldId, | ||
203 | * Returns the OID of the created index. | ||
204 | */ | ||
205 | Oid | ||
206 | -DefineIndex(IndexStmt *stmt, | ||
207 | +DefineIndex(Oid relationId, | ||
208 | + IndexStmt *stmt, | ||
209 | Oid indexRelationId, | ||
210 | bool is_alter_table, | ||
211 | bool check_rights, | ||
212 | @@ -305,7 +307,6 @@ DefineIndex(IndexStmt *stmt, | ||
213 | Oid *collationObjectId; | ||
214 | Oid *classObjectId; | ||
215 | Oid accessMethodId; | ||
216 | - Oid relationId; | ||
217 | Oid namespaceId; | ||
218 | Oid tablespaceId; | ||
219 | List *indexColNames; | ||
220 | @@ -325,6 +326,7 @@ DefineIndex(IndexStmt *stmt, | ||
221 | int n_old_snapshots; | ||
222 | LockRelId heaprelid; | ||
223 | LOCKTAG heaplocktag; | ||
224 | + LOCKMODE lockmode; | ||
225 | Snapshot snapshot; | ||
226 | int i; | ||
227 | |||
228 | @@ -343,14 +345,18 @@ DefineIndex(IndexStmt *stmt, | ||
229 | INDEX_MAX_KEYS))); | ||
230 | |||
231 | /* | ||
232 | - * Open heap relation, acquire a suitable lock on it, remember its OID | ||
233 | - * | ||
234 | * Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard | ||
235 | * index build; but for concurrent builds we allow INSERT/UPDATE/DELETE | ||
236 | * (but not VACUUM). | ||
237 | + * | ||
238 | + * NB: Caller is responsible for making sure that relationId refers | ||
239 | + * to the relation on which the index should be built; except in bootstrap | ||
240 | + * mode, this will typically require the caller to have already locked | ||
241 | + * the relation. To avoid lock upgrade hazards, that lock should be at | ||
242 | + * least as strong as the one we take here. | ||
243 | */ | ||
244 | - rel = heap_openrv(stmt->relation, | ||
245 | - (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock)); | ||
246 | + lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock; | ||
247 | + rel = heap_open(relationId, lockmode); | ||
248 | |||
249 | relationId = RelationGetRelid(rel); | ||
250 | namespaceId = RelationGetNamespace(rel); | ||
251 | diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c | ||
252 | index 7c1f779..bcb81ea 100644 | ||
253 | --- a/src/backend/commands/tablecmds.c | ||
254 | +++ b/src/backend/commands/tablecmds.c | ||
255 | @@ -283,7 +283,8 @@ static void validateCheckConstraint(Relation rel, HeapTuple constrtup); | ||
256 | static void validateForeignKeyConstraint(char *conname, | ||
257 | Relation rel, Relation pkrel, | ||
258 | Oid pkindOid, Oid constraintOid); | ||
259 | -static void createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, | ||
260 | +static void createForeignKeyTriggers(Relation rel, Oid refRelOid, | ||
261 | + Constraint *fkconstraint, | ||
262 | Oid constraintOid, Oid indexOid); | ||
263 | static void ATController(Relation rel, List *cmds, bool recurse, LOCKMODE lockmode); | ||
264 | static void ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd, | ||
265 | @@ -360,8 +361,9 @@ static void ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, | ||
266 | static void ATExecAlterColumnGenericOptions(Relation rel, const char *colName, | ||
267 | List *options, LOCKMODE lockmode); | ||
268 | static void ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode); | ||
269 | -static void ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
270 | - List **wqueue, LOCKMODE lockmode, bool rewrite); | ||
271 | +static void ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, | ||
272 | + char *cmd, List **wqueue, LOCKMODE lockmode, | ||
273 | + bool rewrite); | ||
274 | static void TryReuseIndex(Oid oldId, IndexStmt *stmt); | ||
275 | static void TryReuseForeignKey(Oid oldId, Constraint *con); | ||
276 | static void change_owner_fix_column_acls(Oid relationOid, | ||
277 | @@ -5406,7 +5408,8 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel, | ||
278 | |||
279 | /* The IndexStmt has already been through transformIndexStmt */ | ||
280 | |||
281 | - new_index = DefineIndex(stmt, | ||
282 | + new_index = DefineIndex(RelationGetRelid(rel), | ||
283 | + stmt, | ||
284 | InvalidOid, /* no predefined OID */ | ||
285 | true, /* is_alter_table */ | ||
286 | check_rights, | ||
287 | @@ -5728,7 +5731,10 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, | ||
288 | * table; trying to start with a lesser lock will just create a risk of | ||
289 | * deadlock.) | ||
290 | */ | ||
291 | - pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock); | ||
292 | + if (OidIsValid(fkconstraint->old_pktable_oid)) | ||
293 | + pkrel = heap_open(fkconstraint->old_pktable_oid, AccessExclusiveLock); | ||
294 | + else | ||
295 | + pkrel = heap_openrv(fkconstraint->pktable, AccessExclusiveLock); | ||
296 | |||
297 | /* | ||
298 | * Validity checks (permission checks wait till we have the column | ||
299 | @@ -6066,7 +6072,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel, | ||
300 | /* | ||
301 | * Create the triggers that will enforce the constraint. | ||
302 | */ | ||
303 | - createForeignKeyTriggers(rel, fkconstraint, constrOid, indexOid); | ||
304 | + createForeignKeyTriggers(rel, RelationGetRelid(pkrel), fkconstraint, | ||
305 | + constrOid, indexOid); | ||
306 | |||
307 | /* | ||
308 | * Tell Phase 3 to check that the constraint is satisfied by existing | ||
309 | @@ -6736,7 +6743,7 @@ validateForeignKeyConstraint(char *conname, | ||
310 | } | ||
311 | |||
312 | static void | ||
313 | -CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, | ||
314 | +CreateFKCheckTrigger(Oid myRelOid, Oid refRelOid, Constraint *fkconstraint, | ||
315 | Oid constraintOid, Oid indexOid, bool on_insert) | ||
316 | { | ||
317 | CreateTrigStmt *fk_trigger; | ||
318 | @@ -6752,7 +6759,7 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, | ||
319 | */ | ||
320 | fk_trigger = makeNode(CreateTrigStmt); | ||
321 | fk_trigger->trigname = "RI_ConstraintTrigger_c"; | ||
322 | - fk_trigger->relation = myRel; | ||
323 | + fk_trigger->relation = NULL; | ||
324 | fk_trigger->row = true; | ||
325 | fk_trigger->timing = TRIGGER_TYPE_AFTER; | ||
326 | |||
327 | @@ -6773,10 +6780,11 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, | ||
328 | fk_trigger->isconstraint = true; | ||
329 | fk_trigger->deferrable = fkconstraint->deferrable; | ||
330 | fk_trigger->initdeferred = fkconstraint->initdeferred; | ||
331 | - fk_trigger->constrrel = fkconstraint->pktable; | ||
332 | + fk_trigger->constrrel = NULL; | ||
333 | fk_trigger->args = NIL; | ||
334 | |||
335 | - (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true); | ||
336 | + (void) CreateTrigger(fk_trigger, NULL, myRelOid, refRelOid, constraintOid, | ||
337 | + indexOid, true); | ||
338 | |||
339 | /* Make changes-so-far visible */ | ||
340 | CommandCounterIncrement(); | ||
341 | @@ -6786,18 +6794,13 @@ CreateFKCheckTrigger(RangeVar *myRel, Constraint *fkconstraint, | ||
342 | * Create the triggers that implement an FK constraint. | ||
343 | */ | ||
344 | static void | ||
345 | -createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, | ||
346 | +createForeignKeyTriggers(Relation rel, Oid refRelOid, Constraint *fkconstraint, | ||
347 | Oid constraintOid, Oid indexOid) | ||
348 | { | ||
349 | - RangeVar *myRel; | ||
350 | + Oid myRelOid; | ||
351 | CreateTrigStmt *fk_trigger; | ||
352 | |||
353 | - /* | ||
354 | - * Reconstruct a RangeVar for my relation (not passed in, unfortunately). | ||
355 | - */ | ||
356 | - myRel = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)), | ||
357 | - pstrdup(RelationGetRelationName(rel)), | ||
358 | - -1); | ||
359 | + myRelOid = RelationGetRelid(rel); | ||
360 | |||
361 | /* Make changes-so-far visible */ | ||
362 | CommandCounterIncrement(); | ||
363 | @@ -6808,14 +6811,14 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, | ||
364 | */ | ||
365 | fk_trigger = makeNode(CreateTrigStmt); | ||
366 | fk_trigger->trigname = "RI_ConstraintTrigger_a"; | ||
367 | - fk_trigger->relation = fkconstraint->pktable; | ||
368 | + fk_trigger->relation = NULL; | ||
369 | fk_trigger->row = true; | ||
370 | fk_trigger->timing = TRIGGER_TYPE_AFTER; | ||
371 | fk_trigger->events = TRIGGER_TYPE_DELETE; | ||
372 | fk_trigger->columns = NIL; | ||
373 | fk_trigger->whenClause = NULL; | ||
374 | fk_trigger->isconstraint = true; | ||
375 | - fk_trigger->constrrel = myRel; | ||
376 | + fk_trigger->constrrel = NULL; | ||
377 | switch (fkconstraint->fk_del_action) | ||
378 | { | ||
379 | case FKCONSTR_ACTION_NOACTION: | ||
380 | @@ -6850,7 +6853,8 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, | ||
381 | } | ||
382 | fk_trigger->args = NIL; | ||
383 | |||
384 | - (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true); | ||
385 | + (void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid, | ||
386 | + indexOid, true); | ||
387 | |||
388 | /* Make changes-so-far visible */ | ||
389 | CommandCounterIncrement(); | ||
390 | @@ -6861,14 +6865,14 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, | ||
391 | */ | ||
392 | fk_trigger = makeNode(CreateTrigStmt); | ||
393 | fk_trigger->trigname = "RI_ConstraintTrigger_a"; | ||
394 | - fk_trigger->relation = fkconstraint->pktable; | ||
395 | + fk_trigger->relation = NULL; | ||
396 | fk_trigger->row = true; | ||
397 | fk_trigger->timing = TRIGGER_TYPE_AFTER; | ||
398 | fk_trigger->events = TRIGGER_TYPE_UPDATE; | ||
399 | fk_trigger->columns = NIL; | ||
400 | fk_trigger->whenClause = NULL; | ||
401 | fk_trigger->isconstraint = true; | ||
402 | - fk_trigger->constrrel = myRel; | ||
403 | + fk_trigger->constrrel = NULL; | ||
404 | switch (fkconstraint->fk_upd_action) | ||
405 | { | ||
406 | case FKCONSTR_ACTION_NOACTION: | ||
407 | @@ -6903,7 +6907,8 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, | ||
408 | } | ||
409 | fk_trigger->args = NIL; | ||
410 | |||
411 | - (void) CreateTrigger(fk_trigger, NULL, constraintOid, indexOid, true); | ||
412 | + (void) CreateTrigger(fk_trigger, NULL, refRelOid, myRelOid, constraintOid, | ||
413 | + indexOid, true); | ||
414 | |||
415 | /* Make changes-so-far visible */ | ||
416 | CommandCounterIncrement(); | ||
417 | @@ -6912,8 +6917,10 @@ createForeignKeyTriggers(Relation rel, Constraint *fkconstraint, | ||
418 | * Build and execute CREATE CONSTRAINT TRIGGER statements for the CHECK | ||
419 | * action for both INSERTs and UPDATEs on the referencing table. | ||
420 | */ | ||
421 | - CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, true); | ||
422 | - CreateFKCheckTrigger(myRel, fkconstraint, constraintOid, indexOid, false); | ||
423 | + CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid, | ||
424 | + indexOid, true); | ||
425 | + CreateFKCheckTrigger(myRelOid, refRelOid, fkconstraint, constraintOid, | ||
426 | + indexOid, false); | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | @@ -7832,15 +7839,36 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) | ||
431 | * lock on the table the constraint is attached to, and we need to get | ||
432 | * that before dropping. It's safe because the parser won't actually look | ||
433 | * at the catalogs to detect the existing entry. | ||
434 | + * | ||
435 | + * We can't rely on the output of deparsing to tell us which relation | ||
436 | + * to operate on, because concurrent activity might have made the name | ||
437 | + * resolve differently. Instead, we've got to use the OID of the | ||
438 | + * constraint or index we're processing to figure out which relation | ||
439 | + * to operate on. | ||
440 | */ | ||
441 | forboth(oid_item, tab->changedConstraintOids, | ||
442 | def_item, tab->changedConstraintDefs) | ||
443 | - ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item), | ||
444 | + { | ||
445 | + Oid oldId = lfirst_oid(oid_item); | ||
446 | + Oid relid; | ||
447 | + Oid confrelid; | ||
448 | + | ||
449 | + get_constraint_relation_oids(oldId, &relid, &confrelid); | ||
450 | + ATPostAlterTypeParse(oldId, relid, confrelid, | ||
451 | + (char *) lfirst(def_item), | ||
452 | wqueue, lockmode, tab->rewrite); | ||
453 | + } | ||
454 | forboth(oid_item, tab->changedIndexOids, | ||
455 | def_item, tab->changedIndexDefs) | ||
456 | - ATPostAlterTypeParse(lfirst_oid(oid_item), (char *) lfirst(def_item), | ||
457 | + { | ||
458 | + Oid oldId = lfirst_oid(oid_item); | ||
459 | + Oid relid; | ||
460 | + | ||
461 | + relid = IndexGetRelation(oldId, false); | ||
462 | + ATPostAlterTypeParse(oldId, relid, InvalidOid, | ||
463 | + (char *) lfirst(def_item), | ||
464 | wqueue, lockmode, tab->rewrite); | ||
465 | + } | ||
466 | |||
467 | /* | ||
468 | * Now we can drop the existing constraints and indexes --- constraints | ||
469 | @@ -7873,12 +7901,13 @@ ATPostAlterTypeCleanup(List **wqueue, AlteredTableInfo *tab, LOCKMODE lockmode) | ||
470 | } | ||
471 | |||
472 | static void | ||
473 | -ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
474 | +ATPostAlterTypeParse(Oid oldId, Oid oldRelId, Oid refRelId, char *cmd, | ||
475 | List **wqueue, LOCKMODE lockmode, bool rewrite) | ||
476 | { | ||
477 | List *raw_parsetree_list; | ||
478 | List *querytree_list; | ||
479 | ListCell *list_item; | ||
480 | + Relation rel; | ||
481 | |||
482 | /* | ||
483 | * We expect that we will get only ALTER TABLE and CREATE INDEX | ||
484 | @@ -7894,16 +7923,21 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
485 | |||
486 | if (IsA(stmt, IndexStmt)) | ||
487 | querytree_list = lappend(querytree_list, | ||
488 | - transformIndexStmt((IndexStmt *) stmt, | ||
489 | + transformIndexStmt(oldRelId, | ||
490 | + (IndexStmt *) stmt, | ||
491 | cmd)); | ||
492 | else if (IsA(stmt, AlterTableStmt)) | ||
493 | querytree_list = list_concat(querytree_list, | ||
494 | - transformAlterTableStmt((AlterTableStmt *) stmt, | ||
495 | + transformAlterTableStmt(oldRelId, | ||
496 | + (AlterTableStmt *) stmt, | ||
497 | cmd)); | ||
498 | else | ||
499 | querytree_list = lappend(querytree_list, stmt); | ||
500 | } | ||
501 | |||
502 | + /* Caller should already have acquired whatever lock we need. */ | ||
503 | + rel = relation_open(oldRelId, NoLock); | ||
504 | + | ||
505 | /* | ||
506 | * Attach each generated command to the proper place in the work queue. | ||
507 | * Note this could result in creation of entirely new work-queue entries. | ||
508 | @@ -7915,7 +7949,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
509 | foreach(list_item, querytree_list) | ||
510 | { | ||
511 | Node *stm = (Node *) lfirst(list_item); | ||
512 | - Relation rel; | ||
513 | AlteredTableInfo *tab; | ||
514 | |||
515 | switch (nodeTag(stm)) | ||
516 | @@ -7928,14 +7961,12 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
517 | if (!rewrite) | ||
518 | TryReuseIndex(oldId, stmt); | ||
519 | |||
520 | - rel = relation_openrv(stmt->relation, lockmode); | ||
521 | tab = ATGetQueueEntry(wqueue, rel); | ||
522 | newcmd = makeNode(AlterTableCmd); | ||
523 | newcmd->subtype = AT_ReAddIndex; | ||
524 | newcmd->def = (Node *) stmt; | ||
525 | tab->subcmds[AT_PASS_OLD_INDEX] = | ||
526 | lappend(tab->subcmds[AT_PASS_OLD_INDEX], newcmd); | ||
527 | - relation_close(rel, NoLock); | ||
528 | break; | ||
529 | } | ||
530 | case T_AlterTableStmt: | ||
531 | @@ -7943,7 +7974,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
532 | AlterTableStmt *stmt = (AlterTableStmt *) stm; | ||
533 | ListCell *lcmd; | ||
534 | |||
535 | - rel = relation_openrv(stmt->relation, lockmode); | ||
536 | tab = ATGetQueueEntry(wqueue, rel); | ||
537 | foreach(lcmd, stmt->cmds) | ||
538 | { | ||
539 | @@ -7964,6 +7994,7 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
540 | case AT_AddConstraint: | ||
541 | Assert(IsA(cmd->def, Constraint)); | ||
542 | con = (Constraint *) cmd->def; | ||
543 | + con->old_pktable_oid = refRelId; | ||
544 | /* rewriting neither side of a FK */ | ||
545 | if (con->contype == CONSTR_FOREIGN && | ||
546 | !rewrite && !tab->rewrite) | ||
547 | @@ -7977,7 +8008,6 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
548 | (int) cmd->subtype); | ||
549 | } | ||
550 | } | ||
551 | - relation_close(rel, NoLock); | ||
552 | break; | ||
553 | } | ||
554 | default: | ||
555 | @@ -7985,6 +8015,8 @@ ATPostAlterTypeParse(Oid oldId, char *cmd, | ||
556 | (int) nodeTag(stm)); | ||
557 | } | ||
558 | } | ||
559 | + | ||
560 | + relation_close(rel, NoLock); | ||
561 | } | ||
562 | |||
563 | /* | ||
564 | @@ -7995,7 +8027,6 @@ static void | ||
565 | TryReuseIndex(Oid oldId, IndexStmt *stmt) | ||
566 | { | ||
567 | if (CheckIndexCompatible(oldId, | ||
568 | - stmt->relation, | ||
569 | stmt->accessMethod, | ||
570 | stmt->indexParams, | ||
571 | stmt->excludeOpNames)) | ||
572 | @@ -10291,6 +10322,38 @@ RangeVarCallbackOwnsTable(const RangeVar *relation, | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | + * Callback to RangeVarGetRelidExtended(), similar to | ||
577 | + * RangeVarCallbackOwnsTable() but without checks on the type of the relation. | ||
578 | + */ | ||
579 | +void | ||
580 | +RangeVarCallbackOwnsRelation(const RangeVar *relation, | ||
581 | + Oid relId, Oid oldRelId, void *arg) | ||
582 | +{ | ||
583 | + HeapTuple tuple; | ||
584 | + | ||
585 | + /* Nothing to do if the relation was not found. */ | ||
586 | + if (!OidIsValid(relId)) | ||
587 | + return; | ||
588 | + | ||
589 | + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relId)); | ||
590 | + if (!HeapTupleIsValid(tuple)) /* should not happen */ | ||
591 | + elog(ERROR, "cache lookup failed for relation %u", relId); | ||
592 | + | ||
593 | + if (!pg_class_ownercheck(relId, GetUserId())) | ||
594 | + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, | ||
595 | + relation->relname); | ||
596 | + | ||
597 | + if (!allowSystemTableMods && | ||
598 | + IsSystemClass((Form_pg_class) GETSTRUCT(tuple))) | ||
599 | + ereport(ERROR, | ||
600 | + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), | ||
601 | + errmsg("permission denied: \"%s\" is a system catalog", | ||
602 | + relation->relname))); | ||
603 | + | ||
604 | + ReleaseSysCache(tuple); | ||
605 | +} | ||
606 | + | ||
607 | +/* | ||
608 | * Common RangeVarGetRelid callback for rename, set schema, and alter table | ||
609 | * processing. | ||
610 | */ | ||
611 | diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c | ||
612 | index f546d94..9e6c954 100644 | ||
613 | --- a/src/backend/commands/trigger.c | ||
614 | +++ b/src/backend/commands/trigger.c | ||
615 | @@ -42,6 +42,7 @@ | ||
616 | #include "pgstat.h" | ||
617 | #include "rewrite/rewriteManip.h" | ||
618 | #include "storage/bufmgr.h" | ||
619 | +#include "storage/lmgr.h" | ||
620 | #include "tcop/utility.h" | ||
621 | #include "utils/acl.h" | ||
622 | #include "utils/builtins.h" | ||
623 | @@ -94,6 +95,13 @@ static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, | ||
624 | * queryString is the source text of the CREATE TRIGGER command. | ||
625 | * This must be supplied if a whenClause is specified, else it can be NULL. | ||
626 | * | ||
627 | + * relOid, if nonzero, is the relation on which the trigger should be | ||
628 | + * created. If zero, the name provided in the statement will be looked up. | ||
629 | + * | ||
630 | + * refRelOid, if nonzero, is the relation to which the constraint trigger | ||
631 | + * refers. If zero, the constraint relation name provided in the statement | ||
632 | + * will be looked up as needed. | ||
633 | + * | ||
634 | * constraintOid, if nonzero, says that this trigger is being created | ||
635 | * internally to implement that constraint. A suitable pg_depend entry will | ||
636 | * be made to link the trigger to that constraint. constraintOid is zero when | ||
637 | @@ -116,7 +124,7 @@ static void AfterTriggerSaveEvent(EState *estate, ResultRelInfo *relinfo, | ||
638 | */ | ||
639 | Oid | ||
640 | CreateTrigger(CreateTrigStmt *stmt, const char *queryString, | ||
641 | - Oid constraintOid, Oid indexOid, | ||
642 | + Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, | ||
643 | bool isInternal) | ||
644 | { | ||
645 | int16 tgtype; | ||
646 | @@ -145,7 +153,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, | ||
647 | ObjectAddress myself, | ||
648 | referenced; | ||
649 | |||
650 | - rel = heap_openrv(stmt->relation, AccessExclusiveLock); | ||
651 | + if (OidIsValid(relOid)) | ||
652 | + rel = heap_open(relOid, AccessExclusiveLock); | ||
653 | + else | ||
654 | + rel = heap_openrv(stmt->relation, AccessExclusiveLock); | ||
655 | |||
656 | /* | ||
657 | * Triggers must be on tables or views, and there are additional | ||
658 | @@ -194,7 +205,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, | ||
659 | errmsg("permission denied: \"%s\" is a system catalog", | ||
660 | RelationGetRelationName(rel)))); | ||
661 | |||
662 | - if (stmt->isconstraint && stmt->constrrel != NULL) | ||
663 | + if (stmt->isconstraint) | ||
664 | { | ||
665 | /* | ||
666 | * We must take a lock on the target relation to protect against | ||
667 | @@ -203,7 +214,14 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, | ||
668 | * might end up creating a pg_constraint entry referencing a | ||
669 | * nonexistent table. | ||
670 | */ | ||
671 | - constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock, false); | ||
672 | + if (OidIsValid(refRelOid)) | ||
673 | + { | ||
674 | + LockRelationOid(refRelOid, AccessShareLock); | ||
675 | + constrrelid = refRelOid; | ||
676 | + } | ||
677 | + else if (stmt->constrrel != NULL) | ||
678 | + constrrelid = RangeVarGetRelid(stmt->constrrel, AccessShareLock, | ||
679 | + false); | ||
680 | } | ||
681 | |||
682 | /* permission checks */ | ||
683 | @@ -513,7 +531,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString, | ||
684 | ereport(ERROR, | ||
685 | (errcode(ERRCODE_DUPLICATE_OBJECT), | ||
686 | errmsg("trigger \"%s\" for relation \"%s\" already exists", | ||
687 | - trigname, stmt->relation->relname))); | ||
688 | + trigname, RelationGetRelationName(rel)))); | ||
689 | } | ||
690 | systable_endscan(tgscan); | ||
691 | } | ||
692 | diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c | ||
693 | index 9bac994..dbe0f6a 100644 | ||
694 | --- a/src/backend/nodes/copyfuncs.c | ||
695 | +++ b/src/backend/nodes/copyfuncs.c | ||
696 | @@ -2357,6 +2357,7 @@ _copyConstraint(const Constraint *from) | ||
697 | COPY_SCALAR_FIELD(fk_upd_action); | ||
698 | COPY_SCALAR_FIELD(fk_del_action); | ||
699 | COPY_NODE_FIELD(old_conpfeqop); | ||
700 | + COPY_SCALAR_FIELD(old_pktable_oid); | ||
701 | COPY_SCALAR_FIELD(skip_validation); | ||
702 | COPY_SCALAR_FIELD(initially_valid); | ||
703 | |||
704 | diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c | ||
705 | index d185654..f8770b0 100644 | ||
706 | --- a/src/backend/nodes/equalfuncs.c | ||
707 | +++ b/src/backend/nodes/equalfuncs.c | ||
708 | @@ -2143,6 +2143,7 @@ _equalConstraint(const Constraint *a, const Constraint *b) | ||
709 | COMPARE_SCALAR_FIELD(fk_upd_action); | ||
710 | COMPARE_SCALAR_FIELD(fk_del_action); | ||
711 | COMPARE_NODE_FIELD(old_conpfeqop); | ||
712 | + COMPARE_SCALAR_FIELD(old_pktable_oid); | ||
713 | COMPARE_SCALAR_FIELD(skip_validation); | ||
714 | COMPARE_SCALAR_FIELD(initially_valid); | ||
715 | |||
716 | diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c | ||
717 | index 1df71f6..888ffd2 100644 | ||
718 | --- a/src/backend/nodes/outfuncs.c | ||
719 | +++ b/src/backend/nodes/outfuncs.c | ||
720 | @@ -2653,6 +2653,7 @@ _outConstraint(StringInfo str, const Constraint *node) | ||
721 | WRITE_CHAR_FIELD(fk_upd_action); | ||
722 | WRITE_CHAR_FIELD(fk_del_action); | ||
723 | WRITE_NODE_FIELD(old_conpfeqop); | ||
724 | + WRITE_OID_FIELD(old_pktable_oid); | ||
725 | WRITE_BOOL_FIELD(skip_validation); | ||
726 | WRITE_BOOL_FIELD(initially_valid); | ||
727 | break; | ||
728 | diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c | ||
729 | index e3f9c62..5df939a 100644 | ||
730 | --- a/src/backend/parser/parse_utilcmd.c | ||
731 | +++ b/src/backend/parser/parse_utilcmd.c | ||
732 | @@ -1867,14 +1867,18 @@ transformFKConstraints(CreateStmtContext *cxt, | ||
733 | * a predicate expression. There are several code paths that create indexes | ||
734 | * without bothering to call this, because they know they don't have any | ||
735 | * such expressions to deal with. | ||
736 | + * | ||
737 | + * To avoid race conditions, it's important that this function rely only on | ||
738 | + * the passed-in relid (and not on stmt->relation) to determine the target | ||
739 | + * relation. | ||
740 | */ | ||
741 | IndexStmt * | ||
742 | -transformIndexStmt(IndexStmt *stmt, const char *queryString) | ||
743 | +transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString) | ||
744 | { | ||
745 | - Relation rel; | ||
746 | ParseState *pstate; | ||
747 | RangeTblEntry *rte; | ||
748 | ListCell *l; | ||
749 | + Relation rel; | ||
750 | |||
751 | /* | ||
752 | * We must not scribble on the passed-in IndexStmt, so copy it. (This is | ||
753 | @@ -1882,26 +1886,17 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString) | ||
754 | */ | ||
755 | stmt = (IndexStmt *) copyObject(stmt); | ||
756 | |||
757 | - /* | ||
758 | - * Open the parent table with appropriate locking. We must do this | ||
759 | - * because addRangeTableEntry() would acquire only AccessShareLock, | ||
760 | - * leaving DefineIndex() needing to do a lock upgrade with consequent risk | ||
761 | - * of deadlock. Make sure this stays in sync with the type of lock | ||
762 | - * DefineIndex() wants. If we are being called by ALTER TABLE, we will | ||
763 | - * already hold a higher lock. | ||
764 | - */ | ||
765 | - rel = heap_openrv(stmt->relation, | ||
766 | - (stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock)); | ||
767 | - | ||
768 | /* Set up pstate */ | ||
769 | pstate = make_parsestate(NULL); | ||
770 | pstate->p_sourcetext = queryString; | ||
771 | |||
772 | /* | ||
773 | * Put the parent table into the rtable so that the expressions can refer | ||
774 | - * to its fields without qualification. | ||
775 | + * to its fields without qualification. Caller is responsible for locking | ||
776 | + * relation, but we still need to open it. | ||
777 | */ | ||
778 | - rte = addRangeTableEntry(pstate, stmt->relation, NULL, false, true); | ||
779 | + rel = relation_open(relid, NoLock); | ||
780 | + rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true); | ||
781 | |||
782 | /* no to join list, yes to namespaces */ | ||
783 | addRTEtoQuery(pstate, rte, false, true, true); | ||
784 | @@ -1955,7 +1950,7 @@ transformIndexStmt(IndexStmt *stmt, const char *queryString) | ||
785 | |||
786 | free_parsestate(pstate); | ||
787 | |||
788 | - /* Close relation, but keep the lock */ | ||
789 | + /* Close relation */ | ||
790 | heap_close(rel, NoLock); | ||
791 | |||
792 | return stmt; | ||
793 | @@ -2277,9 +2272,14 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString, | ||
794 | * Returns a List of utility commands to be done in sequence. One of these | ||
795 | * will be the transformed AlterTableStmt, but there may be additional actions | ||
796 | * to be done before and after the actual AlterTable() call. | ||
797 | + * | ||
798 | + * To avoid race conditions, it's important that this function rely only on | ||
799 | + * the passed-in relid (and not on stmt->relation) to determine the target | ||
800 | + * relation. | ||
801 | */ | ||
802 | List * | ||
803 | -transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) | ||
804 | +transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, | ||
805 | + const char *queryString) | ||
806 | { | ||
807 | Relation rel; | ||
808 | ParseState *pstate; | ||
809 | @@ -2291,7 +2291,6 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) | ||
810 | List *newcmds = NIL; | ||
811 | bool skipValidation = true; | ||
812 | AlterTableCmd *newcmd; | ||
813 | - LOCKMODE lockmode; | ||
814 | |||
815 | /* | ||
816 | * We must not scribble on the passed-in AlterTableStmt, so copy it. (This | ||
817 | @@ -2299,29 +2298,8 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) | ||
818 | */ | ||
819 | stmt = (AlterTableStmt *) copyObject(stmt); | ||
820 | |||
821 | - /* | ||
822 | - * Determine the appropriate lock level for this list of subcommands. | ||
823 | - */ | ||
824 | - lockmode = AlterTableGetLockLevel(stmt->cmds); | ||
825 | - | ||
826 | - /* | ||
827 | - * Acquire appropriate lock on the target relation, which will be held | ||
828 | - * until end of transaction. This ensures any decisions we make here | ||
829 | - * based on the state of the relation will still be good at execution. We | ||
830 | - * must get lock now because execution will later require it; taking a | ||
831 | - * lower grade lock now and trying to upgrade later risks deadlock. Any | ||
832 | - * new commands we add after this must not upgrade the lock level | ||
833 | - * requested here. | ||
834 | - */ | ||
835 | - rel = relation_openrv_extended(stmt->relation, lockmode, stmt->missing_ok); | ||
836 | - if (rel == NULL) | ||
837 | - { | ||
838 | - /* this message is consistent with relation_openrv */ | ||
839 | - ereport(NOTICE, | ||
840 | - (errmsg("relation \"%s\" does not exist, skipping", | ||
841 | - stmt->relation->relname))); | ||
842 | - return NIL; | ||
843 | - } | ||
844 | + /* Caller is responsible for locking the relation */ | ||
845 | + rel = relation_open(relid, NoLock); | ||
846 | |||
847 | /* Set up pstate and CreateStmtContext */ | ||
848 | pstate = make_parsestate(NULL); | ||
849 | @@ -2434,7 +2412,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) | ||
850 | IndexStmt *idxstmt = (IndexStmt *) lfirst(l); | ||
851 | |||
852 | Assert(IsA(idxstmt, IndexStmt)); | ||
853 | - idxstmt = transformIndexStmt(idxstmt, queryString); | ||
854 | + idxstmt = transformIndexStmt(relid, idxstmt, queryString); | ||
855 | newcmd = makeNode(AlterTableCmd); | ||
856 | newcmd->subtype = OidIsValid(idxstmt->indexOid) ? AT_AddIndexConstraint : AT_AddIndex; | ||
857 | newcmd->def = (Node *) idxstmt; | ||
858 | @@ -2458,7 +2436,7 @@ transformAlterTableStmt(AlterTableStmt *stmt, const char *queryString) | ||
859 | newcmds = lappend(newcmds, newcmd); | ||
860 | } | ||
861 | |||
862 | - /* Close rel but keep lock */ | ||
863 | + /* Close rel */ | ||
864 | relation_close(rel, NoLock); | ||
865 | |||
866 | /* | ||
867 | diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c | ||
868 | index 509bf4d..7903e03 100644 | ||
869 | --- a/src/backend/tcop/utility.c | ||
870 | +++ b/src/backend/tcop/utility.c | ||
871 | @@ -67,49 +67,6 @@ ProcessUtility_hook_type ProcessUtility_hook = NULL; | ||
872 | |||
873 | |||
874 | /* | ||
875 | - * Verify user has ownership of specified relation, else ereport. | ||
876 | - * | ||
877 | - * If noCatalogs is true then we also deny access to system catalogs, | ||
878 | - * except when allowSystemTableMods is true. | ||
879 | - */ | ||
880 | -void | ||
881 | -CheckRelationOwnership(RangeVar *rel, bool noCatalogs) | ||
882 | -{ | ||
883 | - Oid relOid; | ||
884 | - HeapTuple tuple; | ||
885 | - | ||
886 | - /* | ||
887 | - * XXX: This is unsafe in the presence of concurrent DDL, since it is | ||
888 | - * called before acquiring any lock on the target relation. However, | ||
889 | - * locking the target relation (especially using something like | ||
890 | - * AccessExclusiveLock) before verifying that the user has permissions is | ||
891 | - * not appealing either. | ||
892 | - */ | ||
893 | - relOid = RangeVarGetRelid(rel, NoLock, false); | ||
894 | - | ||
895 | - tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid)); | ||
896 | - if (!HeapTupleIsValid(tuple)) /* should not happen */ | ||
897 | - elog(ERROR, "cache lookup failed for relation %u", relOid); | ||
898 | - | ||
899 | - if (!pg_class_ownercheck(relOid, GetUserId())) | ||
900 | - aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, | ||
901 | - rel->relname); | ||
902 | - | ||
903 | - if (noCatalogs) | ||
904 | - { | ||
905 | - if (!allowSystemTableMods && | ||
906 | - IsSystemClass((Form_pg_class) GETSTRUCT(tuple))) | ||
907 | - ereport(ERROR, | ||
908 | - (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), | ||
909 | - errmsg("permission denied: \"%s\" is a system catalog", | ||
910 | - rel->relname))); | ||
911 | - } | ||
912 | - | ||
913 | - ReleaseSysCache(tuple); | ||
914 | -} | ||
915 | - | ||
916 | - | ||
917 | -/* | ||
918 | * CommandIsReadOnly: is an executable query read-only? | ||
919 | * | ||
920 | * This is a much stricter test than we apply for XactReadOnly mode; | ||
921 | @@ -723,7 +680,8 @@ standard_ProcessUtility(Node *parsetree, | ||
922 | if (OidIsValid(relid)) | ||
923 | { | ||
924 | /* Run parse analysis ... */ | ||
925 | - stmts = transformAlterTableStmt(atstmt, queryString); | ||
926 | + stmts = transformAlterTableStmt(relid, atstmt, | ||
927 | + queryString); | ||
928 | |||
929 | /* ... and do it */ | ||
930 | foreach(l, stmts) | ||
931 | @@ -910,18 +868,36 @@ standard_ProcessUtility(Node *parsetree, | ||
932 | case T_IndexStmt: /* CREATE INDEX */ | ||
933 | { | ||
934 | IndexStmt *stmt = (IndexStmt *) parsetree; | ||
935 | + Oid relid; | ||
936 | + LOCKMODE lockmode; | ||
937 | |||
938 | if (stmt->concurrent) | ||
939 | PreventTransactionChain(isTopLevel, | ||
940 | "CREATE INDEX CONCURRENTLY"); | ||
941 | |||
942 | - CheckRelationOwnership(stmt->relation, true); | ||
943 | + /* | ||
944 | + * Look up the relation OID just once, right here at the | ||
945 | + * beginning, so that we don't end up repeating the name | ||
946 | + * lookup later and latching onto a different relation | ||
947 | + * partway through. To avoid lock upgrade hazards, it's | ||
948 | + * important that we take the strongest lock that will | ||
949 | + * eventually be needed here, so the lockmode calculation | ||
950 | + * needs to match what DefineIndex() does. | ||
951 | + */ | ||
952 | + lockmode = stmt->concurrent ? ShareUpdateExclusiveLock | ||
953 | + : ShareLock; | ||
954 | + relid = | ||
955 | + RangeVarGetRelidExtended(stmt->relation, lockmode, | ||
956 | + false, false, | ||
957 | + RangeVarCallbackOwnsRelation, | ||
958 | + NULL); | ||
959 | |||
960 | /* Run parse analysis ... */ | ||
961 | - stmt = transformIndexStmt(stmt, queryString); | ||
962 | + stmt = transformIndexStmt(relid, stmt, queryString); | ||
963 | |||
964 | /* ... and do it */ | ||
965 | - DefineIndex(stmt, | ||
966 | + DefineIndex(relid, /* OID of heap relation */ | ||
967 | + stmt, | ||
968 | InvalidOid, /* no predefined OID */ | ||
969 | false, /* is_alter_table */ | ||
970 | true, /* check_rights */ | ||
971 | @@ -1057,7 +1033,8 @@ standard_ProcessUtility(Node *parsetree, | ||
972 | |||
973 | case T_CreateTrigStmt: | ||
974 | (void) CreateTrigger((CreateTrigStmt *) parsetree, queryString, | ||
975 | - InvalidOid, InvalidOid, false); | ||
976 | + InvalidOid, InvalidOid, InvalidOid, | ||
977 | + InvalidOid, false); | ||
978 | break; | ||
979 | |||
980 | case T_CreatePLangStmt: | ||
981 | diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h | ||
982 | index d9d40b2..d8f8da4 100644 | ||
983 | --- a/src/include/catalog/pg_constraint.h | ||
984 | +++ b/src/include/catalog/pg_constraint.h | ||
985 | @@ -246,6 +246,7 @@ extern char *ChooseConstraintName(const char *name1, const char *name2, | ||
986 | |||
987 | extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, | ||
988 | Oid newNspId, bool isType, ObjectAddresses *objsMoved); | ||
989 | +extern void get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid); | ||
990 | extern Oid get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok); | ||
991 | extern Oid get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok); | ||
992 | |||
993 | diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h | ||
994 | index 9b6d57a..a00fd37 100644 | ||
995 | --- a/src/include/commands/defrem.h | ||
996 | +++ b/src/include/commands/defrem.h | ||
997 | @@ -20,7 +20,8 @@ | ||
998 | extern void RemoveObjects(DropStmt *stmt); | ||
999 | |||
1000 | /* commands/indexcmds.c */ | ||
1001 | -extern Oid DefineIndex(IndexStmt *stmt, | ||
1002 | +extern Oid DefineIndex(Oid relationId, | ||
1003 | + IndexStmt *stmt, | ||
1004 | Oid indexRelationId, | ||
1005 | bool is_alter_table, | ||
1006 | bool check_rights, | ||
1007 | @@ -35,7 +36,6 @@ extern char *makeObjectName(const char *name1, const char *name2, | ||
1008 | extern char *ChooseRelationName(const char *name1, const char *name2, | ||
1009 | const char *label, Oid namespaceid); | ||
1010 | extern bool CheckIndexCompatible(Oid oldId, | ||
1011 | - RangeVar *heapRelation, | ||
1012 | char *accessMethodName, | ||
1013 | List *attributeList, | ||
1014 | List *exclusionOpNames); | ||
1015 | diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h | ||
1016 | index 4f32062..d41f8a1 100644 | ||
1017 | --- a/src/include/commands/tablecmds.h | ||
1018 | +++ b/src/include/commands/tablecmds.h | ||
1019 | @@ -78,4 +78,6 @@ extern void AtEOSubXact_on_commit_actions(bool isCommit, | ||
1020 | extern void RangeVarCallbackOwnsTable(const RangeVar *relation, | ||
1021 | Oid relId, Oid oldRelId, void *arg); | ||
1022 | |||
1023 | +extern void RangeVarCallbackOwnsRelation(const RangeVar *relation, | ||
1024 | + Oid relId, Oid oldRelId, void *noCatalogs); | ||
1025 | #endif /* TABLECMDS_H */ | ||
1026 | diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h | ||
1027 | index 9303341..0869c0b 100644 | ||
1028 | --- a/src/include/commands/trigger.h | ||
1029 | +++ b/src/include/commands/trigger.h | ||
1030 | @@ -109,7 +109,7 @@ extern PGDLLIMPORT int SessionReplicationRole; | ||
1031 | #define TRIGGER_DISABLED 'D' | ||
1032 | |||
1033 | extern Oid CreateTrigger(CreateTrigStmt *stmt, const char *queryString, | ||
1034 | - Oid constraintOid, Oid indexOid, | ||
1035 | + Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid, | ||
1036 | bool isInternal); | ||
1037 | |||
1038 | extern void RemoveTriggerById(Oid trigOid); | ||
1039 | diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h | ||
1040 | index 327f7cf..31f5479 100644 | ||
1041 | --- a/src/include/nodes/parsenodes.h | ||
1042 | +++ b/src/include/nodes/parsenodes.h | ||
1043 | @@ -1566,6 +1566,8 @@ typedef struct Constraint | ||
1044 | /* Fields used for constraints that allow a NOT VALID specification */ | ||
1045 | bool skip_validation; /* skip validation of existing rows? */ | ||
1046 | bool initially_valid; /* mark the new constraint as valid? */ | ||
1047 | + | ||
1048 | + Oid old_pktable_oid; /* pg_constraint.confrelid of my former self */ | ||
1049 | } Constraint; | ||
1050 | |||
1051 | /* ---------------------- | ||
1052 | diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h | ||
1053 | index 4ad793a..d8b340e 100644 | ||
1054 | --- a/src/include/parser/parse_utilcmd.h | ||
1055 | +++ b/src/include/parser/parse_utilcmd.h | ||
1056 | @@ -18,9 +18,10 @@ | ||
1057 | |||
1058 | |||
1059 | extern List *transformCreateStmt(CreateStmt *stmt, const char *queryString); | ||
1060 | -extern List *transformAlterTableStmt(AlterTableStmt *stmt, | ||
1061 | +extern List *transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, | ||
1062 | const char *queryString); | ||
1063 | -extern IndexStmt *transformIndexStmt(IndexStmt *stmt, const char *queryString); | ||
1064 | +extern IndexStmt *transformIndexStmt(Oid relid, IndexStmt *stmt, | ||
1065 | + const char *queryString); | ||
1066 | extern void transformRuleStmt(RuleStmt *stmt, const char *queryString, | ||
1067 | List **actions, Node **whereClause); | ||
1068 | extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt); | ||
1069 | diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h | ||
1070 | index 54190b2..ae871ca 100644 | ||
1071 | --- a/src/include/tcop/utility.h | ||
1072 | +++ b/src/include/tcop/utility.h | ||
1073 | @@ -42,6 +42,4 @@ extern LogStmtLevel GetCommandLogLevel(Node *parsetree); | ||
1074 | |||
1075 | extern bool CommandIsReadOnly(Node *parsetree); | ||
1076 | |||
1077 | -extern void CheckRelationOwnership(RangeVar *rel, bool noCatalogs); | ||
1078 | - | ||
1079 | #endif /* UTILITY_H */ | ||
1080 | -- | ||
1081 | 1.7.5.4 | ||
1082 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch b/meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch new file mode 100644 index 000000000..fac0a7347 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0006-Fix-handling-of-wide-datetime-input-output.patch | |||
@@ -0,0 +1,465 @@ | |||
1 | From f416622be81d1320417bbc7892fd562cae0dba72 Mon Sep 17 00:00:00 2001 | ||
2 | From: Noah Misch <noah@leadboat.com> | ||
3 | Date: Mon, 17 Feb 2014 09:33:31 -0500 | ||
4 | Subject: [PATCH] Fix handling of wide datetime input/output. | ||
5 | MIME-Version: 1.0 | ||
6 | Content-Type: text/plain; charset=UTF-8 | ||
7 | Content-Transfer-Encoding: 8bit | ||
8 | |||
9 | commit f416622be81d1320417bbc7892fd562cae0dba72 REL9_2_STABLE | ||
10 | |||
11 | Many server functions use the MAXDATELEN constant to size a buffer for | ||
12 | parsing or displaying a datetime value. It was much too small for the | ||
13 | longest possible interval output and slightly too small for certain | ||
14 | valid timestamp input, particularly input with a long timezone name. | ||
15 | The long input was rejected needlessly; the long output caused | ||
16 | interval_out() to overrun its buffer. ECPG's pgtypes library has a copy | ||
17 | of the vulnerable functions, which bore the same vulnerabilities along | ||
18 | with some of its own. In contrast to the server, certain long inputs | ||
19 | caused stack overflow rather than failing cleanly. Back-patch to 8.4 | ||
20 | (all supported versions). | ||
21 | |||
22 | Reported by Daniel Schüssler, reviewed by Tom Lane. | ||
23 | |||
24 | Security: CVE-2014-0063 | ||
25 | |||
26 | |||
27 | Upstream-Status: Backport | ||
28 | |||
29 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
30 | --- | ||
31 | src/include/utils/datetime.h | 17 +++++--- | ||
32 | src/interfaces/ecpg/pgtypeslib/datetime.c | 4 +- | ||
33 | src/interfaces/ecpg/pgtypeslib/dt.h | 17 +++++--- | ||
34 | src/interfaces/ecpg/pgtypeslib/dt_common.c | 44 ++++++++++++++------ | ||
35 | src/interfaces/ecpg/pgtypeslib/interval.c | 2 +- | ||
36 | src/interfaces/ecpg/pgtypeslib/timestamp.c | 2 +- | ||
37 | .../ecpg/test/expected/pgtypeslib-dt_test2.c | 22 +++++++--- | ||
38 | .../ecpg/test/expected/pgtypeslib-dt_test2.stdout | 19 ++++++++ | ||
39 | src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc | 10 ++++ | ||
40 | src/test/regress/expected/interval.out | 7 +++ | ||
41 | src/test/regress/sql/interval.sql | 2 + | ||
42 | 11 files changed, 111 insertions(+), 35 deletions(-) | ||
43 | |||
44 | diff --git a/src/include/utils/datetime.h b/src/include/utils/datetime.h | ||
45 | index d73cc8d..4b805b6 100644 | ||
46 | --- a/src/include/utils/datetime.h | ||
47 | +++ b/src/include/utils/datetime.h | ||
48 | @@ -188,12 +188,17 @@ struct tzEntry; | ||
49 | #define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) | ||
50 | #define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_ALL_SECS_M) | ||
51 | |||
52 | -#define MAXDATELEN 63 /* maximum possible length of an input date | ||
53 | - * string (not counting tr. null) */ | ||
54 | -#define MAXDATEFIELDS 25 /* maximum possible number of fields in a date | ||
55 | - * string */ | ||
56 | -#define TOKMAXLEN 10 /* only this many chars are stored in | ||
57 | - * datetktbl */ | ||
58 | +/* | ||
59 | + * Working buffer size for input and output of interval, timestamp, etc. | ||
60 | + * Inputs that need more working space will be rejected early. Longer outputs | ||
61 | + * will overrun buffers, so this must suffice for all possible output. As of | ||
62 | + * this writing, interval_out() needs the most space at ~90 bytes. | ||
63 | + */ | ||
64 | +#define MAXDATELEN 128 | ||
65 | +/* maximum possible number of fields in a date string */ | ||
66 | +#define MAXDATEFIELDS 25 | ||
67 | +/* only this many chars are stored in datetktbl */ | ||
68 | +#define TOKMAXLEN 10 | ||
69 | |||
70 | /* keep this struct small; it gets used a lot */ | ||
71 | typedef struct | ||
72 | diff --git a/src/interfaces/ecpg/pgtypeslib/datetime.c b/src/interfaces/ecpg/pgtypeslib/datetime.c | ||
73 | index 823626f..4adcd1e 100644 | ||
74 | --- a/src/interfaces/ecpg/pgtypeslib/datetime.c | ||
75 | +++ b/src/interfaces/ecpg/pgtypeslib/datetime.c | ||
76 | @@ -61,14 +61,14 @@ PGTYPESdate_from_asc(char *str, char **endptr) | ||
77 | int nf; | ||
78 | char *field[MAXDATEFIELDS]; | ||
79 | int ftype[MAXDATEFIELDS]; | ||
80 | - char lowstr[MAXDATELEN + 1]; | ||
81 | + char lowstr[MAXDATELEN + MAXDATEFIELDS]; | ||
82 | char *realptr; | ||
83 | char **ptr = (endptr != NULL) ? endptr : &realptr; | ||
84 | |||
85 | bool EuroDates = FALSE; | ||
86 | |||
87 | errno = 0; | ||
88 | - if (strlen(str) >= sizeof(lowstr)) | ||
89 | + if (strlen(str) > MAXDATELEN) | ||
90 | { | ||
91 | errno = PGTYPES_DATE_BAD_DATE; | ||
92 | return INT_MIN; | ||
93 | diff --git a/src/interfaces/ecpg/pgtypeslib/dt.h b/src/interfaces/ecpg/pgtypeslib/dt.h | ||
94 | index dfe6f9e..2780593 100644 | ||
95 | --- a/src/interfaces/ecpg/pgtypeslib/dt.h | ||
96 | +++ b/src/interfaces/ecpg/pgtypeslib/dt.h | ||
97 | @@ -192,12 +192,17 @@ typedef double fsec_t; | ||
98 | #define DTK_DATE_M (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)) | ||
99 | #define DTK_TIME_M (DTK_M(HOUR) | DTK_M(MINUTE) | DTK_M(SECOND)) | ||
100 | |||
101 | -#define MAXDATELEN 63 /* maximum possible length of an input date | ||
102 | - * string (not counting tr. null) */ | ||
103 | -#define MAXDATEFIELDS 25 /* maximum possible number of fields in a date | ||
104 | - * string */ | ||
105 | -#define TOKMAXLEN 10 /* only this many chars are stored in | ||
106 | - * datetktbl */ | ||
107 | +/* | ||
108 | + * Working buffer size for input and output of interval, timestamp, etc. | ||
109 | + * Inputs that need more working space will be rejected early. Longer outputs | ||
110 | + * will overrun buffers, so this must suffice for all possible output. As of | ||
111 | + * this writing, PGTYPESinterval_to_asc() needs the most space at ~90 bytes. | ||
112 | + */ | ||
113 | +#define MAXDATELEN 128 | ||
114 | +/* maximum possible number of fields in a date string */ | ||
115 | +#define MAXDATEFIELDS 25 | ||
116 | +/* only this many chars are stored in datetktbl */ | ||
117 | +#define TOKMAXLEN 10 | ||
118 | |||
119 | /* keep this struct small; it gets used a lot */ | ||
120 | typedef struct | ||
121 | diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c | ||
122 | index 6b89e4a..18178dd 100644 | ||
123 | --- a/src/interfaces/ecpg/pgtypeslib/dt_common.c | ||
124 | +++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c | ||
125 | @@ -1171,15 +1171,22 @@ DecodeNumberField(int len, char *str, int fmask, | ||
126 | if ((cp = strchr(str, '.')) != NULL) | ||
127 | { | ||
128 | #ifdef HAVE_INT64_TIMESTAMP | ||
129 | - char fstr[MAXDATELEN + 1]; | ||
130 | + char fstr[7]; | ||
131 | + int i; | ||
132 | + | ||
133 | + cp++; | ||
134 | |||
135 | /* | ||
136 | * OK, we have at most six digits to care about. Let's construct a | ||
137 | - * string and then do the conversion to an integer. | ||
138 | + * string with those digits, zero-padded on the right, and then do | ||
139 | + * the conversion to an integer. | ||
140 | + * | ||
141 | + * XXX This truncates the seventh digit, unlike rounding it as do | ||
142 | + * the backend and the !HAVE_INT64_TIMESTAMP case. | ||
143 | */ | ||
144 | - strcpy(fstr, (cp + 1)); | ||
145 | - strcpy(fstr + strlen(fstr), "000000"); | ||
146 | - *(fstr + 6) = '\0'; | ||
147 | + for (i = 0; i < 6; i++) | ||
148 | + fstr[i] = *cp != '\0' ? *cp++ : '0'; | ||
149 | + fstr[i] = '\0'; | ||
150 | *fsec = strtol(fstr, NULL, 10); | ||
151 | #else | ||
152 | *fsec = strtod(cp, NULL); | ||
153 | @@ -1531,15 +1538,22 @@ DecodeTime(char *str, int *tmask, struct tm * tm, fsec_t *fsec) | ||
154 | else if (*cp == '.') | ||
155 | { | ||
156 | #ifdef HAVE_INT64_TIMESTAMP | ||
157 | - char fstr[MAXDATELEN + 1]; | ||
158 | + char fstr[7]; | ||
159 | + int i; | ||
160 | + | ||
161 | + cp++; | ||
162 | |||
163 | /* | ||
164 | - * OK, we have at most six digits to work with. Let's construct a | ||
165 | - * string and then do the conversion to an integer. | ||
166 | + * OK, we have at most six digits to care about. Let's construct a | ||
167 | + * string with those digits, zero-padded on the right, and then do | ||
168 | + * the conversion to an integer. | ||
169 | + * | ||
170 | + * XXX This truncates the seventh digit, unlike rounding it as do | ||
171 | + * the backend and the !HAVE_INT64_TIMESTAMP case. | ||
172 | */ | ||
173 | - strncpy(fstr, (cp + 1), 7); | ||
174 | - strcpy(fstr + strlen(fstr), "000000"); | ||
175 | - *(fstr + 6) = '\0'; | ||
176 | + for (i = 0; i < 6; i++) | ||
177 | + fstr[i] = *cp != '\0' ? *cp++ : '0'; | ||
178 | + fstr[i] = '\0'; | ||
179 | *fsec = strtol(fstr, &cp, 10); | ||
180 | #else | ||
181 | str = cp; | ||
182 | @@ -1665,6 +1679,9 @@ DecodePosixTimezone(char *str, int *tzp) | ||
183 | * DTK_NUMBER can hold date fields (yy.ddd) | ||
184 | * DTK_STRING can hold months (January) and time zones (PST) | ||
185 | * DTK_DATE can hold Posix time zones (GMT-8) | ||
186 | + * | ||
187 | + * The "lowstr" work buffer must have at least strlen(timestr) + MAXDATEFIELDS | ||
188 | + * bytes of space. On output, field[] entries will point into it. | ||
189 | */ | ||
190 | int | ||
191 | ParseDateTime(char *timestr, char *lowstr, | ||
192 | @@ -1677,7 +1694,10 @@ ParseDateTime(char *timestr, char *lowstr, | ||
193 | /* outer loop through fields */ | ||
194 | while (*(*endstr) != '\0') | ||
195 | { | ||
196 | + /* Record start of current field */ | ||
197 | field[nf] = lp; | ||
198 | + if (nf >= MAXDATEFIELDS) | ||
199 | + return -1; | ||
200 | |||
201 | /* leading digit? then date or time */ | ||
202 | if (isdigit((unsigned char) *(*endstr))) | ||
203 | @@ -1818,8 +1838,6 @@ ParseDateTime(char *timestr, char *lowstr, | ||
204 | /* force in a delimiter after each field */ | ||
205 | *lp++ = '\0'; | ||
206 | nf++; | ||
207 | - if (nf > MAXDATEFIELDS) | ||
208 | - return -1; | ||
209 | } | ||
210 | |||
211 | *numfields = nf; | ||
212 | diff --git a/src/interfaces/ecpg/pgtypeslib/interval.c b/src/interfaces/ecpg/pgtypeslib/interval.c | ||
213 | index bcc10ee..fdd8f49 100644 | ||
214 | --- a/src/interfaces/ecpg/pgtypeslib/interval.c | ||
215 | +++ b/src/interfaces/ecpg/pgtypeslib/interval.c | ||
216 | @@ -1092,7 +1092,7 @@ PGTYPESinterval_from_asc(char *str, char **endptr) | ||
217 | tm->tm_sec = 0; | ||
218 | fsec = 0; | ||
219 | |||
220 | - if (strlen(str) >= sizeof(lowstr)) | ||
221 | + if (strlen(str) > MAXDATELEN) | ||
222 | { | ||
223 | errno = PGTYPES_INTVL_BAD_INTERVAL; | ||
224 | return NULL; | ||
225 | diff --git a/src/interfaces/ecpg/pgtypeslib/timestamp.c b/src/interfaces/ecpg/pgtypeslib/timestamp.c | ||
226 | index 7d3f7c8..4f91e63 100644 | ||
227 | --- a/src/interfaces/ecpg/pgtypeslib/timestamp.c | ||
228 | +++ b/src/interfaces/ecpg/pgtypeslib/timestamp.c | ||
229 | @@ -297,7 +297,7 @@ PGTYPEStimestamp_from_asc(char *str, char **endptr) | ||
230 | char *realptr; | ||
231 | char **ptr = (endptr != NULL) ? endptr : &realptr; | ||
232 | |||
233 | - if (strlen(str) >= sizeof(lowstr)) | ||
234 | + if (strlen(str) > MAXDATELEN) | ||
235 | { | ||
236 | errno = PGTYPES_TS_BAD_TIMESTAMP; | ||
237 | return (noresult); | ||
238 | diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c | ||
239 | index d3ebb0e..0ba1936 100644 | ||
240 | --- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c | ||
241 | +++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.c | ||
242 | @@ -45,6 +45,15 @@ char *dates[] = { "19990108foobar", | ||
243 | "1999.008", | ||
244 | "J2451187", | ||
245 | "January 8, 99 BC", | ||
246 | + /* | ||
247 | + * Maximize space usage in ParseDateTime() with 25 | ||
248 | + * (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length. | ||
249 | + */ | ||
250 | + "........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | ||
251 | + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | ||
252 | + /* 26 fields */ | ||
253 | + ".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | ||
254 | + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | ||
255 | NULL }; | ||
256 | |||
257 | /* do not conflict with libc "times" symbol */ | ||
258 | @@ -52,6 +61,7 @@ static char *times[] = { "0:04", | ||
259 | "1:59 PDT", | ||
260 | "13:24:40 -8:00", | ||
261 | "13:24:40.495+3", | ||
262 | + "13:24:40.123456789+3", | ||
263 | NULL }; | ||
264 | |||
265 | char *intervals[] = { "1 minute", | ||
266 | @@ -73,22 +83,22 @@ main(void) | ||
267 | |||
268 | |||
269 | |||
270 | -#line 52 "dt_test2.pgc" | ||
271 | +#line 62 "dt_test2.pgc" | ||
272 | date date1 ; | ||
273 | |||
274 | -#line 53 "dt_test2.pgc" | ||
275 | +#line 63 "dt_test2.pgc" | ||
276 | timestamp ts1 , ts2 ; | ||
277 | |||
278 | -#line 54 "dt_test2.pgc" | ||
279 | +#line 64 "dt_test2.pgc" | ||
280 | char * text ; | ||
281 | |||
282 | -#line 55 "dt_test2.pgc" | ||
283 | +#line 65 "dt_test2.pgc" | ||
284 | interval * i1 ; | ||
285 | |||
286 | -#line 56 "dt_test2.pgc" | ||
287 | +#line 66 "dt_test2.pgc" | ||
288 | date * dc ; | ||
289 | /* exec sql end declare section */ | ||
290 | -#line 57 "dt_test2.pgc" | ||
291 | +#line 67 "dt_test2.pgc" | ||
292 | |||
293 | |||
294 | int i, j; | ||
295 | diff --git a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout | ||
296 | index 24e9d26..9a4587b 100644 | ||
297 | --- a/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout | ||
298 | +++ b/src/interfaces/ecpg/test/expected/pgtypeslib-dt_test2.stdout | ||
299 | @@ -8,85 +8,104 @@ TS[3,0]: 1999-01-08 00:04:00 | ||
300 | TS[3,1]: 1999-01-08 01:59:00 | ||
301 | TS[3,2]: 1999-01-08 13:24:40 | ||
302 | TS[3,3]: 1999-01-08 13:24:40.495 | ||
303 | +TS[3,4]: 1999-01-08 13:24:40.123456 | ||
304 | Date[4]: 1999-01-08 (N - F) | ||
305 | TS[4,0]: 1999-01-08 00:04:00 | ||
306 | TS[4,1]: 1999-01-08 01:59:00 | ||
307 | TS[4,2]: 1999-01-08 13:24:40 | ||
308 | TS[4,3]: 1999-01-08 13:24:40.495 | ||
309 | +TS[4,4]: 1999-01-08 13:24:40.123456 | ||
310 | Date[5]: 1999-01-08 (N - F) | ||
311 | TS[5,0]: 1999-01-08 00:04:00 | ||
312 | TS[5,1]: 1999-01-08 01:59:00 | ||
313 | TS[5,2]: 1999-01-08 13:24:40 | ||
314 | TS[5,3]: 1999-01-08 13:24:40.495 | ||
315 | +TS[5,4]: 1999-01-08 13:24:40.123456 | ||
316 | Date[6]: 1999-01-18 (N - F) | ||
317 | TS[6,0]: 1999-01-18 00:04:00 | ||
318 | TS[6,1]: 1999-01-18 01:59:00 | ||
319 | TS[6,2]: 1999-01-18 13:24:40 | ||
320 | TS[6,3]: 1999-01-18 13:24:40.495 | ||
321 | +TS[6,4]: 1999-01-18 13:24:40.123456 | ||
322 | Date[7]: 2003-01-02 (N - F) | ||
323 | TS[7,0]: 2003-01-02 00:04:00 | ||
324 | TS[7,1]: 2003-01-02 01:59:00 | ||
325 | TS[7,2]: 2003-01-02 13:24:40 | ||
326 | TS[7,3]: 2003-01-02 13:24:40.495 | ||
327 | +TS[7,4]: 2003-01-02 13:24:40.123456 | ||
328 | Date[8]: 1999-01-08 (N - F) | ||
329 | TS[8,0]: 1999-01-08 00:04:00 | ||
330 | TS[8,1]: 1999-01-08 01:59:00 | ||
331 | TS[8,2]: 1999-01-08 13:24:40 | ||
332 | TS[8,3]: 1999-01-08 13:24:40.495 | ||
333 | +TS[8,4]: 1999-01-08 13:24:40.123456 | ||
334 | Date[9]: 1999-01-08 (N - F) | ||
335 | TS[9,0]: 1999-01-08 00:04:00 | ||
336 | TS[9,1]: 1999-01-08 01:59:00 | ||
337 | TS[9,2]: 1999-01-08 13:24:40 | ||
338 | TS[9,3]: 1999-01-08 13:24:40.495 | ||
339 | +TS[9,4]: 1999-01-08 13:24:40.123456 | ||
340 | Date[10]: 1999-01-08 (N - F) | ||
341 | TS[10,0]: 1999-01-08 00:04:00 | ||
342 | TS[10,1]: 1999-01-08 01:59:00 | ||
343 | TS[10,2]: 1999-01-08 13:24:40 | ||
344 | TS[10,3]: 1999-01-08 13:24:40.495 | ||
345 | +TS[10,4]: 1999-01-08 13:24:40.123456 | ||
346 | Date[11]: 1999-01-08 (N - F) | ||
347 | TS[11,0]: 1999-01-08 00:04:00 | ||
348 | TS[11,1]: 1999-01-08 01:59:00 | ||
349 | TS[11,2]: 1999-01-08 13:24:40 | ||
350 | TS[11,3]: 1999-01-08 13:24:40.495 | ||
351 | +TS[11,4]: 1999-01-08 13:24:40.123456 | ||
352 | Date[12]: 1999-01-08 (N - F) | ||
353 | TS[12,0]: 1999-01-08 00:04:00 | ||
354 | TS[12,1]: 1999-01-08 01:59:00 | ||
355 | TS[12,2]: 1999-01-08 13:24:40 | ||
356 | TS[12,3]: 1999-01-08 13:24:40.495 | ||
357 | +TS[12,4]: 1999-01-08 13:24:40.123456 | ||
358 | Date[13]: 2006-01-08 (N - F) | ||
359 | TS[13,0]: 2006-01-08 00:04:00 | ||
360 | TS[13,1]: 2006-01-08 01:59:00 | ||
361 | TS[13,2]: 2006-01-08 13:24:40 | ||
362 | TS[13,3]: 2006-01-08 13:24:40.495 | ||
363 | +TS[13,4]: 2006-01-08 13:24:40.123456 | ||
364 | Date[14]: 1999-01-08 (N - F) | ||
365 | TS[14,0]: 1999-01-08 00:04:00 | ||
366 | TS[14,1]: 1999-01-08 01:59:00 | ||
367 | TS[14,2]: 1999-01-08 13:24:40 | ||
368 | TS[14,3]: 1999-01-08 13:24:40.495 | ||
369 | +TS[14,4]: 1999-01-08 13:24:40.123456 | ||
370 | Date[15]: 1999-01-08 (N - F) | ||
371 | TS[15,0]: 1999-01-08 00:04:00 | ||
372 | TS[15,1]: 1999-01-08 01:59:00 | ||
373 | TS[15,2]: 1999-01-08 13:24:40 | ||
374 | TS[15,3]: 1999-01-08 13:24:40.495 | ||
375 | +TS[15,4]: 1999-01-08 13:24:40.123456 | ||
376 | Date[16]: 1999-01-08 (N - F) | ||
377 | TS[16,0]: 1999-01-08 00:04:00 | ||
378 | TS[16,1]: 1999-01-08 01:59:00 | ||
379 | TS[16,2]: 1999-01-08 13:24:40 | ||
380 | TS[16,3]: 1999-01-08 13:24:40.495 | ||
381 | +TS[16,4]: 1999-01-08 13:24:40.123456 | ||
382 | Date[17]: 1999-01-08 (N - F) | ||
383 | TS[17,0]: 1999-01-08 00:04:00 | ||
384 | TS[17,1]: 1999-01-08 01:59:00 | ||
385 | TS[17,2]: 1999-01-08 13:24:40 | ||
386 | TS[17,3]: 1999-01-08 13:24:40.495 | ||
387 | +TS[17,4]: 1999-01-08 13:24:40.123456 | ||
388 | Date[18]: 1999-01-08 (N - F) | ||
389 | TS[18,0]: 1999-01-08 00:04:00 | ||
390 | TS[18,1]: 1999-01-08 01:59:00 | ||
391 | TS[18,2]: 1999-01-08 13:24:40 | ||
392 | TS[18,3]: 1999-01-08 13:24:40.495 | ||
393 | +TS[18,4]: 1999-01-08 13:24:40.123456 | ||
394 | Date[19]: 0099-01-08 BC (N - F) | ||
395 | TS[19,0]: 0099-01-08 00:04:00 BC | ||
396 | TS[19,1]: 0099-01-08 01:59:00 BC | ||
397 | TS[19,2]: 0099-01-08 13:24:40 BC | ||
398 | +TS[19,4]: 0099-01-08 13:24:40.123456 BC | ||
399 | +Date[20]: - (N - T) | ||
400 | +Date[21]: - (N - T) | ||
401 | interval[0]: @ 1 min | ||
402 | interval_copy[0]: @ 1 min | ||
403 | interval[1]: @ 1 day 12 hours 59 mins 10 secs | ||
404 | diff --git a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc | ||
405 | index 0edf012..a127dd9 100644 | ||
406 | --- a/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc | ||
407 | +++ b/src/interfaces/ecpg/test/pgtypeslib/dt_test2.pgc | ||
408 | @@ -27,6 +27,15 @@ char *dates[] = { "19990108foobar", | ||
409 | "1999.008", | ||
410 | "J2451187", | ||
411 | "January 8, 99 BC", | ||
412 | + /* | ||
413 | + * Maximize space usage in ParseDateTime() with 25 | ||
414 | + * (MAXDATEFIELDS) fields and 128 (MAXDATELEN) total length. | ||
415 | + */ | ||
416 | + "........................Xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | ||
417 | + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | ||
418 | + /* 26 fields */ | ||
419 | + ".........................aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | ||
420 | + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", | ||
421 | NULL }; | ||
422 | |||
423 | /* do not conflict with libc "times" symbol */ | ||
424 | @@ -34,6 +43,7 @@ static char *times[] = { "0:04", | ||
425 | "1:59 PDT", | ||
426 | "13:24:40 -8:00", | ||
427 | "13:24:40.495+3", | ||
428 | + "13:24:40.123456789+3", | ||
429 | NULL }; | ||
430 | |||
431 | char *intervals[] = { "1 minute", | ||
432 | diff --git a/src/test/regress/expected/interval.out b/src/test/regress/expected/interval.out | ||
433 | index 3bf2211..99fd0ca 100644 | ||
434 | --- a/src/test/regress/expected/interval.out | ||
435 | +++ b/src/test/regress/expected/interval.out | ||
436 | @@ -306,6 +306,13 @@ select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31 | ||
437 | @ 4541 years 4 mons 4 days 17 mins 31 secs | ||
438 | (1 row) | ||
439 | |||
440 | +-- test long interval output | ||
441 | +select '100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval; | ||
442 | + interval | ||
443 | +------------------------------------------------------------------------------------------- | ||
444 | + @ 100000000 years 10 mons -1000000000 days -1000000000 hours -10 mins -10.000001 secs ago | ||
445 | +(1 row) | ||
446 | + | ||
447 | -- test justify_hours() and justify_days() | ||
448 | 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"; | ||
449 | 6 mons 5 days 4 hours 3 mins 2 seconds | ||
450 | diff --git a/src/test/regress/sql/interval.sql b/src/test/regress/sql/interval.sql | ||
451 | index f1da4c2..7cee286 100644 | ||
452 | --- a/src/test/regress/sql/interval.sql | ||
453 | +++ b/src/test/regress/sql/interval.sql | ||
454 | @@ -108,6 +108,8 @@ select avg(f1) from interval_tbl; | ||
455 | -- test long interval input | ||
456 | select '4 millenniums 5 centuries 4 decades 1 year 4 months 4 days 17 minutes 31 seconds'::interval; | ||
457 | |||
458 | +-- test long interval output | ||
459 | +select '100000000y 10mon -1000000000d -1000000000h -10min -10.000001s ago'::interval; | ||
460 | |||
461 | -- test justify_hours() and justify_days() | ||
462 | |||
463 | -- | ||
464 | 1.7.5.4 | ||
465 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/0007-Make-pqsignal-available-to-pg_regress-of-ECPG-and-is.patch b/meta-oe/recipes-support/postgresql/files/0007-Make-pqsignal-available-to-pg_regress-of-ECPG-and-is.patch new file mode 100644 index 000000000..3cffc0a85 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0007-Make-pqsignal-available-to-pg_regress-of-ECPG-and-is.patch | |||
@@ -0,0 +1,75 @@ | |||
1 | From 0ae841a98c21c53901d5bc9a9323a8cc800364f6 Mon Sep 17 00:00:00 2001 | ||
2 | From: Noah Misch <noah@leadboat.com> | ||
3 | Date: Sat, 14 Jun 2014 10:52:25 -0400 | ||
4 | Subject: [PATCH] Make pqsignal() available to pg_regress of ECPG and | ||
5 | isolation suites. | ||
6 | |||
7 | commit 0ae841a98c21c53901d5bc9a9323a8cc800364f6 REL9_2_STABLE | ||
8 | |||
9 | Commit 453a5d91d49e4d35054f92785d830df4067e10c1 made it available to the | ||
10 | src/test/regress build of pg_regress, but all pg_regress builds need the | ||
11 | same treatment. Patch 9.2 through 8.4; in 9.3 and later, pg_regress | ||
12 | gets pqsignal() via libpgport. | ||
13 | |||
14 | |||
15 | Upstream-Status: Backport | ||
16 | |||
17 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
18 | --- | ||
19 | src/interfaces/ecpg/test/Makefile | 4 ++-- | ||
20 | src/test/isolation/Makefile | 12 +++++++----- | ||
21 | 2 files changed, 9 insertions(+), 7 deletions(-) | ||
22 | |||
23 | diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile | ||
24 | index e9944c6..4bb9525 100644 | ||
25 | --- a/src/interfaces/ecpg/test/Makefile | ||
26 | +++ b/src/interfaces/ecpg/test/Makefile | ||
27 | @@ -47,10 +47,10 @@ clean distclean maintainer-clean: | ||
28 | |||
29 | all: pg_regress$(X) | ||
30 | |||
31 | -pg_regress$(X): pg_regress_ecpg.o $(top_builddir)/src/test/regress/pg_regress.o | ||
32 | +pg_regress$(X): pg_regress_ecpg.o $(top_builddir)/src/test/regress/pg_regress.o $(top_builddir)/src/test/regress/pqsignal.o | ||
33 | $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_EX) $^ $(LIBS) -o $@ | ||
34 | |||
35 | -$(top_builddir)/src/test/regress/pg_regress.o: | ||
36 | +$(top_builddir)/src/test/regress/pg_regress.o $(top_builddir)/src/test/regress/pqsignal.o: | ||
37 | $(MAKE) -C $(dir $@) $(notdir $@) | ||
38 | |||
39 | # dependencies ensure that path changes propagate | ||
40 | diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile | ||
41 | index 46ea6f0..e20ba48 100644 | ||
42 | --- a/src/test/isolation/Makefile | ||
43 | +++ b/src/test/isolation/Makefile | ||
44 | @@ -15,13 +15,15 @@ OBJS = specparse.o isolationtester.o | ||
45 | |||
46 | all: isolationtester$(X) pg_isolation_regress$(X) | ||
47 | |||
48 | -submake-regress: | ||
49 | +pg_regress.o: | ||
50 | $(MAKE) -C $(top_builddir)/src/test/regress pg_regress.o | ||
51 | - | ||
52 | -pg_regress.o: | submake-regress | ||
53 | rm -f $@ && $(LN_S) $(top_builddir)/src/test/regress/pg_regress.o . | ||
54 | |||
55 | -pg_isolation_regress$(X): isolation_main.o pg_regress.o | ||
56 | +pqsignal.o: | ||
57 | + $(MAKE) -C $(top_builddir)/src/test/regress pqsignal.o | ||
58 | + rm -f $@ && $(LN_S) $(top_builddir)/src/test/regress/pqsignal.o . | ||
59 | + | ||
60 | +pg_isolation_regress$(X): isolation_main.o pg_regress.o pqsignal.o | ||
61 | $(CC) $(CFLAGS) $^ $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@ | ||
62 | |||
63 | isolationtester$(X): $(OBJS) | submake-libpq submake-libpgport | ||
64 | @@ -59,7 +61,7 @@ endif | ||
65 | # so do not clean them here | ||
66 | clean distclean: | ||
67 | rm -f isolationtester$(X) pg_isolation_regress$(X) $(OBJS) isolation_main.o | ||
68 | - rm -f pg_regress.o | ||
69 | + rm -f pg_regress.o pqsignal.o | ||
70 | rm -rf $(pg_regress_clean_files) | ||
71 | |||
72 | maintainer-clean: distclean | ||
73 | -- | ||
74 | 1.7.5.4 | ||
75 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/0008-Prevent-potential-overruns-of-fixed-size-buffers.patch b/meta-oe/recipes-support/postgresql/files/0008-Prevent-potential-overruns-of-fixed-size-buffers.patch new file mode 100644 index 000000000..62ec9354d --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/0008-Prevent-potential-overruns-of-fixed-size-buffers.patch | |||
@@ -0,0 +1,393 @@ | |||
1 | From 655b665f745e2e07cf6936c6063b0250f5caa98f Mon Sep 17 00:00:00 2001 | ||
2 | From: Tom Lane <tgl@sss.pgh.pa.us> | ||
3 | Date: Mon, 17 Feb 2014 11:20:27 -0500 | ||
4 | Subject: [PATCH] Prevent potential overruns of fixed-size buffers. | ||
5 | |||
6 | commit 655b665f745e2e07cf6936c6063b0250f5caa98f REL9_2_STABLE | ||
7 | |||
8 | Coverity identified a number of places in which it couldn't prove that a | ||
9 | string being copied into a fixed-size buffer would fit. We believe that | ||
10 | most, perhaps all of these are in fact safe, or are copying data that is | ||
11 | coming from a trusted source so that any overrun is not really a security | ||
12 | issue. Nonetheless it seems prudent to forestall any risk by using | ||
13 | strlcpy() and similar functions. | ||
14 | |||
15 | Fixes by Peter Eisentraut and Jozef Mlich based on Coverity reports. | ||
16 | |||
17 | In addition, fix a potential null-pointer-dereference crash in | ||
18 | contrib/chkpass. The crypt(3) function is defined to return NULL on | ||
19 | failure, but chkpass.c didn't check for that before using the result. | ||
20 | The main practical case in which this could be an issue is if libc is | ||
21 | configured to refuse to execute unapproved hashing algorithms (e.g., | ||
22 | "FIPS mode"). This ideally should've been a separate commit, but | ||
23 | since it touches code adjacent to one of the buffer overrun changes, | ||
24 | I included it in this commit to avoid last-minute merge issues. | ||
25 | This issue was reported by Honza Horak. | ||
26 | |||
27 | Security: CVE-2014-0065 for buffer overruns, CVE-2014-0066 for crypt() | ||
28 | |||
29 | Upsteam-Status: Backport | ||
30 | |||
31 | Signed-off-by: Kai Kang <kai.kang@windriver.com> | ||
32 | --- | ||
33 | contrib/chkpass/chkpass.c | 29 ++++++++++++++++++++++++++--- | ||
34 | contrib/pg_standby/pg_standby.c | 2 +- | ||
35 | src/backend/access/transam/xlog.c | 10 +++++----- | ||
36 | src/backend/tsearch/spell.c | 2 +- | ||
37 | src/backend/utils/adt/datetime.c | 11 ++++++----- | ||
38 | src/bin/initdb/findtimezone.c | 4 ++-- | ||
39 | src/bin/pg_basebackup/pg_basebackup.c | 8 ++++---- | ||
40 | src/interfaces/ecpg/preproc/pgc.l | 2 +- | ||
41 | src/interfaces/libpq/fe-protocol2.c | 2 +- | ||
42 | src/interfaces/libpq/fe-protocol3.c | 2 +- | ||
43 | src/port/exec.c | 4 ++-- | ||
44 | src/test/regress/pg_regress.c | 6 +++--- | ||
45 | src/timezone/pgtz.c | 2 +- | ||
46 | 13 files changed, 54 insertions(+), 30 deletions(-) | ||
47 | |||
48 | diff --git a/contrib/chkpass/chkpass.c b/contrib/chkpass/chkpass.c | ||
49 | index 0c9fec0..1795b8c 100644 | ||
50 | --- a/contrib/chkpass/chkpass.c | ||
51 | +++ b/contrib/chkpass/chkpass.c | ||
52 | @@ -70,6 +70,7 @@ chkpass_in(PG_FUNCTION_ARGS) | ||
53 | char *str = PG_GETARG_CSTRING(0); | ||
54 | chkpass *result; | ||
55 | char mysalt[4]; | ||
56 | + char *crypt_output; | ||
57 | static char salt_chars[] = | ||
58 | "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; | ||
59 | |||
60 | @@ -92,7 +93,15 @@ chkpass_in(PG_FUNCTION_ARGS) | ||
61 | mysalt[1] = salt_chars[random() & 0x3f]; | ||
62 | mysalt[2] = 0; /* technically the terminator is not necessary | ||
63 | * but I like to play safe */ | ||
64 | - strcpy(result->password, crypt(str, mysalt)); | ||
65 | + | ||
66 | + crypt_output = crypt(str, mysalt); | ||
67 | + if (crypt_output == NULL) | ||
68 | + ereport(ERROR, | ||
69 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||
70 | + errmsg("crypt() failed"))); | ||
71 | + | ||
72 | + strlcpy(result->password, crypt_output, sizeof(result->password)); | ||
73 | + | ||
74 | PG_RETURN_POINTER(result); | ||
75 | } | ||
76 | |||
77 | @@ -141,9 +150,16 @@ chkpass_eq(PG_FUNCTION_ARGS) | ||
78 | chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0); | ||
79 | text *a2 = PG_GETARG_TEXT_PP(1); | ||
80 | char str[9]; | ||
81 | + char *crypt_output; | ||
82 | |||
83 | text_to_cstring_buffer(a2, str, sizeof(str)); | ||
84 | - PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) == 0); | ||
85 | + crypt_output = crypt(str, a1->password); | ||
86 | + if (crypt_output == NULL) | ||
87 | + ereport(ERROR, | ||
88 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||
89 | + errmsg("crypt() failed"))); | ||
90 | + | ||
91 | + PG_RETURN_BOOL(strcmp(a1->password, crypt_output) == 0); | ||
92 | } | ||
93 | |||
94 | PG_FUNCTION_INFO_V1(chkpass_ne); | ||
95 | @@ -153,7 +169,14 @@ chkpass_ne(PG_FUNCTION_ARGS) | ||
96 | chkpass *a1 = (chkpass *) PG_GETARG_POINTER(0); | ||
97 | text *a2 = PG_GETARG_TEXT_PP(1); | ||
98 | char str[9]; | ||
99 | + char *crypt_output; | ||
100 | |||
101 | text_to_cstring_buffer(a2, str, sizeof(str)); | ||
102 | - PG_RETURN_BOOL(strcmp(a1->password, crypt(str, a1->password)) != 0); | ||
103 | + crypt_output = crypt(str, a1->password); | ||
104 | + if (crypt_output == NULL) | ||
105 | + ereport(ERROR, | ||
106 | + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), | ||
107 | + errmsg("crypt() failed"))); | ||
108 | + | ||
109 | + PG_RETURN_BOOL(strcmp(a1->password, crypt_output) != 0); | ||
110 | } | ||
111 | diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c | ||
112 | index 84941ed..0f1e0c1 100644 | ||
113 | --- a/contrib/pg_standby/pg_standby.c | ||
114 | +++ b/contrib/pg_standby/pg_standby.c | ||
115 | @@ -338,7 +338,7 @@ SetWALFileNameForCleanup(void) | ||
116 | if (strcmp(restartWALFileName, nextWALFileName) > 0) | ||
117 | return false; | ||
118 | |||
119 | - strcpy(exclusiveCleanupFileName, restartWALFileName); | ||
120 | + strlcpy(exclusiveCleanupFileName, restartWALFileName, sizeof(exclusiveCleanupFileName)); | ||
121 | return true; | ||
122 | } | ||
123 | |||
124 | diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c | ||
125 | index d639c4a..49bb453 100644 | ||
126 | --- a/src/backend/access/transam/xlog.c | ||
127 | +++ b/src/backend/access/transam/xlog.c | ||
128 | @@ -3017,7 +3017,7 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname) | ||
129 | xlogfpath, oldpath))); | ||
130 | } | ||
131 | #else | ||
132 | - strncpy(oldpath, xlogfpath, MAXPGPATH); | ||
133 | + strlcpy(oldpath, xlogfpath, MAXPGPATH); | ||
134 | #endif | ||
135 | if (unlink(oldpath) != 0) | ||
136 | ereport(FATAL, | ||
137 | @@ -5913,7 +5913,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis) | ||
138 | |||
139 | recordRestorePointData = (xl_restore_point *) XLogRecGetData(record); | ||
140 | recordXtime = recordRestorePointData->rp_time; | ||
141 | - strncpy(recordRPName, recordRestorePointData->rp_name, MAXFNAMELEN); | ||
142 | + strlcpy(recordRPName, recordRestorePointData->rp_name, MAXFNAMELEN); | ||
143 | } | ||
144 | else | ||
145 | return false; | ||
146 | @@ -6008,7 +6008,7 @@ recoveryStopsHere(XLogRecord *record, bool *includeThis) | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | - strncpy(recoveryStopName, recordRPName, MAXFNAMELEN); | ||
151 | + strlcpy(recoveryStopName, recordRPName, MAXFNAMELEN); | ||
152 | |||
153 | ereport(LOG, | ||
154 | (errmsg("recovery stopping at restore point \"%s\", time %s", | ||
155 | @@ -6348,7 +6348,7 @@ StartupXLOG(void) | ||
156 | * see them | ||
157 | */ | ||
158 | XLogCtl->RecoveryTargetTLI = recoveryTargetTLI; | ||
159 | - strncpy(XLogCtl->archiveCleanupCommand, | ||
160 | + strlcpy(XLogCtl->archiveCleanupCommand, | ||
161 | archiveCleanupCommand ? archiveCleanupCommand : "", | ||
162 | sizeof(XLogCtl->archiveCleanupCommand)); | ||
163 | |||
164 | @@ -8760,7 +8760,7 @@ XLogRestorePoint(const char *rpName) | ||
165 | xl_restore_point xlrec; | ||
166 | |||
167 | xlrec.rp_time = GetCurrentTimestamp(); | ||
168 | - strncpy(xlrec.rp_name, rpName, MAXFNAMELEN); | ||
169 | + strlcpy(xlrec.rp_name, rpName, MAXFNAMELEN); | ||
170 | |||
171 | rdata.buffer = InvalidBuffer; | ||
172 | rdata.data = (char *) &xlrec; | ||
173 | diff --git a/src/backend/tsearch/spell.c b/src/backend/tsearch/spell.c | ||
174 | index 449aa6a..4acc33e 100644 | ||
175 | --- a/src/backend/tsearch/spell.c | ||
176 | +++ b/src/backend/tsearch/spell.c | ||
177 | @@ -255,7 +255,7 @@ NIAddSpell(IspellDict *Conf, const char *word, const char *flag) | ||
178 | } | ||
179 | Conf->Spell[Conf->nspell] = (SPELL *) tmpalloc(SPELLHDRSZ + strlen(word) + 1); | ||
180 | strcpy(Conf->Spell[Conf->nspell]->word, word); | ||
181 | - strncpy(Conf->Spell[Conf->nspell]->p.flag, flag, MAXFLAGLEN); | ||
182 | + strlcpy(Conf->Spell[Conf->nspell]->p.flag, flag, MAXFLAGLEN); | ||
183 | Conf->nspell++; | ||
184 | } | ||
185 | |||
186 | diff --git a/src/backend/utils/adt/datetime.c b/src/backend/utils/adt/datetime.c | ||
187 | index 4763a6f..4105f17 100644 | ||
188 | --- a/src/backend/utils/adt/datetime.c | ||
189 | +++ b/src/backend/utils/adt/datetime.c | ||
190 | @@ -90,10 +90,10 @@ char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", | ||
191 | * Note that this table must be strictly alphabetically ordered to allow an | ||
192 | * O(ln(N)) search algorithm to be used. | ||
193 | * | ||
194 | - * The text field is NOT guaranteed to be NULL-terminated. | ||
195 | + * The token field is NOT guaranteed to be NULL-terminated. | ||
196 | * | ||
197 | - * To keep this table reasonably small, we divide the lexval for TZ and DTZ | ||
198 | - * entries by 15 (so they are on 15 minute boundaries) and truncate the text | ||
199 | + * To keep this table reasonably small, we divide the value for TZ and DTZ | ||
200 | + * entries by 15 (so they are on 15 minute boundaries) and truncate the token | ||
201 | * field at TOKMAXLEN characters. | ||
202 | * Formerly, we divided by 10 rather than 15 but there are a few time zones | ||
203 | * which are 30 or 45 minutes away from an even hour, most are on an hour | ||
204 | @@ -108,7 +108,7 @@ static datetkn *timezonetktbl = NULL; | ||
205 | static int sztimezonetktbl = 0; | ||
206 | |||
207 | static const datetkn datetktbl[] = { | ||
208 | -/* text, token, lexval */ | ||
209 | + /* token, type, value */ | ||
210 | {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */ | ||
211 | {DA_D, ADBC, AD}, /* "ad" for years > 0 */ | ||
212 | {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */ | ||
213 | @@ -188,7 +188,7 @@ static const datetkn datetktbl[] = { | ||
214 | static int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0]; | ||
215 | |||
216 | static datetkn deltatktbl[] = { | ||
217 | - /* text, token, lexval */ | ||
218 | + /* token, type, value */ | ||
219 | {"@", IGNORE_DTF, 0}, /* postgres relative prefix */ | ||
220 | {DAGO, AGO, 0}, /* "ago" indicates negative time offset */ | ||
221 | {"c", UNITS, DTK_CENTURY}, /* "century" relative */ | ||
222 | @@ -4201,6 +4201,7 @@ ConvertTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl, | ||
223 | tbl->numabbrevs = n; | ||
224 | for (i = 0; i < n; i++) | ||
225 | { | ||
226 | + /* do NOT use strlcpy here; token field need not be null-terminated */ | ||
227 | strncpy(newtbl[i].token, abbrevs[i].abbrev, TOKMAXLEN); | ||
228 | newtbl[i].type = abbrevs[i].is_dst ? DTZ : TZ; | ||
229 | TOVAL(&newtbl[i], abbrevs[i].offset / MINS_PER_HOUR); | ||
230 | diff --git a/src/bin/initdb/findtimezone.c b/src/bin/initdb/findtimezone.c | ||
231 | index 6d6f96a..6d38151 100644 | ||
232 | --- a/src/bin/initdb/findtimezone.c | ||
233 | +++ b/src/bin/initdb/findtimezone.c | ||
234 | @@ -68,7 +68,7 @@ pg_open_tzfile(const char *name, char *canonname) | ||
235 | if (canonname) | ||
236 | strlcpy(canonname, name, TZ_STRLEN_MAX + 1); | ||
237 | |||
238 | - strcpy(fullname, pg_TZDIR()); | ||
239 | + strlcpy(fullname, pg_TZDIR(), sizeof(fullname)); | ||
240 | if (strlen(fullname) + 1 + strlen(name) >= MAXPGPATH) | ||
241 | return -1; /* not gonna fit */ | ||
242 | strcat(fullname, "/"); | ||
243 | @@ -375,7 +375,7 @@ identify_system_timezone(void) | ||
244 | } | ||
245 | |||
246 | /* Search for the best-matching timezone file */ | ||
247 | - strcpy(tmptzdir, pg_TZDIR()); | ||
248 | + strlcpy(tmptzdir, pg_TZDIR(), sizeof(tmptzdir)); | ||
249 | bestscore = -1; | ||
250 | resultbuf[0] = '\0'; | ||
251 | scan_available_timezones(tmptzdir, tmptzdir + strlen(tmptzdir) + 1, | ||
252 | diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c | ||
253 | index 9d840a1..26cc758 100644 | ||
254 | --- a/src/bin/pg_basebackup/pg_basebackup.c | ||
255 | +++ b/src/bin/pg_basebackup/pg_basebackup.c | ||
256 | @@ -735,9 +735,9 @@ ReceiveAndUnpackTarFile(PGconn *conn, PGresult *res, int rownum) | ||
257 | FILE *file = NULL; | ||
258 | |||
259 | if (PQgetisnull(res, rownum, 0)) | ||
260 | - strcpy(current_path, basedir); | ||
261 | + strlcpy(current_path, basedir, sizeof(current_path)); | ||
262 | else | ||
263 | - strcpy(current_path, PQgetvalue(res, rownum, 1)); | ||
264 | + strlcpy(current_path, PQgetvalue(res, rownum, 1), sizeof(current_path)); | ||
265 | |||
266 | /* | ||
267 | * Get the COPY data | ||
268 | @@ -1053,7 +1053,7 @@ BaseBackup(void) | ||
269 | progname); | ||
270 | disconnect_and_exit(1); | ||
271 | } | ||
272 | - strcpy(xlogstart, PQgetvalue(res, 0, 0)); | ||
273 | + strlcpy(xlogstart, PQgetvalue(res, 0, 0), sizeof(xlogstart)); | ||
274 | if (verbose && includewal) | ||
275 | fprintf(stderr, "transaction log start point: %s\n", xlogstart); | ||
276 | PQclear(res); | ||
277 | @@ -1153,7 +1153,7 @@ BaseBackup(void) | ||
278 | progname); | ||
279 | disconnect_and_exit(1); | ||
280 | } | ||
281 | - strcpy(xlogend, PQgetvalue(res, 0, 0)); | ||
282 | + strlcpy(xlogend, PQgetvalue(res, 0, 0), sizeof(xlogend)); | ||
283 | if (verbose && includewal) | ||
284 | fprintf(stderr, "transaction log end point: %s\n", xlogend); | ||
285 | PQclear(res); | ||
286 | diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l | ||
287 | index f2e7edd..7ae8556 100644 | ||
288 | --- a/src/interfaces/ecpg/preproc/pgc.l | ||
289 | +++ b/src/interfaces/ecpg/preproc/pgc.l | ||
290 | @@ -1315,7 +1315,7 @@ parse_include(void) | ||
291 | yytext[i] = '\0'; | ||
292 | memmove(yytext, yytext+1, strlen(yytext)); | ||
293 | |||
294 | - strncpy(inc_file, yytext, sizeof(inc_file)); | ||
295 | + strlcpy(inc_file, yytext, sizeof(inc_file)); | ||
296 | yyin = fopen(inc_file, "r"); | ||
297 | if (!yyin) | ||
298 | { | ||
299 | diff --git a/src/interfaces/libpq/fe-protocol2.c b/src/interfaces/libpq/fe-protocol2.c | ||
300 | index 1ba5885..af4c412 100644 | ||
301 | --- a/src/interfaces/libpq/fe-protocol2.c | ||
302 | +++ b/src/interfaces/libpq/fe-protocol2.c | ||
303 | @@ -500,7 +500,7 @@ pqParseInput2(PGconn *conn) | ||
304 | if (!conn->result) | ||
305 | return; | ||
306 | } | ||
307 | - strncpy(conn->result->cmdStatus, conn->workBuffer.data, | ||
308 | + strlcpy(conn->result->cmdStatus, conn->workBuffer.data, | ||
309 | CMDSTATUS_LEN); | ||
310 | checkXactStatus(conn, conn->workBuffer.data); | ||
311 | conn->asyncStatus = PGASYNC_READY; | ||
312 | diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c | ||
313 | index d289f82..6f8a470 100644 | ||
314 | --- a/src/interfaces/libpq/fe-protocol3.c | ||
315 | +++ b/src/interfaces/libpq/fe-protocol3.c | ||
316 | @@ -206,7 +206,7 @@ pqParseInput3(PGconn *conn) | ||
317 | if (!conn->result) | ||
318 | return; | ||
319 | } | ||
320 | - strncpy(conn->result->cmdStatus, conn->workBuffer.data, | ||
321 | + strlcpy(conn->result->cmdStatus, conn->workBuffer.data, | ||
322 | CMDSTATUS_LEN); | ||
323 | conn->asyncStatus = PGASYNC_READY; | ||
324 | break; | ||
325 | diff --git a/src/port/exec.c b/src/port/exec.c | ||
326 | index c79e8ba..0726dbe 100644 | ||
327 | --- a/src/port/exec.c | ||
328 | +++ b/src/port/exec.c | ||
329 | @@ -66,7 +66,7 @@ validate_exec(const char *path) | ||
330 | if (strlen(path) >= strlen(".exe") && | ||
331 | pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0) | ||
332 | { | ||
333 | - strcpy(path_exe, path); | ||
334 | + strlcpy(path_exe, path, sizeof(path_exe) - 4); | ||
335 | strcat(path_exe, ".exe"); | ||
336 | path = path_exe; | ||
337 | } | ||
338 | @@ -275,7 +275,7 @@ resolve_symlinks(char *path) | ||
339 | } | ||
340 | |||
341 | /* must copy final component out of 'path' temporarily */ | ||
342 | - strcpy(link_buf, fname); | ||
343 | + strlcpy(link_buf, fname, sizeof(link_buf)); | ||
344 | |||
345 | if (!getcwd(path, MAXPGPATH)) | ||
346 | { | ||
347 | diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c | ||
348 | index d991a5c..a6466eb 100644 | ||
349 | --- a/src/test/regress/pg_regress.c | ||
350 | +++ b/src/test/regress/pg_regress.c | ||
351 | @@ -1233,7 +1233,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul | ||
352 | */ | ||
353 | platform_expectfile = get_expectfile(testname, resultsfile); | ||
354 | |||
355 | - strcpy(expectfile, default_expectfile); | ||
356 | + strlcpy(expectfile, default_expectfile, sizeof(expectfile)); | ||
357 | if (platform_expectfile) | ||
358 | { | ||
359 | /* | ||
360 | @@ -1288,7 +1288,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul | ||
361 | { | ||
362 | /* This diff was a better match than the last one */ | ||
363 | best_line_count = l; | ||
364 | - strcpy(best_expect_file, alt_expectfile); | ||
365 | + strlcpy(best_expect_file, alt_expectfile, sizeof(best_expect_file)); | ||
366 | } | ||
367 | free(alt_expectfile); | ||
368 | } | ||
369 | @@ -1316,7 +1316,7 @@ results_differ(const char *testname, const char *resultsfile, const char *defaul | ||
370 | { | ||
371 | /* This diff was a better match than the last one */ | ||
372 | best_line_count = l; | ||
373 | - strcpy(best_expect_file, default_expectfile); | ||
374 | + strlcpy(best_expect_file, default_expectfile, sizeof(best_expect_file)); | ||
375 | } | ||
376 | } | ||
377 | |||
378 | diff --git a/src/timezone/pgtz.c b/src/timezone/pgtz.c | ||
379 | index d5bc83e..80c5635 100644 | ||
380 | --- a/src/timezone/pgtz.c | ||
381 | +++ b/src/timezone/pgtz.c | ||
382 | @@ -83,7 +83,7 @@ pg_open_tzfile(const char *name, char *canonname) | ||
383 | * Loop to split the given name into directory levels; for each level, | ||
384 | * search using scan_directory_ci(). | ||
385 | */ | ||
386 | - strcpy(fullname, pg_TZDIR()); | ||
387 | + strlcpy(fullname, pg_TZDIR(), sizeof(fullname)); | ||
388 | orignamelen = fullnamelen = strlen(fullname); | ||
389 | fname = name; | ||
390 | for (;;) | ||
391 | -- | ||
392 | 1.7.5.4 | ||
393 | |||
diff --git a/meta-oe/recipes-support/postgresql/files/no-ecpg-test.patch b/meta-oe/recipes-support/postgresql/files/no-ecpg-test.patch new file mode 100644 index 000000000..c0f28f425 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/no-ecpg-test.patch | |||
@@ -0,0 +1,12 @@ | |||
1 | diff --git a/src/interfaces/ecpg/Makefile b/src/interfaces/ecpg/Makefile | ||
2 | index dcd578f..1428423 100644 | ||
3 | --- a/src/interfaces/ecpg/Makefile | ||
4 | +++ b/src/interfaces/ecpg/Makefile | ||
5 | @@ -8,7 +8,6 @@ all install installdirs uninstall dep depend distprep: | ||
6 | $(MAKE) -C ecpglib $@ | ||
7 | $(MAKE) -C compatlib $@ | ||
8 | $(MAKE) -C preproc $@ | ||
9 | - $(MAKE) -C test $@ | ||
10 | |||
11 | clean distclean maintainer-clean: | ||
12 | -$(MAKE) -C include $@ | ||
diff --git a/meta-oe/recipes-support/postgresql/files/postgresql-bashprofile b/meta-oe/recipes-support/postgresql/files/postgresql-bashprofile new file mode 100644 index 000000000..1c931f37f --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/postgresql-bashprofile | |||
@@ -0,0 +1,4 @@ | |||
1 | [ -f /etc/profile ] && source /etc/profile | ||
2 | |||
3 | PGDATA=/var/lib/postgresql/data | ||
4 | export PGDATA | ||
diff --git a/meta-oe/recipes-support/postgresql/files/postgresql-setup b/meta-oe/recipes-support/postgresql/files/postgresql-setup new file mode 100644 index 000000000..75bb01e05 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/postgresql-setup | |||
@@ -0,0 +1,73 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # postgresql-setup Initialization operation for PostgreSQL | ||
4 | |||
5 | # For SELinux we need to use 'runuser' not 'su' | ||
6 | if [ -x /sbin/runuser ] | ||
7 | then | ||
8 | SU=runuser | ||
9 | else | ||
10 | SU=su | ||
11 | fi | ||
12 | |||
13 | PGENGINE=/usr/bin | ||
14 | PGDATA=/var/lib/postgresql/data | ||
15 | PGLOG=/var/lib/postgresql/pgstartup.log | ||
16 | script_result=0 | ||
17 | |||
18 | initdb(){ | ||
19 | if [ -f "$PGDATA/PG_VERSION" ] | ||
20 | then | ||
21 | echo -n "Data directory is not empty!" | ||
22 | echo -n " [FAILED] " | ||
23 | echo | ||
24 | script_result=1 | ||
25 | else | ||
26 | echo -n "Initializing database: " | ||
27 | if [ ! -e "$PGDATA" -a ! -h "$PGDATA" ] | ||
28 | then | ||
29 | mkdir -p "$PGDATA" || exit 1 | ||
30 | chown postgres:postgres "$PGDATA" | ||
31 | chmod go-rwx "$PGDATA" | ||
32 | fi | ||
33 | # Clean up SELinux tagging for PGDATA | ||
34 | [ -x /sbin/restorecon ] && /sbin/restorecon "$PGDATA" | ||
35 | |||
36 | # Make sure the startup-time log file is OK, too | ||
37 | if [ ! -e "$PGLOG" -a ! -h "$PGLOG" ] | ||
38 | then | ||
39 | touch "$PGLOG" || exit 1 | ||
40 | chown postgres:postgres "$PGLOG" | ||
41 | chmod go-rwx "$PGLOG" | ||
42 | [ -x /sbin/restorecon ] && /sbin/restorecon "$PGLOG" | ||
43 | fi | ||
44 | |||
45 | # Initialize the database | ||
46 | $SU -l postgres -c "$PGENGINE/initdb --pgdata='$PGDATA' --auth='ident'" >> "$PGLOG" 2>&1 < /dev/null | ||
47 | |||
48 | # Create directory for postmaster log | ||
49 | mkdir "$PGDATA/pg_log" | ||
50 | chown postgres:postgres "$PGDATA/pg_log" | ||
51 | chmod go-rwx "$PGDATA/pg_log" | ||
52 | |||
53 | if [ -f "$PGDATA/PG_VERSION" ] | ||
54 | then | ||
55 | echo -n " [ OK ] " | ||
56 | else | ||
57 | echo -n " [FAILED] " | ||
58 | script_result=1 | ||
59 | fi | ||
60 | echo | ||
61 | fi | ||
62 | } | ||
63 | |||
64 | case "$1" in | ||
65 | initdb) | ||
66 | initdb | ||
67 | ;; | ||
68 | *) | ||
69 | echo "Usage: $0 initdb" | ||
70 | exit 2 | ||
71 | esac | ||
72 | |||
73 | exit $script_result | ||
diff --git a/meta-oe/recipes-support/postgresql/files/postgresql.init b/meta-oe/recipes-support/postgresql/files/postgresql.init new file mode 100644 index 000000000..4a4f0cd16 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/postgresql.init | |||
@@ -0,0 +1,193 @@ | |||
1 | #!/bin/sh | ||
2 | # | ||
3 | # postgresql This is the init script for starting up the PostgreSQL | ||
4 | # server. | ||
5 | # | ||
6 | # chkconfig: - 64 36 | ||
7 | # description: PostgreSQL database server. | ||
8 | # processname: postmaster | ||
9 | # pidfile: /var/run/postmaster.PORT.pid | ||
10 | |||
11 | # This script is slightly unusual in that the name of the daemon (postmaster) | ||
12 | # is not the same as the name of the subsystem (postgresql) | ||
13 | |||
14 | # PGVERSION is the full package version, e.g., 8.4.0 | ||
15 | # Note: the specfile inserts the correct value during package build | ||
16 | PGVERSION=9.2.4 | ||
17 | # PGMAJORVERSION is major version, e.g., 8.4 (this should match PG_VERSION) | ||
18 | PGMAJORVERSION=`echo "$PGVERSION" | sed 's/^\([0-9]*\.[0-9]*\).*$/\1/'` | ||
19 | |||
20 | # Source function library. | ||
21 | . /etc/init.d/functions | ||
22 | |||
23 | # Find the name of the script | ||
24 | NAME=`basename $0` | ||
25 | if [ ${NAME:0:1} = "S" -o ${NAME:0:1} = "K" ] | ||
26 | then | ||
27 | NAME=${NAME:3} | ||
28 | fi | ||
29 | |||
30 | # For SELinux we need to use 'runuser' not 'su' | ||
31 | if [ -x /sbin/runuser ] | ||
32 | then | ||
33 | SU=runuser | ||
34 | else | ||
35 | SU=su | ||
36 | fi | ||
37 | |||
38 | |||
39 | # Set defaults for configuration variables | ||
40 | PGENGINE=/usr/bin | ||
41 | PGPORT=5432 | ||
42 | PGDATA=/var/lib/postgresql/data | ||
43 | PGLOG=/var/lib/postgresql/pgstartup.log | ||
44 | # Value to set as postmaster process's oom_adj | ||
45 | PG_OOM_ADJ=-17 | ||
46 | |||
47 | # Override defaults from /etc/sysconfig/postgresql if file is present | ||
48 | [ -f /etc/default/postgresql/${NAME} ] && . /etc/default/postgresql/${NAME} | ||
49 | |||
50 | export PGDATA | ||
51 | export PGPORT | ||
52 | |||
53 | lockfile="/var/lock/subsys/${NAME}" | ||
54 | pidfile="/var/run/postmaster.${PGPORT}.pid" | ||
55 | |||
56 | script_result=0 | ||
57 | |||
58 | start(){ | ||
59 | [ -x "$PGENGINE/postmaster" ] || exit 5 | ||
60 | |||
61 | PSQL_START=$"Starting ${NAME} service: " | ||
62 | |||
63 | # Make sure startup-time log file is valid | ||
64 | if [ ! -e "$PGLOG" -a ! -h "$PGLOG" ] | ||
65 | then | ||
66 | touch "$PGLOG" || exit 4 | ||
67 | chown postgres:postgres "$PGLOG" | ||
68 | chmod go-rwx "$PGLOG" | ||
69 | [ -x /sbin/restorecon ] && /sbin/restorecon "$PGLOG" | ||
70 | fi | ||
71 | |||
72 | # Check for the PGDATA structure | ||
73 | if [ -f "$PGDATA/PG_VERSION" ] && [ -d "$PGDATA/base" ] | ||
74 | then | ||
75 | # Check version of existing PGDATA | ||
76 | if [ x`cat "$PGDATA/PG_VERSION"` != x"$PGMAJORVERSION" ] | ||
77 | then | ||
78 | SYSDOCDIR="(Your System's documentation directory)" | ||
79 | if [ -d "/usr/doc/postgresql-$PGVERSION" ] | ||
80 | then | ||
81 | SYSDOCDIR=/usr/doc | ||
82 | fi | ||
83 | if [ -d "/usr/share/doc/postgresql-$PGVERSION" ] | ||
84 | then | ||
85 | SYSDOCDIR=/usr/share/doc | ||
86 | fi | ||
87 | if [ -d "/usr/doc/packages/postgresql-$PGVERSION" ] | ||
88 | then | ||
89 | SYSDOCDIR=/usr/doc/packages | ||
90 | fi | ||
91 | if [ -d "/usr/share/doc/packages/postgresql-$PGVERSION" ] | ||
92 | then | ||
93 | SYSDOCDIR=/usr/share/doc/packages | ||
94 | fi | ||
95 | echo | ||
96 | echo $"An old version of the database format was found." | ||
97 | echo $"You need to upgrade the data format before using PostgreSQL." | ||
98 | echo $"See $SYSDOCDIR/postgresql-$PGVERSION/README.rpm-dist for more information." | ||
99 | exit 1 | ||
100 | fi | ||
101 | else | ||
102 | # No existing PGDATA! Warn the user to initdb it. | ||
103 | echo | ||
104 | echo "$PGDATA is missing. Use \"postgresql-setup initdb\" to initialize the cluster first." | ||
105 | echo -n " [FAILED] " | ||
106 | echo | ||
107 | exit 1 | ||
108 | fi | ||
109 | |||
110 | echo -n "$PSQL_START" | ||
111 | test x"$PG_OOM_ADJ" != x && echo "$PG_OOM_ADJ" > /proc/self/oom_score_adj | ||
112 | $SU -l postgres -c "$PGENGINE/postmaster -p '$PGPORT' -D '$PGDATA' ${PGOPTS} &" >> "$PGLOG" 2>&1 < /dev/null | ||
113 | sleep 2 | ||
114 | pid=`head -n 1 "$PGDATA/postmaster.pid" 2>/dev/null` | ||
115 | if [ "x$pid" != x ] | ||
116 | then | ||
117 | echo -n " [ OK ]" | ||
118 | touch "$lockfile" | ||
119 | echo $pid > "$pidfile" | ||
120 | echo | ||
121 | else | ||
122 | echo -n " [FAILED]" | ||
123 | echo | ||
124 | script_result=1 | ||
125 | fi | ||
126 | } | ||
127 | |||
128 | stop(){ | ||
129 | echo -n $"Stopping ${NAME} service: " | ||
130 | if [ -e "$lockfile" ] | ||
131 | then | ||
132 | $SU -l postgres -c "$PGENGINE/pg_ctl stop -D '$PGDATA' -s -m fast" > /dev/null 2>&1 < /dev/null | ||
133 | ret=$? | ||
134 | if [ $ret -eq 0 ] | ||
135 | then | ||
136 | echo -n " [ OK ] " | ||
137 | rm -f "$pidfile" | ||
138 | rm -f "$lockfile" | ||
139 | else | ||
140 | echo -n " [FAILED] " | ||
141 | script_result=1 | ||
142 | fi | ||
143 | else | ||
144 | # not running; per LSB standards this is "ok" | ||
145 | echo -n " [ OK ] " | ||
146 | fi | ||
147 | echo | ||
148 | } | ||
149 | |||
150 | restart(){ | ||
151 | stop | ||
152 | start | ||
153 | } | ||
154 | |||
155 | condrestart(){ | ||
156 | [ -e "$lockfile" ] && restart || : | ||
157 | } | ||
158 | |||
159 | reload(){ | ||
160 | $SU -l postgres -c "$PGENGINE/pg_ctl reload -D '$PGDATA' -s" > /dev/null 2>&1 < /dev/null | ||
161 | } | ||
162 | |||
163 | |||
164 | # See how we were called. | ||
165 | case "$1" in | ||
166 | start) | ||
167 | start | ||
168 | ;; | ||
169 | stop) | ||
170 | stop | ||
171 | ;; | ||
172 | status) | ||
173 | status postmaster | ||
174 | script_result=$? | ||
175 | ;; | ||
176 | restart) | ||
177 | restart | ||
178 | ;; | ||
179 | condrestart|try-restart) | ||
180 | condrestart | ||
181 | ;; | ||
182 | reload) | ||
183 | reload | ||
184 | ;; | ||
185 | force-reload) | ||
186 | restart | ||
187 | ;; | ||
188 | *) | ||
189 | echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" | ||
190 | exit 2 | ||
191 | esac | ||
192 | |||
193 | exit $script_result | ||
diff --git a/meta-oe/recipes-support/postgresql/files/postgresql.pam b/meta-oe/recipes-support/postgresql/files/postgresql.pam new file mode 100644 index 000000000..0b6fdc5f2 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/postgresql.pam | |||
@@ -0,0 +1,4 @@ | |||
1 | #%PAM-1.0 | ||
2 | auth include common-auth | ||
3 | account include common-account | ||
4 | password include common-password | ||
diff --git a/meta-oe/recipes-support/postgresql/files/postgresql.service b/meta-oe/recipes-support/postgresql/files/postgresql.service new file mode 100644 index 000000000..4ec959e84 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/files/postgresql.service | |||
@@ -0,0 +1,27 @@ | |||
1 | [Unit] | ||
2 | Description=PostgreSQL database server | ||
3 | After=network.target | ||
4 | |||
5 | [Service] | ||
6 | Type=forking | ||
7 | User=postgres | ||
8 | Group=postgres | ||
9 | |||
10 | # Port number for server to listen on | ||
11 | Environment=PGPORT=5432 | ||
12 | |||
13 | # Location of database directory | ||
14 | Environment=PGDATA=/var/lib/postgresql/data | ||
15 | |||
16 | # Disable OOM kill on the postmaster | ||
17 | OOMScoreAdjust=-17 | ||
18 | |||
19 | ExecStart=@BINDIR@/pg_ctl start -D ${PGDATA} -s -o "-p ${PGPORT}" -w -t 300 | ||
20 | ExecStop=@BINDIR@/pg_ctl stop -D ${PGDATA} -s -m fast | ||
21 | ExecReload=@BINDIR@/pg_ctl reload -D ${PGDATA} -s | ||
22 | |||
23 | # Give a reasonable amount of time for the server to start up/shut down | ||
24 | TimeoutSec=300 | ||
25 | |||
26 | [Install] | ||
27 | WantedBy=multi-user.target | ||
diff --git a/meta-oe/recipes-support/postgresql/postgresql-9.2.4/ecpg-parallel-make-fix.patch b/meta-oe/recipes-support/postgresql/postgresql-9.2.4/ecpg-parallel-make-fix.patch new file mode 100644 index 000000000..63615cd51 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/postgresql-9.2.4/ecpg-parallel-make-fix.patch | |||
@@ -0,0 +1,31 @@ | |||
1 | Upstream-status: backport | ||
2 | |||
3 | From 602070f9cce790debd8d1469254e7726ab499ae7 Mon Sep 17 00:00:00 2001 | ||
4 | From: Peter Eisentraut <peter_e@gmx.net> | ||
5 | Date: Fri, 29 Mar 2013 21:39:55 -0400 | ||
6 | Subject: [PATCH] ecpg: Parallel make fix | ||
7 | |||
8 | In some parallel make situations, the install-headers target could be | ||
9 | called before the installation directories are created by installdirs, | ||
10 | causing the installation to fail. Fix that by making install-headers | ||
11 | depend on installdirs. | ||
12 | --- | ||
13 | src/interfaces/ecpg/include/Makefile | 2 +- | ||
14 | 1 file changed, 1 insertion(+), 1 deletion(-) | ||
15 | |||
16 | diff --git a/src/interfaces/ecpg/include/Makefile b/src/interfaces/ecpg/include/Makefile | ||
17 | index eab833b..e92e56f 100644 | ||
18 | --- a/src/interfaces/ecpg/include/Makefile | ||
19 | +++ b/src/interfaces/ecpg/include/Makefile | ||
20 | @@ -18,7 +18,7 @@ ecpg_headers = ecpgerrno.h ecpglib.h ecpgtype.h sqlca.h sql3types.h ecpg_informi | ||
21 | sqlda.h sqlda-compat.h sqlda-native.h | ||
22 | informix_headers = datetime.h decimal.h sqltypes.h | ||
23 | |||
24 | -install-headers: $(ecpg_headers) $(informix_headers) | ||
25 | +install-headers: $(ecpg_headers) $(informix_headers) installdirs | ||
26 | $(INSTALL_DATA) $(addprefix $(srcdir)/,$(ecpg_headers)) '$(DESTDIR)$(includedir)/' | ||
27 | $(INSTALL_DATA) $(addprefix $(srcdir)/,$(informix_headers)) '$(DESTDIR)$(informix_esql_dir)/' | ||
28 | $(INSTALL_DATA) $(ecpg_config_h) '$(DESTDIR)$(includedir)' | ||
29 | -- | ||
30 | 1.8.3.4 | ||
31 | |||
diff --git a/meta-oe/recipes-support/postgresql/postgresql-9.2.4/remove.autoconf.version.check.patch b/meta-oe/recipes-support/postgresql/postgresql-9.2.4/remove.autoconf.version.check.patch new file mode 100644 index 000000000..022aa3d76 --- /dev/null +++ b/meta-oe/recipes-support/postgresql/postgresql-9.2.4/remove.autoconf.version.check.patch | |||
@@ -0,0 +1,15 @@ | |||
1 | Index: postgresql-9.2.4/configure.in | ||
2 | =================================================================== | ||
3 | --- postgresql-9.2.4.orig/configure.in | ||
4 | +++ postgresql-9.2.4/configure.in | ||
5 | @@ -19,10 +19,6 @@ m4_pattern_forbid(^PGAC_)dnl to catch un | ||
6 | |||
7 | AC_INIT([PostgreSQL], [9.2.4], [pgsql-bugs@postgresql.org]) | ||
8 | |||
9 | -m4_if(m4_defn([m4_PACKAGE_VERSION]), [2.63], [], [m4_fatal([Autoconf version 2.63 is required. | ||
10 | -Untested combinations of 'autoconf' and PostgreSQL versions are not | ||
11 | -recommended. You can remove the check from 'configure.in' but it is then | ||
12 | -your responsibility whether the result works or not.])]) | ||
13 | AC_COPYRIGHT([Copyright (c) 1996-2012, PostgreSQL Global Development Group]) | ||
14 | AC_CONFIG_SRCDIR([src/backend/access/common/heaptuple.c]) | ||
15 | AC_CONFIG_AUX_DIR(config) | ||
diff --git a/meta-oe/recipes-support/postgresql/postgresql.inc b/meta-oe/recipes-support/postgresql/postgresql.inc new file mode 100644 index 000000000..1397f564d --- /dev/null +++ b/meta-oe/recipes-support/postgresql/postgresql.inc | |||
@@ -0,0 +1,395 @@ | |||
1 | SUMMARY = "PostgreSQL is a powerful, open source relational database system." | ||
2 | DESCRIPTION = "\ | ||
3 | PostgreSQL is an advanced Object-Relational database management system \ | ||
4 | (DBMS) that supports almost all SQL constructs (including \ | ||
5 | transactions, subselects and user-defined types and functions). The \ | ||
6 | postgresql package includes the client programs and libraries that \ | ||
7 | you'll need to access a PostgreSQL DBMS server. These PostgreSQL \ | ||
8 | client programs are programs that directly manipulate the internal \ | ||
9 | structure of PostgreSQL databases on a PostgreSQL server. These client \ | ||
10 | programs can be located on the same machine with the PostgreSQL \ | ||
11 | server, or may be on a remote machine which accesses a PostgreSQL \ | ||
12 | server over a network connection. This package contains the docs \ | ||
13 | in HTML for the whole package, as well as command-line utilities for \ | ||
14 | managing PostgreSQL databases on a PostgreSQL server. \ | ||
15 | \ | ||
16 | If you want to manipulate a PostgreSQL database on a local or remote \ | ||
17 | PostgreSQL server, you need this package. You also need to install \ | ||
18 | this package if you're installing the postgresql-server package. \ | ||
19 | " | ||
20 | HOMEPAGE = "http://www.postgresql.com" | ||
21 | LICENSE = "BSD" | ||
22 | DEPENDS = "zlib readline tzcode-native" | ||
23 | INC_PR = "r0" | ||
24 | |||
25 | ARM_INSTRUCTION_SET = "arm" | ||
26 | |||
27 | SRC_URI = "http://ftp.postgresql.org/pub/source/v${PV}/${BP}.tar.bz2 \ | ||
28 | file://postgresql.init \ | ||
29 | file://postgresql-bashprofile \ | ||
30 | file://postgresql.pam \ | ||
31 | file://postgresql-setup \ | ||
32 | file://postgresql.service \ | ||
33 | file://0001-Use-pkg-config-for-libxml2-detection.patch \ | ||
34 | file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \ | ||
35 | file://0003-Shore-up-ADMIN-OPTION-restrictions.patch \ | ||
36 | file://0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch \ | ||
37 | file://0005-Avoid-repeated-name-lookups-during-table-and-index-D.patch \ | ||
38 | file://0006-Fix-handling-of-wide-datetime-input-output.patch \ | ||
39 | file://0007-Make-pqsignal-available-to-pg_regress-of-ECPG-and-is.patch \ | ||
40 | file://0008-Prevent-potential-overruns-of-fixed-size-buffers.patch \ | ||
41 | " | ||
42 | |||
43 | LEAD_SONAME = "libpq.so" | ||
44 | |||
45 | # LDFLAGS for shared libraries | ||
46 | export LDFLAGS_SL = "${LDFLAGS}" | ||
47 | |||
48 | inherit autotools pkgconfig perlnative pythonnative useradd update-rc.d systemd | ||
49 | |||
50 | SYSTEMD_SERVICE_${PN} = "postgresql.service" | ||
51 | SYSTEMD_AUTO_ENABLE_${PN} = "disable" | ||
52 | |||
53 | DEPENDS_append = " ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd-systemctl-native', '', d)}" | ||
54 | pkg_postinst_${PN} () { | ||
55 | if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd sysvinit', 'true', 'false', d)}; then | ||
56 | if [ -n "$D" ]; then | ||
57 | OPTS="--root=$D" | ||
58 | fi | ||
59 | systemctl $OPTS mask postgresql-server.service | ||
60 | fi | ||
61 | } | ||
62 | |||
63 | enable_pam = "${@base_contains('DISTRO_FEATURES', 'pam', 'pam', '', d)}" | ||
64 | PACKAGECONFIG ??= "${enable_pam} openssl python uuid libxml tcl nls libxml perl" | ||
65 | PACKAGECONFIG[pam] = "--with-pam,--without-pam,libpam," | ||
66 | PACKAGECONFIG[openssl] = "--with-openssl,--without-openssl,openssl," | ||
67 | PACKAGECONFIG[python] = "--with-python,--without-python,python,python" | ||
68 | PACKAGECONFIG[uuid] = "--with-ossp-uuid,--without-ossp-uuid,ossp-uuid," | ||
69 | # when tcl native package is fixed change WORKDIR to STAGING_BINDIR_CROSS | ||
70 | PACKAGECONFIG[tcl] = \ | ||
71 | "--with-tcl --with-tclconfig=${STAGING_BINDIR_CROSS},--without-tcl,tcl," | ||
72 | PACKAGECONFIG[nls] = "--enable-nls,--disable-nls,," | ||
73 | PACKAGECONFIG[libxml] = "--with-libxml,--without-libxml,libxml2,libxml2" | ||
74 | PACKAGECONFIG[perl] = "--with-perl,--without-perl,perl,perl" | ||
75 | |||
76 | EXTRA_OECONF += "--enable-thread-safety --disable-rpath \ | ||
77 | --datadir=${datadir}/${BPN} \ | ||
78 | --sysconfdir=${sysconfdir}/${BPN} \ | ||
79 | --without-krb5 \ | ||
80 | " | ||
81 | EXTRA_OECONF_sh4 += "--disable-spinlocks" | ||
82 | EXTRA_OECONF_aarch64 += "--disable-spinlocks" | ||
83 | |||
84 | PACKAGES_DYNAMIC += "^${PN}-plperl ^${PN}-plperl-dbg \ | ||
85 | ^${PN}-pltcl ^${PN}-pltcl-dbg \ | ||
86 | ^${PN}-plpython ^${PN}-plpython-dbg \ | ||
87 | " | ||
88 | |||
89 | python populate_packages_prepend() { | ||
90 | |||
91 | def fill_more(name, dbg=True): | ||
92 | if name is None or name.strip() == "": | ||
93 | return | ||
94 | |||
95 | fpack=d.getVar('PACKAGES') or "" | ||
96 | fpack="${PN}-" + name + " " + fpack | ||
97 | if dbg: | ||
98 | fpack="${PN}-" + name + "-dbg" + " " + fpack | ||
99 | d.setVar('PACKAGES', fpack) | ||
100 | |||
101 | conf=(d.getVar('PACKAGECONFIG', True) or "").split() | ||
102 | pack=d.getVar('PACKAGES') or "" | ||
103 | bb.debug(1, "PACKAGECONFIG=%s" % conf) | ||
104 | bb.debug(1, "PACKAGES1=%s" % pack ) | ||
105 | |||
106 | if "perl" in conf : | ||
107 | fill_more("plperl") | ||
108 | |||
109 | if "tcl" in conf: | ||
110 | fill_more("pltcl") | ||
111 | |||
112 | if "python" in conf: | ||
113 | fill_more("plpython") | ||
114 | |||
115 | pack=d.getVar('PACKAGES', True) or "" | ||
116 | bb.debug(1, "PACKAGES2=%s" % pack) | ||
117 | |||
118 | } | ||
119 | |||
120 | do_configure() { | ||
121 | # do_configure_prepend | ||
122 | # make sure configure finds python includdirs with these envs | ||
123 | export BUILD_SYS=${BUILD_SYS} HOST_SYS=${HOST_SYS} \ | ||
124 | STAGING_INCDIR=${STAGING_INCDIR} \ | ||
125 | STAGING_LIBDIR=${STAGING_LIBDIR} | ||
126 | |||
127 | # do_configure | ||
128 | autotools_do_configure | ||
129 | |||
130 | # do_configure_append | ||
131 | # workaround perl package related bugs | ||
132 | sed -i -e "s:-L/usr/local/lib:-L=/usr/local/lib:g" \ | ||
133 | ${B}/src/Makefile.global | ||
134 | LIBPNA="\${STAGING_LIBDIR_NATIVE}/perl-native" | ||
135 | LIBNA="\${STAGING_LIBDIR_NATIVE}" | ||
136 | BLIBNA="\${STAGING_BASE_LIBDIR_NATIVE}" | ||
137 | sed -i -e "/^perl_archlibexp/s:${LIBPNA}:${STAGING_LIBDIR}:g" \ | ||
138 | ${B}/src/Makefile.global | ||
139 | sed -i -e "/^perl_privlibexp/s:${LIBPNA}:${STAGING_LIBDIR}:g" \ | ||
140 | ${B}/src/Makefile.global | ||
141 | # remove the rpath, replace with correct lib path | ||
142 | sed -i \ | ||
143 | -e "/^perl_embed_ldflags/s:-Wl,-rpath,${LIBNA}::g" \ | ||
144 | -e "/^perl_embed_ldflags/s:-Wl,-rpath,${BLIBNA}::g" \ | ||
145 | -e "/^perl_embed_ldflags/s:-Wl,-rpath-link,${LIBNA}::g" \ | ||
146 | -e "/^perl_embed_ldflags/s:-Wl,-rpath-link,${BLIBNA}::g" \ | ||
147 | -e "/^perl_embed_ldflags/s:${LIBPNA}:${STAGING_LIBDIR}:g" \ | ||
148 | -e "/^perl_embed_ldflags/s:${LIBNA}:${STAGING_LIBDIR}:g" \ | ||
149 | -e "/^perl_embed_ldflags/s:${BLIBNA}:${STAGING_BASELIBDIR}:g" \ | ||
150 | ${B}/src/Makefile.global | ||
151 | |||
152 | # workaround perl package's libperl.so problem | ||
153 | # we are using perlnative so this perl should have same version | ||
154 | perl_version=`perl -v 2>/dev/null | \ | ||
155 | sed -n 's/This is perl.*v[a-z ]*\([0-9]\.[0-9][0-9.]*\).*$/\1/p'` | ||
156 | if [ ! -h "${STAGING_LIBDIR}/perl/$perl_version/CORE/libperl.so" -a \ | ||
157 | ! -h "${STAGING_LIBDIR}/libperl.so" ]; then | ||
158 | ln -sf ../../../libperl.so.5 \ | ||
159 | ${STAGING_LIBDIR}/perl/$perl_version/CORE/libperl.so | ||
160 | fi | ||
161 | } | ||
162 | |||
163 | do_compile_append() { | ||
164 | oe_runmake -C contrib all | ||
165 | } | ||
166 | |||
167 | # server needs to configure user and group | ||
168 | usernum = "28" | ||
169 | groupnum = "28" | ||
170 | USERADD_PACKAGES = "${PN}" | ||
171 | USERADD_PARAM_${PN} = "-M -g postgres -o -r -d ${localstatedir}/lib/${BPN} \ | ||
172 | -s /bin/bash -c 'PostgreSQL Server' -u ${usernum} postgres" | ||
173 | GROUPADD_PARAM_${PN} = "-g ${groupnum} -o -r postgres" | ||
174 | |||
175 | INITSCRIPT_PACKAGES = "${PN}" | ||
176 | INITSCRIPT_NAME = "${BPN}-server" | ||
177 | INITSCRIPT_PARAMS = "start 64 . stop 36 0 1 2 3 4 5 6 ." | ||
178 | |||
179 | do_install_append() { | ||
180 | # install contrib | ||
181 | oe_runmake DESTDIR=${D} -C contrib install | ||
182 | # install tutorial | ||
183 | install -d -m 0755 ${D}${libdir}/${BPN}/tutorial | ||
184 | install ${B}/src/tutorial/* ${D}${libdir}/${BPN}/tutorial | ||
185 | |||
186 | # install COPYRIGHT README HISTORY | ||
187 | install -d -m 0755 ${D}${docdir}/${BPN} | ||
188 | for i in ${B}/{COPYRIGHT,README,HISTORY} ${B}/doc/{KNOWN_BUGS,MISSING_FEATURES,README*,bug.template}; do | ||
189 | [ -f $i ] && install $i ${D}${docdir}/${BPN} | ||
190 | done | ||
191 | |||
192 | # install dirs and server init | ||
193 | install -d ${D}${sysconfdir}/init.d | ||
194 | install -m 0755 ${WORKDIR}/${BPN}.init ${D}${sysconfdir}/init.d/${BPN}-server | ||
195 | sed -i -e "s/^PGVERSION=.*$/PGVERSION=${PV}/g" ${D}${sysconfdir}/init.d/${BPN}-server | ||
196 | install -m 0755 ${WORKDIR}/${BPN}-setup ${D}${bindir}/${BPN}-setup | ||
197 | install -d -m 700 ${D}${localstatedir}/lib/${BPN}/data | ||
198 | install -d -m 700 ${D}${localstatedir}/lib/${BPN}/backups | ||
199 | install -m 644 ${WORKDIR}/${BPN}-bashprofile ${D}${localstatedir}/lib/${BPN}/.bash_profile | ||
200 | chown -R postgres:postgres ${D}${localstatedir}/lib/${BPN} | ||
201 | # multiple server config directory | ||
202 | install -d -m 700 ${D}${sysconfdir}/default/${BPN} | ||
203 | |||
204 | if [ "${@d.getVar('enable_pam', True)}" = "pam" ]; then | ||
205 | install -d ${D}${sysconfdir}/pam.d | ||
206 | install -m 644 ${WORKDIR}/postgresql.pam ${D}${sysconfdir}/pam.d/postgresql | ||
207 | fi | ||
208 | |||
209 | # Install systemd unit files | ||
210 | install -d ${D}${systemd_unitdir}/system | ||
211 | install -m 0644 ${WORKDIR}/postgresql.service ${D}${systemd_unitdir}/system | ||
212 | sed -i -e 's,@BINDIR@,${bindir},g' \ | ||
213 | ${D}${systemd_unitdir}/system/postgresql.service | ||
214 | } | ||
215 | |||
216 | SSTATE_SCAN_FILES += "Makefile.global" | ||
217 | |||
218 | PACKAGES =+ "${PN}-client ${PN}-server-dev ${PN}-timezone \ | ||
219 | libecpg-compat-dbg libecpg-compat libecpg-compat-dev \ | ||
220 | libecpg-dbg libecpg libecpg-dev libecpg-staticdev libecpg-doc \ | ||
221 | libpq-dbg libpq libpq-dev libpq-staticdev \ | ||
222 | libpgtypes-dbg libpgtypes libpgtypes-staticdev libpgtypes-dev \ | ||
223 | ${PN}-contrib ${PN}-contrib-dbg \ | ||
224 | " | ||
225 | |||
226 | FILES_${PN} += "${sysconfdir}/init.d/${BPN}-server \ | ||
227 | ${localstatedir}/lib/${BPN}/data ${localstatedir}/lib/${BPN}/backups \ | ||
228 | ${localstatedir}/lib/${BPN}/.bash_profile ${sysconfdir}/default/${BPN} \ | ||
229 | ${libdir}/${BPN}/dict_snowball.so ${libdir}/${BPN}/plpgsql.so \ | ||
230 | ${libdir}/${BPN}/euc2004_sjis2004.so \ | ||
231 | ${libdir}/${BPN}/libpqwalreceiver.so \ | ||
232 | ${libdir}/${BPN}/*_and_*.so \ | ||
233 | ${@'${sysconfdir}/pam.d/postgresql' \ | ||
234 | if 'pam' == d.getVar('enable_pam', True) \ | ||
235 | else ''} \ | ||
236 | " | ||
237 | |||
238 | FILES_${PN}-dbg += " ${libdir}/${BPN}/.debug/dict_snowball.so \ | ||
239 | ${libdir}/${BPN}/.debug/plpgsql.so \ | ||
240 | ${libdir}/${BPN}/.debug/euc2004_sjis2004.so \ | ||
241 | ${libdir}/${BPN}/.debug/libpqwalreceiver.so \ | ||
242 | ${libdir}/${BPN}/.debug/*_and_*.so \ | ||
243 | " | ||
244 | |||
245 | FILES_${PN}-client = "${bindir}/clusterdb \ | ||
246 | ${bindir}/createdb \ | ||
247 | ${bindir}/createlang \ | ||
248 | ${bindir}/createuser \ | ||
249 | ${bindir}/dropdb \ | ||
250 | ${bindir}/droplang \ | ||
251 | ${bindir}/dropuser \ | ||
252 | ${bindir}/pg_dump \ | ||
253 | ${bindir}/pg_dumpall \ | ||
254 | ${bindir}/pg_restore \ | ||
255 | ${bindir}/psql \ | ||
256 | ${bindir}/reindexdb \ | ||
257 | ${bindir}/vacuumdb \ | ||
258 | ${bindir}/vacuumlo \ | ||
259 | ${datadir}/${BPN}/psqlrc.sample" | ||
260 | |||
261 | FILES_${PN}-client-doc = "${mandir}/man1/clusterdb.* \ | ||
262 | ${mandir}/man1/createdb.* ${mandir}/man1/createlang.* \ | ||
263 | ${mandir}/man1/createuser.* ${mandir}/man1/dropdb.* \ | ||
264 | ${mandir}/man1/droplang.* ${mandir}/man1/dropuser.* \ | ||
265 | ${mandir}/man1/pg_dump.* ${mandir}/man1/pg_dumpall.* \ | ||
266 | ${mandir}/man1/pg_restore.* ${mandir}/man1/psql.* \ | ||
267 | ${mandir}/man1/reindexdb.* ${mandir}/man1/vacuumdb.* \ | ||
268 | ${mandir}/man7/* \ | ||
269 | " | ||
270 | |||
271 | FILES_${PN}-doc += "${docdir}/${BPN}/html ${libdir}/${BPN}/tutorial/ \ | ||
272 | ${mandir}/man1/initdb.* ${mandir}/man1/pg_controldata.* \ | ||
273 | ${mandir}/man1/pg_ctl.* ${mandir}/man1/pg_resetxlog.* \ | ||
274 | ${mandir}/man1/postgres.* ${mandir}/man1/postmaster.* \ | ||
275 | " | ||
276 | |||
277 | FILES_${PN}-timezone = "${datadir}/${BPN}/timezone \ | ||
278 | ${datadir}/${BPN}/timezonesets \ | ||
279 | " | ||
280 | RDEPENDS_${PN} += "${PN}-timezone" | ||
281 | FILES_${PN}-server-dev = "${includedir}/${BPN}/server" | ||
282 | |||
283 | FILES_libecpg = "${libdir}/libecpg*${SOLIBS}" | ||
284 | FILES_libecpg-dbg = "${libdir}/.debug/libecpg*" | ||
285 | FILES_libecpg-dev = "${libdir}/libecpg*${SOLIBSDEV} \ | ||
286 | ${libdir}/libpgtypes*${SOLIBSDEV} \ | ||
287 | ${includedir}/ecpg*.h ${includedir}/${BPN}/ecpg*.h \ | ||
288 | ${includedir}/pgtypes*.h ${includedir}/${BPN}/informix \ | ||
289 | ${includedir}/sql3types.h ${includedir}/sqlca.h" | ||
290 | FILES_libecpg-doc = "${mandir}/man1/ecpg.*" | ||
291 | FILES_libecpg-staticdev = "${libdir}/libecpg*.a" | ||
292 | SECTION_libecpg-staticdev = "devel" | ||
293 | RDEPENDS_libecpg-staticdev = "libecpg-dev (= ${EXTENDPKGV})" | ||
294 | |||
295 | FILES_libpq = "${libdir}/libpq*${SOLIBS}" | ||
296 | FILES_libpq-dbg = "${libdir}/.debug/libpq* ${libdir}/${BPN}/pgxs/src/test/regress/.debug/*" | ||
297 | FILES_libpq-dev = "${libdir}/libpq*${SOLIBSDEV} \ | ||
298 | ${includedir}" | ||
299 | FILES_libpq-staticdev = "${libdir}/libpq*.a ${libdir}/libpgport.a" | ||
300 | SECTION_libpq-staticdev = "devel" | ||
301 | RDEPENDS_libpq-staticdev = "libpq-dev (= ${EXTENDPKGV})" | ||
302 | |||
303 | FILES_libecpg-compat = "${libdir}/libecpg_compat*${SOLIBS}" | ||
304 | FILES_libecpg-compat-dbg = "${libdir}/.debug/libecpg_compat*" | ||
305 | FILES_libecpg-compat-dev = "${libdir}/libecpg_compat*${SOLIBS}" | ||
306 | FILES_libpgtypes = "${libdir}/libpgtypes*${SOLIBS}" | ||
307 | FILES_libpgtypes-dbg = "${libdir}/.debug/libpgtypes*" | ||
308 | FILES_libpgtypes-staticdev = "${libdir}/libpgtypes*.a" | ||
309 | FILES_libpgtypes-dev = "${libdir}/libpgtypes*${SOLIBS} ${includedir}/pgtypes*.h" | ||
310 | |||
311 | FILES_${PN}-contrib = " ${bindir}/oid2name ${bindir}/pg_standby \ | ||
312 | ${bindir}/pgbench ${bindir}/vacuumlo \ | ||
313 | ${S}/contrib/spi/*.example \ | ||
314 | ${libdir}/${BPN}/_int.so ${libdir}/${BPN}/adminpack.so \ | ||
315 | ${libdir}/${BPN}/autoinc.so ${libdir}/${BPN}/auto_explain.so \ | ||
316 | ${libdir}/${BPN}/auth_delay.so ${libdir}/${BPN}/btree_gin.so \ | ||
317 | ${libdir}/${BPN}/btree_gist.so ${libdir}/${BPN}/.so \ | ||
318 | ${libdir}/${BPN}/chkpass.so ${libdir}/${BPN}/citext.so \ | ||
319 | ${libdir}/${BPN}/cube.so ${libdir}/${BPN}/dblink.so \ | ||
320 | ${libdir}/${BPN}/dict_int.so ${libdir}/${BPN}/dict_xsyn.so \ | ||
321 | ${libdir}/${BPN}/dummy_seclabel.so ${libdir}/${BPN}/earthdistance.so \ | ||
322 | ${libdir}/${BPN}/file_fdw.so ${libdir}/${BPN}/fuzzystrmatch.so \ | ||
323 | ${libdir}/${BPN}/hstore.so ${libdir}/${BPN}/insert_username.so \ | ||
324 | ${libdir}/${BPN}/isn.so ${libdir}/${BPN}/lo.so \ | ||
325 | ${libdir}/${BPN}/ltree.so ${libdir}/${BPN}/moddatetime.so \ | ||
326 | ${libdir}/${BPN}/pageinspect.so ${libdir}/${BPN}/pg_buffercache.so \ | ||
327 | ${libdir}/${BPN}/pg_freespacemap.so ${libdir}/${BPN}/pg_trgm.so \ | ||
328 | ${libdir}/${BPN}/pgcrypto.so ${libdir}/${BPN}/pgrowlocks.so \ | ||
329 | ${libdir}/${BPN}/pgstattuple.so ${libdir}/${BPN}/pg_stat_statements.so \ | ||
330 | ${libdir}/${BPN}/refint.so ${libdir}/${BPN}/seg.so \ | ||
331 | ${libdir}/${BPN}/sslinfo.so \ | ||
332 | ${libdir}/${BPN}/tablefunc.so \ | ||
333 | ${libdir}/${BPN}/test_parser.so ${libdir}/${BPN}/timetravel.so \ | ||
334 | ${libdir}/${BPN}/tsearch2.so ${libdir}/${BPN}/uuid-ossp.so \ | ||
335 | ${libdir}/${BPN}/pgxml.so ${libdir}/${BPN}/passwordcheck.so \ | ||
336 | ${libdir}/${BPN}/pg_upgrade_support.so ${libdir}/${BPN}/.so \ | ||
337 | ${libdir}/${BPN}/unaccent.so \ | ||
338 | " | ||
339 | FILES_${PN}-contrib-dbg = " \ | ||
340 | ${libdir}/${BPN}/.debug/_int.so ${libdir}/${BPN}/.debug/adminpack.so \ | ||
341 | ${libdir}/${BPN}/.debug/autoinc.so ${libdir}/${BPN}/.debug/auto_explain.so \ | ||
342 | ${libdir}/${BPN}/.debug/auth_delay.so ${libdir}/${BPN}/.debug/btree_gin.so \ | ||
343 | ${libdir}/${BPN}/.debug/btree_gist.so ${libdir}/${BPN}/.debug/.so \ | ||
344 | ${libdir}/${BPN}/.debug/chkpass.so ${libdir}/${BPN}/.debug/citext.so \ | ||
345 | ${libdir}/${BPN}/.debug/cube.so ${libdir}/${BPN}/.debug/dblink.so \ | ||
346 | ${libdir}/${BPN}/.debug/dict_int.so ${libdir}/${BPN}/.debug/dict_xsyn.so \ | ||
347 | ${libdir}/${BPN}/.debug/dummy_seclabel.so \ | ||
348 | ${libdir}/${BPN}/.debug/earthdistance.so \ | ||
349 | ${libdir}/${BPN}/.debug/file_fdw.so ${libdir}/${BPN}/.debug/fuzzystrmatch.so \ | ||
350 | ${libdir}/${BPN}/.debug/hstore.so ${libdir}/${BPN}/.debug/insert_username.so \ | ||
351 | ${libdir}/${BPN}/.debug/isn.so ${libdir}/${BPN}/.debug/lo.so \ | ||
352 | ${libdir}/${BPN}/.debug/ltree.so ${libdir}/${BPN}/.debug/moddatetime.so \ | ||
353 | ${libdir}/${BPN}/.debug/pageinspect.so \ | ||
354 | ${libdir}/${BPN}/.debug/pg_buffercache.so \ | ||
355 | ${libdir}/${BPN}/.debug/pg_freespacemap.so \ | ||
356 | ${libdir}/${BPN}/.debug/pg_trgm.so \ | ||
357 | ${libdir}/${BPN}/.debug/pgcrypto.so ${libdir}/${BPN}/.debug/pgrowlocks.so \ | ||
358 | ${libdir}/${BPN}/.debug/pgstattuple.so \ | ||
359 | ${libdir}/${BPN}/.debug/pg_stat_statements.so \ | ||
360 | ${libdir}/${BPN}/.debug/refint.so ${libdir}/${BPN}/.debug/seg.so \ | ||
361 | ${libdir}/${BPN}/.debug/sslinfo.so \ | ||
362 | ${libdir}/${BPN}/.debug/tablefunc.so \ | ||
363 | ${libdir}/${BPN}/.debug/test_parser.so ${libdir}/${BPN}/.debug/timetravel.so \ | ||
364 | ${libdir}/${BPN}/.debug/tsearch2.so ${libdir}/${BPN}/.debug/uuid-ossp.so \ | ||
365 | ${libdir}/${BPN}/.debug/pgxml.so ${libdir}/${BPN}/.debug/passwordcheck.so \ | ||
366 | ${libdir}/${BPN}/.debug/pg_upgrade_support.so \ | ||
367 | ${libdir}/${BPN}/.debug/unaccent.so \ | ||
368 | " | ||
369 | DESCRIPTION_${PN}-contrib = "The postgresql-contrib package contains \ | ||
370 | contributed packages that are included in the PostgreSQL distribution." | ||
371 | |||
372 | FILES_${PN}-pltcl = "${libdir}/${BPN}/pltcl.so ${bindir}/pltcl_delmod \ | ||
373 | ${binddir}/pltcl_listmod ${bindir}/pltcl_loadmod \ | ||
374 | ${datadir}/${BPN}/unknown.pltcl" | ||
375 | FILES_${PN}-pltcl-dbg = "${libdir}/${BPN}/.debug/pltcl.so" | ||
376 | SUMMARY_${PN}-pltcl = "The Tcl procedural language for PostgreSQL" | ||
377 | DESCRIPTION_${PN}-pltcl = "PostgreSQL is an advanced Object-Relational \ | ||
378 | database management system. The postgresql-pltcl package contains the PL/Tcl \ | ||
379 | procedural language for the backend." | ||
380 | |||
381 | FILES_${PN}-plperl = "${libdir}/${BPN}/plperl.so" | ||
382 | FILES_${PN}-plperl-dbg = "${libdir}/${BPN}/.debug/plperl.so" | ||
383 | SUMMARY_${PN}-plperl = "The Perl procedural language for PostgreSQL" | ||
384 | DESCRIPTION_${PN}-plperl = "PostgreSQL is an advanced Object-Relational \ | ||
385 | database management system. The postgresql-plperl package contains the \ | ||
386 | PL/Perl procedural language for the backend." | ||
387 | |||
388 | # In version 8, it will be plpython.so | ||
389 | # In version 9, it might be plpython{2,3}.so depending on python2 or 3 | ||
390 | FILES_${PN}-plpython = "${libdir}/${BPN}/plpython*.so" | ||
391 | FILES_${PN}-plpython-dbg = "${libdir}/${BPN}/.debug/plpython*.so" | ||
392 | SUMMARY_${PN}-plpython = "The Python procedural language for PostgreSQL" | ||
393 | DESCRIPTION_${PN}-plpython = "PostgreSQL is an advanced Object-Relational \ | ||
394 | database management system. The postgresql-plpython package contains \ | ||
395 | the PL/Python procedural language for the backend." | ||
diff --git a/meta-oe/recipes-support/postgresql/postgresql_9.2.4.bb b/meta-oe/recipes-support/postgresql/postgresql_9.2.4.bb new file mode 100644 index 000000000..49ca53fae --- /dev/null +++ b/meta-oe/recipes-support/postgresql/postgresql_9.2.4.bb | |||
@@ -0,0 +1,13 @@ | |||
1 | require postgresql.inc | ||
2 | |||
3 | LIC_FILES_CHKSUM = "file://COPYRIGHT;md5=ab55a5887d3f8ba77d0fd7db787e4bab" | ||
4 | |||
5 | PR = "${INC_PR}.0" | ||
6 | |||
7 | SRC_URI += "\ | ||
8 | file://remove.autoconf.version.check.patch \ | ||
9 | file://ecpg-parallel-make-fix.patch \ | ||
10 | " | ||
11 | |||
12 | SRC_URI[md5sum] = "6ee5bb53b97da7c6ad9cb0825d3300dd" | ||
13 | SRC_URI[sha256sum] = "d97dd918a88a4449225998f46aafa85216a3f89163a3411830d6890507ffae93" | ||