diff options
author | Robert Haas <rhaas@postgresql.org> | 2012-02-13 22:20:27 -0500 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2012-02-13 22:21:14 -0500 |
commit | cd30728fb2ed7c367d545fc14ab850b5fa2a4850 (patch) | |
tree | c5d487f3abf9e5c66734db8ecb100f4442763822 /src/backend/commands/functioncmds.c | |
parent | 2bbd88f8f841b01efb073972b60d4dc1ff1f6fd0 (diff) | |
download | postgresql-cd30728fb2ed7c367d545fc14ab850b5fa2a4850.tar.gz postgresql-cd30728fb2ed7c367d545fc14ab850b5fa2a4850.zip |
Allow LEAKPROOF functions for better performance of security views.
We don't normally allow quals to be pushed down into a view created
with the security_barrier option, but functions without side effects
are an exception: they're OK. This allows much better performance in
common cases, such as when using an equality operator (that might
even be indexable).
There is an outstanding issue here with the CREATE FUNCTION / ALTER
FUNCTION syntax: there's no way to use ALTER FUNCTION to unset the
leakproof flag. But I'm committing this as-is so that it doesn't
have to be rebased again; we can fix up the grammar in a future
commit.
KaiGai Kohei, with some wordsmithing by me.
Diffstat (limited to 'src/backend/commands/functioncmds.c')
-rw-r--r-- | src/backend/commands/functioncmds.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index c692a658340..ce866a20a99 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -446,6 +446,7 @@ compute_common_attribute(DefElem *defel, DefElem **volatility_item, DefElem **strict_item, DefElem **security_item, + DefElem **leakproof_item, List **set_items, DefElem **cost_item, DefElem **rows_item) @@ -471,6 +472,13 @@ compute_common_attribute(DefElem *defel, *security_item = defel; } + else if (strcmp(defel->defname, "leakproof") == 0) + { + if (*leakproof_item) + goto duplicate_error; + + *leakproof_item = defel; + } else if (strcmp(defel->defname, "set") == 0) { *set_items = lappend(*set_items, defel->arg); @@ -564,6 +572,7 @@ compute_attributes_sql_style(List *options, char *volatility_p, bool *strict_p, bool *security_definer, + bool *leakproof_p, ArrayType **proconfig, float4 *procost, float4 *prorows) @@ -575,6 +584,7 @@ compute_attributes_sql_style(List *options, DefElem *volatility_item = NULL; DefElem *strict_item = NULL; DefElem *security_item = NULL; + DefElem *leakproof_item = NULL; List *set_items = NIL; DefElem *cost_item = NULL; DefElem *rows_item = NULL; @@ -611,6 +621,7 @@ compute_attributes_sql_style(List *options, &volatility_item, &strict_item, &security_item, + &leakproof_item, &set_items, &cost_item, &rows_item)) @@ -653,6 +664,8 @@ compute_attributes_sql_style(List *options, *strict_p = intVal(strict_item->arg); if (security_item) *security_definer = intVal(security_item->arg); + if (leakproof_item) + *leakproof_p = intVal(leakproof_item->arg); if (set_items) *proconfig = update_proconfig_value(NULL, set_items); if (cost_item) @@ -805,7 +818,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) Oid requiredResultType; bool isWindowFunc, isStrict, - security; + security, + isLeakProof; char volatility; ArrayType *proconfig; float4 procost; @@ -828,6 +842,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) isWindowFunc = false; isStrict = false; security = false; + isLeakProof = false; volatility = PROVOLATILE_VOLATILE; proconfig = NULL; procost = -1; /* indicates not set */ @@ -837,7 +852,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) compute_attributes_sql_style(stmt->options, &as_clause, &language, &isWindowFunc, &volatility, - &isStrict, &security, + &isStrict, &security, &isLeakProof, &proconfig, &procost, &prorows); /* Look up the language and validate permissions */ @@ -875,6 +890,16 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) ReleaseSysCache(languageTuple); /* + * Only superuser is allowed to create leakproof functions because + * it possibly allows unprivileged users to reference invisible tuples + * to be filtered out using views for row-level security. + */ + if (isLeakProof && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("only superuser can define a leakproof function"))); + + /* * Convert remaining parameters of CREATE to form wanted by * ProcedureCreate. */ @@ -960,6 +985,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) false, /* not an aggregate */ isWindowFunc, security, + isLeakProof, isStrict, volatility, parameterTypes, @@ -1238,6 +1264,7 @@ AlterFunction(AlterFunctionStmt *stmt) DefElem *volatility_item = NULL; DefElem *strict_item = NULL; DefElem *security_def_item = NULL; + DefElem *leakproof_item = NULL; List *set_items = NIL; DefElem *cost_item = NULL; DefElem *rows_item = NULL; @@ -1274,6 +1301,7 @@ AlterFunction(AlterFunctionStmt *stmt) &volatility_item, &strict_item, &security_def_item, + &leakproof_item, &set_items, &cost_item, &rows_item) == false) @@ -1286,6 +1314,14 @@ AlterFunction(AlterFunctionStmt *stmt) procForm->proisstrict = intVal(strict_item->arg); if (security_def_item) procForm->prosecdef = intVal(security_def_item->arg); + if (leakproof_item) + { + if (intVal(leakproof_item->arg) && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("only superuser can define a leakproof function"))); + procForm->proleakproof = intVal(leakproof_item->arg); + } if (cost_item) { procForm->procost = defGetNumeric(cost_item); |