🌐 AI搜索 & 代理 主页
Skip to content

Commit 8a2530e

Browse files
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
1 parent d6f0c0d commit 8a2530e

File tree

3 files changed

+35
-0
lines changed

3 files changed

+35
-0
lines changed

src/backend/commands/statscmds.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "utils/builtins.h"
3434
#include "utils/fmgroids.h"
3535
#include "utils/inval.h"
36+
#include "utils/lsyscache.h"
3637
#include "utils/memutils.h"
3738
#include "utils/rel.h"
3839
#include "utils/syscache.h"
@@ -89,6 +90,7 @@ CreateStatistics(CreateStatsStmt *stmt)
8990
bool requested_type = false;
9091
int i;
9192
ListCell *cell;
93+
AclResult aclresult;
9294

9395
Assert(IsA(stmt, CreateStatsStmt));
9496

@@ -167,6 +169,12 @@ CreateStatistics(CreateStatsStmt *stmt)
167169
}
168170
namestrcpy(&stxname, namestr);
169171

172+
/* Check we have creation rights in target namespace. */
173+
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
174+
if (aclresult != ACLCHECK_OK)
175+
aclcheck_error(aclresult, OBJECT_SCHEMA,
176+
get_namespace_name(namespaceId));
177+
170178
/*
171179
* Deal with the possibility that the statistics object already exists.
172180
*/

src/test/regress/expected/stats_ext.out

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1745,6 +1745,18 @@ SELECT * FROM tststats.priv_test_parent_tbl t
17451745
(0 rows)
17461746

17471747
DELETE FROM tststats.priv_test_parent_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak
1748+
-- CREATE STATISTICS checks for CREATE on the schema
1749+
RESET SESSION AUTHORIZATION;
1750+
CREATE SCHEMA sts_sch1 CREATE TABLE sts_sch1.tbl (a INT, b INT);
1751+
GRANT USAGE ON SCHEMA sts_sch1 TO regress_stats_user1;
1752+
ALTER TABLE sts_sch1.tbl OWNER TO regress_stats_user1;
1753+
SET SESSION AUTHORIZATION regress_stats_user1;
1754+
CREATE STATISTICS sts_sch1.fail ON a, b FROM sts_sch1.tbl;
1755+
ERROR: permission denied for schema sts_sch1
1756+
RESET SESSION AUTHORIZATION;
1757+
GRANT CREATE ON SCHEMA sts_sch1 TO regress_stats_user1;
1758+
SET SESSION AUTHORIZATION regress_stats_user1;
1759+
CREATE STATISTICS sts_sch1.pass ON a, b FROM sts_sch1.tbl;
17481760
-- Tidy up
17491761
DROP OPERATOR <<< (int, int);
17501762
DROP FUNCTION op_leak(int, int);
@@ -1756,4 +1768,6 @@ NOTICE: drop cascades to 3 other objects
17561768
DETAIL: drop cascades to table tststats.priv_test_parent_tbl
17571769
drop cascades to table tststats.priv_test_tbl
17581770
drop cascades to view tststats.priv_test_view
1771+
DROP SCHEMA sts_sch1 CASCADE;
1772+
NOTICE: drop cascades to table sts_sch1.tbl
17591773
DROP USER regress_stats_user1;

src/test/regress/sql/stats_ext.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,11 +963,24 @@ SELECT * FROM tststats.priv_test_parent_tbl t
963963
WHERE a <<< 0 AND (b <<< 0 OR t.* <<< (1, 1) IS NOT NULL); -- Should not leak
964964
DELETE FROM tststats.priv_test_parent_tbl WHERE a <<< 0 AND b <<< 0; -- Should not leak
965965

966+
-- CREATE STATISTICS checks for CREATE on the schema
967+
RESET SESSION AUTHORIZATION;
968+
CREATE SCHEMA sts_sch1 CREATE TABLE sts_sch1.tbl (a INT, b INT);
969+
GRANT USAGE ON SCHEMA sts_sch1 TO regress_stats_user1;
970+
ALTER TABLE sts_sch1.tbl OWNER TO regress_stats_user1;
971+
SET SESSION AUTHORIZATION regress_stats_user1;
972+
CREATE STATISTICS sts_sch1.fail ON a, b FROM sts_sch1.tbl;
973+
RESET SESSION AUTHORIZATION;
974+
GRANT CREATE ON SCHEMA sts_sch1 TO regress_stats_user1;
975+
SET SESSION AUTHORIZATION regress_stats_user1;
976+
CREATE STATISTICS sts_sch1.pass ON a, b FROM sts_sch1.tbl;
977+
966978
-- Tidy up
967979
DROP OPERATOR <<< (int, int);
968980
DROP FUNCTION op_leak(int, int);
969981
DROP OPERATOR <<< (record, record);
970982
DROP FUNCTION op_leak(record, record);
971983
RESET SESSION AUTHORIZATION;
972984
DROP SCHEMA tststats CASCADE;
985+
DROP SCHEMA sts_sch1 CASCADE;
973986
DROP USER regress_stats_user1;

0 commit comments

Comments
 (0)