Skip to content

Commit 823b9dc

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

File tree

6 files changed

+101
-1
lines changed

6 files changed

+101
-1
lines changed

src/backend/catalog/pg_proc.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,9 @@ fmgr_internal_validator(PG_FUNCTION_ARGS)
623623
Datum tmp;
624624
char *prosrc;
625625

626+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
627+
PG_RETURN_VOID();
628+
626629
/*
627630
* We do not honor check_function_bodies since it's unlikely the function
628631
* name will be found later if it isn't there now.
@@ -672,6 +675,9 @@ fmgr_c_validator(PG_FUNCTION_ARGS)
672675
char *prosrc;
673676
char *probin;
674677

678+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
679+
PG_RETURN_VOID();
680+
675681
/*
676682
* It'd be most consistent to skip the check if !check_function_bodies,
677683
* but the purpose of that switch is to be helpful for pg_dump loading,
@@ -724,6 +730,9 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
724730
bool haspolyarg;
725731
int i;
726732

733+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
734+
PG_RETURN_VOID();
735+
727736
tuple = SearchSysCache(PROCOID,
728737
ObjectIdGetDatum(funcoid),
729738
0, 0, 0);

src/backend/commands/functioncmds.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,6 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
929929
prorows);
930930
}
931931

932-
933932
/*
934933
* RemoveFunction
935934
* Deletes a function.

src/backend/utils/fmgr/fmgr.c

Lines changed: 85 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"
@@ -2428,3 +2429,87 @@ get_call_expr_arg_stable(Node *expr, int argnum)
24282429

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

src/include/fmgr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ extern Oid get_fn_expr_argtype(FmgrInfo *flinfo, int argnum);
518518
extern Oid get_call_expr_argtype(fmNodePtr expr, int argnum);
519519
extern bool get_fn_expr_arg_stable(FmgrInfo *flinfo, int argnum);
520520
extern bool get_call_expr_arg_stable(fmNodePtr expr, int argnum);
521+
extern bool CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid);
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
@@ -1094,6 +1094,9 @@ plperl_validator(PG_FUNCTION_ARGS)
10941094
bool istrigger = false;
10951095
int i;
10961096

1097+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
1098+
PG_RETURN_VOID();
1099+
10971100
/* Get the new function's pg_proc entry */
10981101
tuple = SearchSysCache(PROCOID,
10991102
ObjectIdGetDatum(funcoid),

src/pl/plpgsql/src/pl_handler.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ plpgsql_validator(PG_FUNCTION_ARGS)
136136
bool istrigger = false;
137137
int i;
138138

139+
if (!CheckFunctionValidatorAccess(fcinfo->flinfo->fn_oid, funcoid))
140+
PG_RETURN_VOID();
141+
139142
/* Get the new function's pg_proc entry */
140143
tuple = SearchSysCache(PROCOID,
141144
ObjectIdGetDatum(funcoid),

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy