diff options
-rw-r--r-- | meta-oe/recipes-support/postgresql/files/0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch | 267 | ||||
-rw-r--r-- | meta-oe/recipes-support/postgresql/postgresql.inc | 1 |
2 files changed, 268 insertions, 0 deletions
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/postgresql.inc b/meta-oe/recipes-support/postgresql/postgresql.inc index d6a4cd781..e2e5947b7 100644 --- a/meta-oe/recipes-support/postgresql/postgresql.inc +++ b/meta-oe/recipes-support/postgresql/postgresql.inc | |||
@@ -33,6 +33,7 @@ SRC_URI = "http://ftp.postgresql.org/pub/source/v${PV}/${BP}.tar.bz2 \ | |||
33 | file://0001-Use-pkg-config-for-libxml2-detection.patch \ | 33 | file://0001-Use-pkg-config-for-libxml2-detection.patch \ |
34 | file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \ | 34 | file://0002-Predict-integer-overflow-to-avoid-buffer-overruns.patch \ |
35 | file://0003-Shore-up-ADMIN-OPTION-restrictions.patch \ | 35 | file://0003-Shore-up-ADMIN-OPTION-restrictions.patch \ |
36 | file://0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch \ | ||
36 | " | 37 | " |
37 | 38 | ||
38 | LEAD_SONAME = "libpq.so" | 39 | LEAD_SONAME = "libpq.so" |