|
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"
|
@@ -2428,3 +2429,87 @@ get_call_expr_arg_stable(Node *expr, int argnum)
|
2428 | 2429 |
|
2429 | 2430 | return false;
|
2430 | 2431 | }
|
| 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 | +} |
0 commit comments