diff options
Diffstat (limited to 'src/backend/catalog')
-rw-r--r-- | src/backend/catalog/Makefile | 3 | ||||
-rw-r--r-- | src/backend/catalog/dependency.c | 13 | ||||
-rw-r--r-- | src/backend/catalog/fix-CVE-2024-4317.sql | 117 | ||||
-rw-r--r-- | src/backend/catalog/heap.c | 3 | ||||
-rw-r--r-- | src/backend/catalog/pg_proc.c | 7 | ||||
-rw-r--r-- | src/backend/catalog/system_views.sql | 11 |
6 files changed, 142 insertions, 12 deletions
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 89a0221..7304e2b 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -130,13 +130,14 @@ install-data: bki-stamp installdirs $(INSTALL_DATA) $(srcdir)/system_views.sql '$(DESTDIR)$(datadir)/system_views.sql' $(INSTALL_DATA) $(srcdir)/information_schema.sql '$(DESTDIR)$(datadir)/information_schema.sql' $(INSTALL_DATA) $(srcdir)/sql_features.txt '$(DESTDIR)$(datadir)/sql_features.txt' + $(INSTALL_DATA) $(srcdir)/fix-CVE-2024-4317.sql '$(DESTDIR)$(datadir)/fix-CVE-2024-4317.sql' installdirs: $(MKDIR_P) '$(DESTDIR)$(datadir)' .PHONY: uninstall-data uninstall-data: - rm -f $(addprefix '$(DESTDIR)$(datadir)'/, postgres.bki system_constraints.sql system_functions.sql system_views.sql information_schema.sql sql_features.txt) + rm -f $(addprefix '$(DESTDIR)$(datadir)'/, postgres.bki system_constraints.sql system_functions.sql system_views.sql information_schema.sql sql_features.txt fix-CVE-2024-4317.sql) # postgres.bki, system_constraints.sql, and the generated headers are # in the distribution tarball, so they are not cleaned here. diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 85e2a90..3cca107 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -75,6 +75,7 @@ #include "commands/trigger.h" #include "commands/typecmds.h" #include "funcapi.h" +#include "miscadmin.h" #include "nodes/nodeFuncs.h" #include "parser/parsetree.h" #include "rewrite/rewriteRemove.h" @@ -517,6 +518,12 @@ findDependentObjects(const ObjectAddress *object, return; /* + * since this function recurses, it could be driven to stack overflow, + * because of the deep dependency tree, not only due to dependency loops. + */ + check_stack_depth(); + + /* * It's also possible that the target object has already been completely * processed and put into targetObjects. If so, again we just add the * specified objflags to its entry and return. @@ -2378,7 +2385,11 @@ process_function_rte_ref(RangeTblEntry *rte, AttrNumber attnum, { TupleDesc tupdesc; - tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr, true); + /* If it has a coldeflist, it certainly returns RECORD */ + if (rtfunc->funccolnames != NIL) + tupdesc = NULL; /* no need to work hard */ + else + tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr, true); if (tupdesc && tupdesc->tdtypeid != RECORDOID) { /* diff --git a/src/backend/catalog/fix-CVE-2024-4317.sql b/src/backend/catalog/fix-CVE-2024-4317.sql new file mode 100644 index 0000000..b24eba9 --- /dev/null +++ b/src/backend/catalog/fix-CVE-2024-4317.sql @@ -0,0 +1,117 @@ +/* + * fix-CVE-2024-4317.sql + * + * Copyright (c) 2024, PostgreSQL Global Development Group + * + * src/backend/catalog/fix-CVE-2024-4317.sql + * + * This file should be run in every database in the cluster to address + * CVE-2024-4317. + */ + +SET search_path = pg_catalog; + +CREATE OR REPLACE VIEW pg_stats_ext WITH (security_barrier) AS + SELECT cn.nspname AS schemaname, + c.relname AS tablename, + sn.nspname AS statistics_schemaname, + s.stxname AS statistics_name, + pg_get_userbyid(s.stxowner) AS statistics_owner, + ( SELECT array_agg(a.attname ORDER BY a.attnum) + FROM unnest(s.stxkeys) k + JOIN pg_attribute a + ON (a.attrelid = s.stxrelid AND a.attnum = k) + ) AS attnames, + pg_get_statisticsobjdef_expressions(s.oid) as exprs, + s.stxkind AS kinds, + sd.stxdinherit AS inherited, + sd.stxdndistinct AS n_distinct, + sd.stxddependencies AS dependencies, + m.most_common_vals, + m.most_common_val_nulls, + m.most_common_freqs, + m.most_common_base_freqs + FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid) + JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid) + LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace) + LEFT JOIN pg_namespace sn ON (sn.oid = s.stxnamespace) + LEFT JOIN LATERAL + ( SELECT array_agg(values) AS most_common_vals, + array_agg(nulls) AS most_common_val_nulls, + array_agg(frequency) AS most_common_freqs, + array_agg(base_frequency) AS most_common_base_freqs + FROM pg_mcv_list_items(sd.stxdmcv) + ) m ON sd.stxdmcv IS NOT NULL + WHERE pg_has_role(c.relowner, 'USAGE') + AND (c.relrowsecurity = false OR NOT row_security_active(c.oid)); + +CREATE OR REPLACE VIEW pg_stats_ext_exprs WITH (security_barrier) AS + SELECT cn.nspname AS schemaname, + c.relname AS tablename, + sn.nspname AS statistics_schemaname, + s.stxname AS statistics_name, + pg_get_userbyid(s.stxowner) AS statistics_owner, + stat.expr, + sd.stxdinherit AS inherited, + (stat.a).stanullfrac AS null_frac, + (stat.a).stawidth AS avg_width, + (stat.a).stadistinct AS n_distinct, + (CASE + WHEN (stat.a).stakind1 = 1 THEN (stat.a).stavalues1 + WHEN (stat.a).stakind2 = 1 THEN (stat.a).stavalues2 + WHEN (stat.a).stakind3 = 1 THEN (stat.a).stavalues3 + WHEN (stat.a).stakind4 = 1 THEN (stat.a).stavalues4 + WHEN (stat.a).stakind5 = 1 THEN (stat.a).stavalues5 + END) AS most_common_vals, + (CASE + WHEN (stat.a).stakind1 = 1 THEN (stat.a).stanumbers1 + WHEN (stat.a).stakind2 = 1 THEN (stat.a).stanumbers2 + WHEN (stat.a).stakind3 = 1 THEN (stat.a).stanumbers3 + WHEN (stat.a).stakind4 = 1 THEN (stat.a).stanumbers4 + WHEN (stat.a).stakind5 = 1 THEN (stat.a).stanumbers5 + END) AS most_common_freqs, + (CASE + WHEN (stat.a).stakind1 = 2 THEN (stat.a).stavalues1 + WHEN (stat.a).stakind2 = 2 THEN (stat.a).stavalues2 + WHEN (stat.a).stakind3 = 2 THEN (stat.a).stavalues3 + WHEN (stat.a).stakind4 = 2 THEN (stat.a).stavalues4 + WHEN (stat.a).stakind5 = 2 THEN (stat.a).stavalues5 + END) AS histogram_bounds, + (CASE + WHEN (stat.a).stakind1 = 3 THEN (stat.a).stanumbers1[1] + WHEN (stat.a).stakind2 = 3 THEN (stat.a).stanumbers2[1] + WHEN (stat.a).stakind3 = 3 THEN (stat.a).stanumbers3[1] + WHEN (stat.a).stakind4 = 3 THEN (stat.a).stanumbers4[1] + WHEN (stat.a).stakind5 = 3 THEN (stat.a).stanumbers5[1] + END) correlation, + (CASE + WHEN (stat.a).stakind1 = 4 THEN (stat.a).stavalues1 + WHEN (stat.a).stakind2 = 4 THEN (stat.a).stavalues2 + WHEN (stat.a).stakind3 = 4 THEN (stat.a).stavalues3 + WHEN (stat.a).stakind4 = 4 THEN (stat.a).stavalues4 + WHEN (stat.a).stakind5 = 4 THEN (stat.a).stavalues5 + END) AS most_common_elems, + (CASE + WHEN (stat.a).stakind1 = 4 THEN (stat.a).stanumbers1 + WHEN (stat.a).stakind2 = 4 THEN (stat.a).stanumbers2 + WHEN (stat.a).stakind3 = 4 THEN (stat.a).stanumbers3 + WHEN (stat.a).stakind4 = 4 THEN (stat.a).stanumbers4 + WHEN (stat.a).stakind5 = 4 THEN (stat.a).stanumbers5 + END) AS most_common_elem_freqs, + (CASE + WHEN (stat.a).stakind1 = 5 THEN (stat.a).stanumbers1 + WHEN (stat.a).stakind2 = 5 THEN (stat.a).stanumbers2 + WHEN (stat.a).stakind3 = 5 THEN (stat.a).stanumbers3 + WHEN (stat.a).stakind4 = 5 THEN (stat.a).stanumbers4 + WHEN (stat.a).stakind5 = 5 THEN (stat.a).stanumbers5 + END) AS elem_count_histogram + FROM pg_statistic_ext s JOIN pg_class c ON (c.oid = s.stxrelid) + LEFT JOIN pg_statistic_ext_data sd ON (s.oid = sd.stxoid) + LEFT JOIN pg_namespace cn ON (cn.oid = c.relnamespace) + LEFT JOIN pg_namespace sn ON (sn.oid = s.stxnamespace) + JOIN LATERAL ( + SELECT unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr, + unnest(sd.stxdexpr)::pg_statistic AS a + ) stat ON (stat.expr IS NOT NULL) + WHERE pg_has_role(c.relowner, 'USAGE') + AND (c.relrowsecurity = false OR NOT row_security_active(c.oid)); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index bd6b9c4..9197909 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -552,6 +552,9 @@ CheckAttributeType(const char *attname, char att_typtype = get_typtype(atttypid); Oid att_typelem; + /* since this function recurses, it could be driven to stack overflow */ + check_stack_depth(); + if (att_typtype == TYPTYPE_PSEUDO) { /* diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 7514015..5fd8a38 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -972,9 +972,10 @@ fmgr_sql_validator(PG_FUNCTION_ARGS) (void) get_func_result_type(funcoid, &rettype, &rettupdesc); - (void) check_sql_fn_retval(querytree_list, - rettype, rettupdesc, - false, NULL); + (void) check_sql_fn_retval_ext(querytree_list, + rettype, rettupdesc, + proc->prokind, + false, NULL); } error_context_stack = sqlerrcontext.previous; diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 76e4177..ffa8632 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -284,12 +284,7 @@ CREATE VIEW pg_stats_ext WITH (security_barrier) AS array_agg(base_frequency) AS most_common_base_freqs FROM pg_mcv_list_items(sd.stxdmcv) ) m ON sd.stxdmcv IS NOT NULL - WHERE NOT EXISTS - ( SELECT 1 - FROM unnest(stxkeys) k - JOIN pg_attribute a - ON (a.attrelid = s.stxrelid AND a.attnum = k) - WHERE NOT has_column_privilege(c.oid, a.attnum, 'select') ) + WHERE pg_has_role(c.relowner, 'USAGE') AND (c.relrowsecurity = false OR NOT row_security_active(c.oid)); CREATE VIEW pg_stats_ext_exprs WITH (security_barrier) AS @@ -359,7 +354,9 @@ CREATE VIEW pg_stats_ext_exprs WITH (security_barrier) AS JOIN LATERAL ( SELECT unnest(pg_get_statisticsobjdef_expressions(s.oid)) AS expr, unnest(sd.stxdexpr)::pg_statistic AS a - ) stat ON (stat.expr IS NOT NULL); + ) stat ON (stat.expr IS NOT NULL) + WHERE pg_has_role(c.relowner, 'USAGE') + AND (c.relrowsecurity = false OR NOT row_security_active(c.oid)); -- unprivileged users may read pg_statistic_ext but not pg_statistic_ext_data REVOKE ALL ON pg_statistic_ext_data FROM public; |