Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc0ac4c7

Browse files
committed
Prevent privilege escalation in explicit calls to PL validators.
The primary role of PL validators is to be called implicitly duringCREATE FUNCTION, but they are also normal functions that a user can callexplicitly. Add a permissions check to each validator to ensure that auser cannot use explicit validator calls to achieve things he could nototherwise achieve. Back-patch to 8.4 (all supported versions).Non-core procedural language extensions ought to make the same two-linechange to their own validators.Andres Freund, reviewed by Tom Lane and Noah Misch.Security:CVE-2014-0061
1 parent7890636 commitc0ac4c7

File tree

7 files changed

+104
-2
lines changed

7 files changed

+104
-2
lines changed

‎doc/src/sgml/plhandler.sgml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,10 @@ CREATE LANGUAGE plsample
179179
or updated a function written in the procedural language.
180180
The passed-in OID is the OID of the function's <classname>pg_proc</>
181181
row. The validator must fetch this row in the usual way, and do
182-
whatever checking is appropriate. Typical checks include verifying
182+
whatever checking is appropriate.
183+
First, call <function>CheckFunctionValidatorAccess()</> to diagnose
184+
explicit calls to the validator that the user could not achieve through
185+
<command>CREATE FUNCTION</>. Typical checks then include verifying
183186
that the function's argument and result types are supported by the
184187
language, and that the function's body is syntactically correct
185188
in the language. If the validator finds the function to be okay,

‎src/backend/catalog/pg_proc.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
688688
Datumtmp;
689689
char*prosrc;
690690

691+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid,funcoid))
692+
PG_RETURN_VOID();
693+
691694
/*
692695
* We do not honor check_function_bodies since it's unlikely the function
693696
* name will be found later if it isn't there now.
@@ -735,6 +738,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
735738
char*prosrc;
736739
char*probin;
737740

741+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid,funcoid))
742+
PG_RETURN_VOID();
743+
738744
/*
739745
* It'd be most consistent to skip the check if !check_function_bodies,
740746
* but the purpose of that switch is to be helpful for pg_dump loading,
@@ -785,6 +791,9 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
785791
boolhaspolyarg;
786792
inti;
787793

794+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid,funcoid))
795+
PG_RETURN_VOID();
796+
788797
tuple=SearchSysCache1(PROCOID,ObjectIdGetDatum(funcoid));
789798
if (!HeapTupleIsValid(tuple))
790799
elog(ERROR,"cache lookup failed for function %u",funcoid);

‎src/backend/commands/functioncmds.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,6 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
960960
prorows);
961961
}
962962

963-
964963
/*
965964
* RemoveFunction
966965
*Deletes a function.

‎src/backend/utils/fmgr/fmgr.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include"miscadmin.h"
2525
#include"nodes/nodeFuncs.h"
2626
#include"pgstat.h"
27+
#include"utils/acl.h"
2728
#include"utils/builtins.h"
2829
#include"utils/fmgrtab.h"
2930
#include"utils/guc.h"
@@ -2409,3 +2410,86 @@ get_call_expr_arg_stable(Node *expr, int argnum)
24092410

24102411
return false;
24112412
}
2413+
2414+
/*-------------------------------------------------------------------------
2415+
*Support routines for procedural language implementations
2416+
*-------------------------------------------------------------------------
2417+
*/
2418+
2419+
/*
2420+
* Verify that a validator is actually associated with the language of a
2421+
* particular function and that the user has access to both the language and
2422+
* the function. All validators should call this before doing anything
2423+
* substantial. Doing so ensures a user cannot achieve anything with explicit
2424+
* calls to validators that he could not achieve with CREATE FUNCTION or by
2425+
* simply calling an existing function.
2426+
*
2427+
* When this function returns false, callers should skip all validation work
2428+
* and call PG_RETURN_VOID(). This never happens at present; it is reserved
2429+
* for future expansion.
2430+
*
2431+
* In particular, checking that the validator corresponds to the function's
2432+
* language allows untrusted language validators to assume they process only
2433+
* superuser-chosen source code. (Untrusted language call handlers, by
2434+
* definition, do assume that.) A user lacking the USAGE language privilege
2435+
* would be unable to reach the validator through CREATE FUNCTION, so we check
2436+
* that to block explicit calls as well. Checking the EXECUTE privilege on
2437+
* the function is often superfluous, because most users can clone the
2438+
* function to get an executable copy. It is meaningful against users with no
2439+
* database TEMP right and no permanent schema CREATE right, thereby unable to
2440+
* create any function. Also, if the function tracks persistent state by
2441+
* function OID or name, validating the original function might permit more
2442+
* mischief than creating and validating a clone thereof.
2443+
*/
2444+
bool
2445+
CheckFunctionValidatorAccess(OidvalidatorOid,OidfunctionOid)
2446+
{
2447+
HeapTupleprocTup;
2448+
HeapTuplelangTup;
2449+
Form_pg_procprocStruct;
2450+
Form_pg_languagelangStruct;
2451+
AclResultaclresult;
2452+
2453+
/* Get the function's pg_proc entry */
2454+
procTup=SearchSysCache1(PROCOID,ObjectIdGetDatum(functionOid));
2455+
if (!HeapTupleIsValid(procTup))
2456+
elog(ERROR,"cache lookup failed for function %u",functionOid);
2457+
procStruct= (Form_pg_proc)GETSTRUCT(procTup);
2458+
2459+
/*
2460+
* Fetch pg_language entry to know if this is the correct validation
2461+
* function for that pg_proc entry.
2462+
*/
2463+
langTup=SearchSysCache1(LANGOID,ObjectIdGetDatum(procStruct->prolang));
2464+
if (!HeapTupleIsValid(langTup))
2465+
elog(ERROR,"cache lookup failed for language %u",procStruct->prolang);
2466+
langStruct= (Form_pg_language)GETSTRUCT(langTup);
2467+
2468+
if (langStruct->lanvalidator!=validatorOid)
2469+
ereport(ERROR,
2470+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2471+
errmsg("language validation function %u called for language %u instead of %u",
2472+
validatorOid,procStruct->prolang,
2473+
langStruct->lanvalidator)));
2474+
2475+
/* first validate that we have permissions to use the language */
2476+
aclresult=pg_language_aclcheck(procStruct->prolang,GetUserId(),
2477+
ACL_USAGE);
2478+
if (aclresult!=ACLCHECK_OK)
2479+
aclcheck_error(aclresult,ACL_KIND_LANGUAGE,
2480+
NameStr(langStruct->lanname));
2481+
2482+
/*
2483+
* Check whether we are allowed to execute the function itself. If we can
2484+
* execute it, there should be no possible side-effect of
2485+
* compiling/validation that execution can't have.
2486+
*/
2487+
aclresult=pg_proc_aclcheck(functionOid,GetUserId(),ACL_EXECUTE);
2488+
if (aclresult!=ACLCHECK_OK)
2489+
aclcheck_error(aclresult,ACL_KIND_PROC,NameStr(procStruct->proname));
2490+
2491+
ReleaseSysCache(procTup);
2492+
ReleaseSysCache(langTup);
2493+
2494+
return true;
2495+
}

‎src/include/fmgr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ extern Oidget_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
518518
externOidget_call_expr_argtype(fmNodePtrexpr,intargnum);
519519
externboolget_fn_expr_arg_stable(FmgrInfo*flinfo,intargnum);
520520
externboolget_call_expr_arg_stable(fmNodePtrexpr,intargnum);
521+
externboolCheckFunctionValidatorAccess(OidvalidatorOid,OidfunctionOid);
521522

522523
/*
523524
* Routines in dfmgr.c

‎src/pl/plperl/plperl.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,9 @@ plperl_validator(PG_FUNCTION_ARGS)
13951395
boolistrigger= false;
13961396
inti;
13971397

1398+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid,funcoid))
1399+
PG_RETURN_VOID();
1400+
13981401
/* Get the new function's pg_proc entry */
13991402
tuple=SearchSysCache1(PROCOID,ObjectIdGetDatum(funcoid));
14001403
if (!HeapTupleIsValid(tuple))

‎src/pl/plpgsql/src/pl_handler.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ plpgsql_validator(PG_FUNCTION_ARGS)
217217
boolistrigger= false;
218218
inti;
219219

220+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid,funcoid))
221+
PG_RETURN_VOID();
222+
220223
/* Get the new function's pg_proc entry */
221224
tuple=SearchSysCache1(PROCOID,ObjectIdGetDatum(funcoid));
222225
if (!HeapTupleIsValid(tuple))

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp