aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/functioncmds.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2012-02-13 22:20:27 -0500
committerRobert Haas <rhaas@postgresql.org>2012-02-13 22:21:14 -0500
commitcd30728fb2ed7c367d545fc14ab850b5fa2a4850 (patch)
treec5d487f3abf9e5c66734db8ecb100f4442763822 /src/backend/commands/functioncmds.c
parent2bbd88f8f841b01efb073972b60d4dc1ff1f6fd0 (diff)
downloadpostgresql-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.c40
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);