mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
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.
This commit is contained in:
@ -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);
|
||||
|
Reference in New Issue
Block a user