|
24 | 24 | #include "miscadmin.h"
|
25 | 25 | #include "nodes/nodeFuncs.h"
|
26 | 26 | #include "pgstat.h"
|
| 27 | +#include "utils/acl.h" |
27 | 28 | #include "utils/builtins.h"
|
28 | 29 | #include "utils/fmgrtab.h"
|
29 | 30 | #include "utils/guc.h"
|
@@ -2409,3 +2410,86 @@ get_call_expr_arg_stable(Node *expr, int argnum)
|
2409 | 2410 |
|
2410 | 2411 | return false;
|
2411 | 2412 | }
|
| 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(Oid validatorOid, Oid functionOid) |
| 2446 | +{ |
| 2447 | + HeapTuple procTup; |
| 2448 | + HeapTuple langTup; |
| 2449 | + Form_pg_proc procStruct; |
| 2450 | + Form_pg_language langStruct; |
| 2451 | + AclResult aclresult; |
| 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 | +} |
0 commit comments