From cd30728fb2ed7c367d545fc14ab850b5fa2a4850 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 13 Feb 2012 22:20:27 -0500 Subject: 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. --- src/backend/commands/functioncmds.c | 40 +++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'src/backend/commands/functioncmds.c') 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 */ @@ -874,6 +889,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); -- cgit v1.2.3