From 02f16014c3458e549719aaaaf4bb6c338e55b6e2 Mon Sep 17 00:00:00 2001 From: Greg Stark Date: Thu, 16 Jun 2022 01:40:49 -0400 Subject: [PATCH 2/2] Instead of checks actually force search_path on immutable and security definer functions --- src/backend/commands/functioncmds.c | 79 ++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 9347ed70e2..20da751202 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -41,6 +41,7 @@ #include "catalog/indexing.h" #include "catalog/objectaccess.h" #include "catalog/pg_aggregate.h" +#include "catalog/pg_authid.h" #include "catalog/pg_cast.h" #include "catalog/pg_language.h" #include "catalog/pg_namespace.h" @@ -683,9 +684,83 @@ update_proconfig_value(ArrayType *a, List *set_items) * https://www.postgresql.org/docs/current/sql-createfunction.html#SQL-CREATEFUNCTION-SECURITY */ -/* XXX This logic should perhaps be moved to namespace.c XXX */ +/* XXX Some or all of this logic should perhaps be moved to namespace.c XXX */ #include "utils/varlena.h" +static ArrayType * +fixup_proconfig_value(ArrayType *a, char provolatile, bool prosecdef) { + char *search_path = NULL; + + List *namelist; + ListCell *l; + StringInfoData string; + + if (provolatile != PROVOLATILE_IMMUTABLE && !prosecdef) { + return a; + } + if (a != NULL) { + search_path = GUCArrayLookup(a, "search_path"); + } + if (!search_path) { + search_path = pstrdup(namespace_search_path); + } + + /* Parse string into list of identifiers + * GUCArrayLookup returns a pstrdup'd string so this is safe + */ + if (!SplitIdentifierString(search_path, ',', &namelist)) + { + /* syntax error in name list */ + elog(ERROR, "invalid list syntax in search_path setting on function"); + } + + initStringInfo(&string); + appendStringInfoString(&string, "pg_catalog"); + foreach(l, namelist) + { + char *curname = (char *) lfirst(l); + + if (strcmp(curname, "pg_catalog") == 0) + { + if (foreach_current_index(l) != 0) + elog(WARNING, "moving pg_catalog to first position in search_path for IMMUTABLE or SECURITY DEFINER function"); + continue; + } + if (strcmp(curname, "pg_temp") == 0) + { + if (foreach_current_index(l) != namelist->length-1) + elog(WARNING, "moving pg_temp to last position in search_path for IMMUTABLE or SECURITY DEFINER function"); + continue; + } + if (strcmp(curname, "$user") == 0) + { + /* $user --- substitute namespace matching user name, if any */ + HeapTuple tuple; + + tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId())); + if (HeapTupleIsValid(tuple)) + { + curname = NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname); + ReleaseSysCache(tuple); + /*elog(WARNING, "IMMUTABLE or SECURITY DEFINER functions should not have a search path including $user");*/ + } else { + /* No great options here */ + ReleaseSysCache(tuple); + elog(WARNING, "removing invalid $user from search_path on IMMUTABLE or SECURITY DEFINER function"); + continue; + } + } + appendStringInfoChar(&string, ','); + appendStringInfoString(&string, quote_identifier(curname)); + } + appendStringInfoChar(&string, ','); + appendStringInfoString(&string, "pg_temp"); + + a = GUCArrayAdd(a, "search_path", string.data); + return a; +} + + static void verify_proconfig_value(ArrayType *a, char provolatile, bool prosecdef) { char *proconfig_search_path = NULL; @@ -1233,6 +1308,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) } } + proconfig = fixup_proconfig_value(proconfig, volatility, security); verify_proconfig_value(proconfig, volatility, security); /* @@ -1564,6 +1640,7 @@ AlterFunction(ParseState *pstate, AlterFunctionStmt *stmt) /* update according to each SET or RESET item, left to right */ a = update_proconfig_value(a, set_items); + a = fixup_proconfig_value(a, procForm->provolatile, procForm->prosecdef); verify_proconfig_value(a, procForm->provolatile, procForm->prosecdef); /* update the tuple */ -- 2.36.1