@@ -80,7 +80,10 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo,
8080 Oid relId ,
8181 const char * accessMethodName , Oid accessMethodId ,
8282 bool amcanorder ,
83- bool isconstraint );
83+ bool isconstraint ,
84+ Oid ddl_userid ,
85+ int ddl_sec_context ,
86+ int * ddl_save_nestlevel );
8487static char * ChooseIndexName (const char * tabname , Oid namespaceId ,
8588 List * colnames , List * exclusionOpNames ,
8689 bool primary , bool isconstraint );
@@ -220,9 +223,8 @@ CheckIndexCompatible(Oid oldId,
220223 * Compute the operator classes, collations, and exclusion operators for
221224 * the new index, so we can test whether it's compatible with the existing
222225 * one. Note that ComputeIndexAttrs might fail here, but that's OK:
223- * DefineIndex would have called this function with the same arguments
224- * later on, and it would have failed then anyway. Our attributeList
225- * contains only key attributes, thus we're filling ii_NumIndexAttrs and
226+ * DefineIndex would have failed later. Our attributeList contains only
227+ * key attributes, thus we're filling ii_NumIndexAttrs and
226228 * ii_NumIndexKeyAttrs with same value.
227229 */
228230 indexInfo = makeIndexInfo (numberOfAttributes , numberOfAttributes ,
@@ -236,7 +238,7 @@ CheckIndexCompatible(Oid oldId,
236238 coloptions , attributeList ,
237239 exclusionOpNames , relationId ,
238240 accessMethodName , accessMethodId ,
239- amcanorder , isconstraint );
241+ amcanorder , isconstraint , InvalidOid , 0 , NULL );
240242
241243
242244 /* Get the soon-obsolete pg_index tuple. */
@@ -482,6 +484,19 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
482484 * DefineIndex
483485 * Creates a new index.
484486 *
487+ * This function manages the current userid according to the needs of pg_dump.
488+ * Recreating old-database catalog entries in new-database is fine, regardless
489+ * of which users would have permission to recreate those entries now. That's
490+ * just preservation of state. Running opaque expressions, like calling a
491+ * function named in a catalog entry or evaluating a pg_node_tree in a catalog
492+ * entry, as anyone other than the object owner, is not fine. To adhere to
493+ * those principles and to remain fail-safe, use the table owner userid for
494+ * most ACL checks. Use the original userid for ACL checks reached without
495+ * traversing opaque expressions. (pg_dump can predict such ACL checks from
496+ * catalogs.) Overall, this is a mess. Future DDL development should
497+ * consider offering one DDL command for catalog setup and a separate DDL
498+ * command for steps that run opaque expressions.
499+ *
485500 * 'relationId': the OID of the heap relation on which the index is to be
486501 * created
487502 * 'stmt': IndexStmt describing the properties of the new index.
@@ -890,7 +905,8 @@ DefineIndex(Oid relationId,
890905 coloptions , allIndexParams ,
891906 stmt -> excludeOpNames , relationId ,
892907 accessMethodName , accessMethodId ,
893- amcanorder , stmt -> isconstraint );
908+ amcanorder , stmt -> isconstraint , root_save_userid ,
909+ root_save_sec_context , & root_save_nestlevel );
894910
895911 /*
896912 * Extra checks when creating a PRIMARY KEY index.
@@ -1170,11 +1186,8 @@ DefineIndex(Oid relationId,
11701186
11711187 /*
11721188 * Roll back any GUC changes executed by index functions, and keep
1173- * subsequent changes local to this command. It's barely possible that
1174- * some index function changed a behavior-affecting GUC, e.g. xmloption,
1175- * that affects subsequent steps. This improves bug-compatibility with
1176- * older PostgreSQL versions. They did the AtEOXact_GUC() here for the
1177- * purpose of clearing the above default_tablespace change.
1189+ * subsequent changes local to this command. This is essential if some
1190+ * index function changed a behavior-affecting GUC, e.g. search_path.
11781191 */
11791192 AtEOXact_GUC (false, root_save_nestlevel );
11801193 root_save_nestlevel = NewGUCNestLevel ();
@@ -1730,6 +1743,10 @@ CheckPredicate(Expr *predicate)
17301743 * Compute per-index-column information, including indexed column numbers
17311744 * or index expressions, opclasses and their options. Note, all output vectors
17321745 * should be allocated for all columns, including "including" ones.
1746+ *
1747+ * If the caller switched to the table owner, ddl_userid is the role for ACL
1748+ * checks reached without traversing opaque expressions. Otherwise, it's
1749+ * InvalidOid, and other ddl_* arguments are undefined.
17331750 */
17341751static void
17351752ComputeIndexAttrs (IndexInfo * indexInfo ,
@@ -1743,12 +1760,17 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
17431760 const char * accessMethodName ,
17441761 Oid accessMethodId ,
17451762 bool amcanorder ,
1746- bool isconstraint )
1763+ bool isconstraint ,
1764+ Oid ddl_userid ,
1765+ int ddl_sec_context ,
1766+ int * ddl_save_nestlevel )
17471767{
17481768 ListCell * nextExclOp ;
17491769 ListCell * lc ;
17501770 int attn ;
17511771 int nkeycols = indexInfo -> ii_NumIndexKeyAttrs ;
1772+ Oid save_userid ;
1773+ int save_sec_context ;
17521774
17531775 /* Allocate space for exclusion operator info, if needed */
17541776 if (exclusionOpNames )
@@ -1762,6 +1784,9 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
17621784 else
17631785 nextExclOp = NULL ;
17641786
1787+ if (OidIsValid (ddl_userid ))
1788+ GetUserIdAndSecContext (& save_userid , & save_sec_context );
1789+
17651790 /*
17661791 * process attributeList
17671792 */
@@ -1892,10 +1917,24 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
18921917 }
18931918
18941919 /*
1895- * Apply collation override if any
1920+ * Apply collation override if any. Use of ddl_userid is necessary
1921+ * due to ACL checks therein, and it's safe because collations don't
1922+ * contain opaque expressions (or non-opaque expressions).
18961923 */
18971924 if (attribute -> collation )
1925+ {
1926+ if (OidIsValid (ddl_userid ))
1927+ {
1928+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1929+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1930+ }
18981931 attcollation = get_collation_oid (attribute -> collation , false);
1932+ if (OidIsValid (ddl_userid ))
1933+ {
1934+ SetUserIdAndSecContext (save_userid , save_sec_context );
1935+ * ddl_save_nestlevel = NewGUCNestLevel ();
1936+ }
1937+ }
18991938
19001939 /*
19011940 * Check we have a collation iff it's a collatable type. The only
@@ -1923,12 +1962,25 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
19231962 collationOidP [attn ] = attcollation ;
19241963
19251964 /*
1926- * Identify the opclass to use.
1965+ * Identify the opclass to use. Use of ddl_userid is necessary due to
1966+ * ACL checks therein. This is safe despite opclasses containing
1967+ * opaque expressions (specifically, functions), because only
1968+ * superusers can define opclasses.
19271969 */
1970+ if (OidIsValid (ddl_userid ))
1971+ {
1972+ AtEOXact_GUC (false, * ddl_save_nestlevel );
1973+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
1974+ }
19281975 classOidP [attn ] = ResolveOpClass (attribute -> opclass ,
19291976 atttype ,
19301977 accessMethodName ,
19311978 accessMethodId );
1979+ if (OidIsValid (ddl_userid ))
1980+ {
1981+ SetUserIdAndSecContext (save_userid , save_sec_context );
1982+ * ddl_save_nestlevel = NewGUCNestLevel ();
1983+ }
19321984
19331985 /*
19341986 * Identify the exclusion operator, if any.
@@ -1942,9 +1994,23 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
19421994
19431995 /*
19441996 * Find the operator --- it must accept the column datatype
1945- * without runtime coercion (but binary compatibility is OK)
1997+ * without runtime coercion (but binary compatibility is OK).
1998+ * Operators contain opaque expressions (specifically, functions).
1999+ * compatible_oper_opid() boils down to oper() and
2000+ * IsBinaryCoercible(). PostgreSQL would have security problems
2001+ * elsewhere if oper() started calling opaque expressions.
19462002 */
2003+ if (OidIsValid (ddl_userid ))
2004+ {
2005+ AtEOXact_GUC (false, * ddl_save_nestlevel );
2006+ SetUserIdAndSecContext (ddl_userid , ddl_sec_context );
2007+ }
19472008 opid = compatible_oper_opid (opname , atttype , atttype , false);
2009+ if (OidIsValid (ddl_userid ))
2010+ {
2011+ SetUserIdAndSecContext (save_userid , save_sec_context );
2012+ * ddl_save_nestlevel = NewGUCNestLevel ();
2013+ }
19482014
19492015 /*
19502016 * Only allow commutative operators to be used in exclusion
0 commit comments