summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorNathan Bossart <nathan@postgresql.org>2025-11-10 09:00:00 -0600
committerNathan Bossart <nathan@postgresql.org>2025-11-10 09:00:00 -0600
commit5e4fcbe531c668b4112beedde97aac79724074c5 (patch)
treee7730d86b4273314d18202fad67e4524b1ec6324 /src/backend
parent600086f471a3bb57ff4953accf1d3f8d2efe0201 (diff)
Check for CREATE privilege on the schema in CREATE STATISTICS.
This omission allowed table owners to create statistics in any schema, potentially leading to unexpected naming conflicts. For ALTER TABLE commands that require re-creating statistics objects, skip this check in case the user has since lost CREATE on the schema. The addition of a second parameter to CreateStatistics() breaks ABI compatibility, but we are unaware of any impacted third-party code. Reported-by: Jelte Fennema-Nio <postgres@jeltef.nl> Author: Jelte Fennema-Nio <postgres@jeltef.nl> Co-authored-by: Nathan Bossart <nathandbossart@gmail.com> Reviewed-by: Noah Misch <noah@leadboat.com> Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de> Security: CVE-2025-12817 Backpatch-through: 13
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/statscmds.c17
-rw-r--r--src/backend/commands/tablecmds.c2
-rw-r--r--src/backend/tcop/utility.c2
3 files changed, 18 insertions, 3 deletions
diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c
index 27bf67e7c4b..0cf0ea43f19 100644
--- a/src/backend/commands/statscmds.c
+++ b/src/backend/commands/statscmds.c
@@ -60,7 +60,7 @@ compare_int16(const void *a, const void *b)
* CREATE STATISTICS
*/
ObjectAddress
-CreateStatistics(CreateStatsStmt *stmt)
+CreateStatistics(CreateStatsStmt *stmt, bool check_rights)
{
int16 attnums[STATS_MAX_DIMENSIONS];
int nattnums = 0;
@@ -171,6 +171,21 @@ CreateStatistics(CreateStatsStmt *stmt)
namestrcpy(&stxname, namestr);
/*
+ * Check we have creation rights in target namespace. Skip check if
+ * caller doesn't want it.
+ */
+ if (check_rights)
+ {
+ AclResult aclresult;
+
+ aclresult = object_aclcheck(NamespaceRelationId, namespaceId,
+ GetUserId(), ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, OBJECT_SCHEMA,
+ get_namespace_name(namespaceId));
+ }
+
+ /*
* Deal with the possibility that the statistics object already exists.
*/
if (SearchSysCacheExists2(STATEXTNAMENSP,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 3aac459e483..23ebaa3f230 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9682,7 +9682,7 @@ ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
/* The CreateStatsStmt has already been through transformStatsStmt */
Assert(stmt->transformed);
- address = CreateStatistics(stmt);
+ address = CreateStatistics(stmt, !is_rebuild);
return address;
}
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 082967c0a86..d18a3a60a46 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1900,7 +1900,7 @@ ProcessUtilitySlow(ParseState *pstate,
/* Run parse analysis ... */
stmt = transformStatsStmt(relid, stmt, queryString);
- address = CreateStatistics(stmt);
+ address = CreateStatistics(stmt, true);
}
break;