summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta-oe/recipes-support/postgresql/files/0004-Prevent-privilege-escalation-in-explicit-calls-to-PL.patch267
-rw-r--r--meta-oe/recipes-support/postgresql/postgresql.inc1
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 @@
1From 1d701d28a796ea2d1a4d2be9e9ee06209eaea040 Mon Sep 17 00:00:00 2001
2From: Noah Misch <noah@leadboat.com>
3Date: Mon, 17 Feb 2014 09:33:31 -0500
4Subject: [PATCH] Prevent privilege escalation in explicit calls to PL
5 validators.
6
7commit 1d701d28a796ea2d1a4d2be9e9ee06209eaea040 REL9_2_STABLE
8
9The primary role of PL validators is to be called implicitly during
10CREATE FUNCTION, but they are also normal functions that a user can call
11explicitly. Add a permissions check to each validator to ensure that a
12user cannot use explicit validator calls to achieve things he could not
13otherwise achieve. Back-patch to 8.4 (all supported versions).
14Non-core procedural language extensions ought to make the same two-line
15change to their own validators.
16
17Andres Freund, reviewed by Tom Lane and Noah Misch.
18
19Security: CVE-2014-0061
20
21Upstream-Status: Backport
22Signed-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
34diff --git a/doc/src/sgml/plhandler.sgml b/doc/src/sgml/plhandler.sgml
35index 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,
50diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
51index 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);
84diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
85index 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 *
96diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c
97index 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+}
195diff --git a/src/include/fmgr.h b/src/include/fmgr.h
196index 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
207diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
208index 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
229diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
230index 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))
243diff --git a/src/pl/plpython/plpy_main.c b/src/pl/plpython/plpy_main.c
244index 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--
2661.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
38LEAD_SONAME = "libpq.so" 39LEAD_SONAME = "libpq.so"