Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite2fb3df

Browse files
Check for CREATE privilege on the schema in CREATE STATISTICS.
This omission allowed table owners to create statistics in anyschema, potentially leading to unexpected naming conflicts. ForALTER TABLE commands that require re-creating statistics objects,skip this check in case the user has since lost CREATE on theschema. The addition of a second parameter to CreateStatistics()breaks ABI compatibility, but we are unaware of any impactedthird-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-12817Backpatch-through: 13
1 parentf5999f0 commite2fb3df

File tree

6 files changed

+90
-4
lines changed

6 files changed

+90
-4
lines changed

‎src/backend/commands/statscmds.c‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ compare_int16(const void *a, const void *b)
5959
*CREATE STATISTICS
6060
*/
6161
ObjectAddress
62-
CreateStatistics(CreateStatsStmt*stmt)
62+
CreateStatistics(CreateStatsStmt*stmt,boolcheck_rights)
6363
{
6464
int16attnums[STATS_MAX_DIMENSIONS];
6565
intnattnums=0;
@@ -169,6 +169,21 @@ CreateStatistics(CreateStatsStmt *stmt)
169169
}
170170
namestrcpy(&stxname,namestr);
171171

172+
/*
173+
* Check we have creation rights in target namespace. Skip check if
174+
* caller doesn't want it.
175+
*/
176+
if (check_rights)
177+
{
178+
AclResultaclresult;
179+
180+
aclresult=object_aclcheck(NamespaceRelationId,namespaceId,
181+
GetUserId(),ACL_CREATE);
182+
if (aclresult!=ACLCHECK_OK)
183+
aclcheck_error(aclresult,OBJECT_SCHEMA,
184+
get_namespace_name(namespaceId));
185+
}
186+
172187
/*
173188
* Deal with the possibility that the statistics object already exists.
174189
*/

‎src/backend/commands/tablecmds.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9249,7 +9249,7 @@ ATExecAddStatistics(AlteredTableInfo *tab, Relation rel,
92499249
/* The CreateStatsStmt has already been through transformStatsStmt */
92509250
Assert(stmt->transformed);
92519251

9252-
address = CreateStatistics(stmt);
9252+
address = CreateStatistics(stmt, !is_rebuild);
92539253

92549254
return address;
92559255
}

‎src/backend/tcop/utility.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1898,7 +1898,7 @@ ProcessUtilitySlow(ParseState *pstate,
18981898
/* Run parse analysis ... */
18991899
stmt=transformStatsStmt(relid,stmt,queryString);
19001900

1901-
address=CreateStatistics(stmt);
1901+
address=CreateStatistics(stmt, true);
19021902
}
19031903
break;
19041904

‎src/include/commands/defrem.h‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ extern void RemoveOperatorById(Oid operOid);
8181
externObjectAddressAlterOperator(AlterOperatorStmt*stmt);
8282

8383
/* commands/statscmds.c */
84-
externObjectAddressCreateStatistics(CreateStatsStmt*stmt);
84+
externObjectAddressCreateStatistics(CreateStatsStmt*stmt,boolcheck_rights);
8585
externObjectAddressAlterStatistics(AlterStatsStmt*stmt);
8686
externvoidRemoveStatisticsById(OidstatsOid);
8787
externvoidRemoveStatisticsDataById(OidstatsOid,boolinh);

‎src/test/regress/expected/stats_ext.out‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3409,6 +3409,41 @@ SELECT statistics_name, most_common_vals FROM pg_stats_ext_exprs x
34093409
s_expr | {1}
34103410
(2 rows)
34113411

3412+
-- CREATE STATISTICS checks for CREATE on the schema
3413+
RESET SESSION AUTHORIZATION;
3414+
CREATE SCHEMA sts_sch1 CREATE TABLE sts_sch1.tbl (a INT, b INT, c INT GENERATED ALWAYS AS (b * 2) STORED);
3415+
CREATE SCHEMA sts_sch2;
3416+
GRANT USAGE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1;
3417+
ALTER TABLE sts_sch1.tbl OWNER TO regress_stats_user1;
3418+
SET SESSION AUTHORIZATION regress_stats_user1;
3419+
CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
3420+
ERROR: permission denied for schema sts_sch1
3421+
CREATE STATISTICS sts_sch2.fail ON a, b, c FROM sts_sch1.tbl;
3422+
ERROR: permission denied for schema sts_sch2
3423+
RESET SESSION AUTHORIZATION;
3424+
GRANT CREATE ON SCHEMA sts_sch1 TO regress_stats_user1;
3425+
SET SESSION AUTHORIZATION regress_stats_user1;
3426+
CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
3427+
CREATE STATISTICS sts_sch2.fail ON a, b, c FROM sts_sch1.tbl;
3428+
ERROR: permission denied for schema sts_sch2
3429+
RESET SESSION AUTHORIZATION;
3430+
REVOKE CREATE ON SCHEMA sts_sch1 FROM regress_stats_user1;
3431+
GRANT CREATE ON SCHEMA sts_sch2 TO regress_stats_user1;
3432+
SET SESSION AUTHORIZATION regress_stats_user1;
3433+
CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
3434+
ERROR: permission denied for schema sts_sch1
3435+
CREATE STATISTICS sts_sch2.pass1 ON a, b, c FROM sts_sch1.tbl;
3436+
RESET SESSION AUTHORIZATION;
3437+
GRANT CREATE ON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1;
3438+
SET SESSION AUTHORIZATION regress_stats_user1;
3439+
CREATE STATISTICS ON a, b, c FROM sts_sch1.tbl;
3440+
CREATE STATISTICS sts_sch2.pass2 ON a, b, c FROM sts_sch1.tbl;
3441+
-- re-creating statistics via ALTER TABLE bypasses checks for CREATE on schema
3442+
RESET SESSION AUTHORIZATION;
3443+
REVOKE CREATE ON SCHEMA sts_sch1, sts_sch2 FROM regress_stats_user1;
3444+
SET SESSION AUTHORIZATION regress_stats_user1;
3445+
ALTER TABLE sts_sch1.tbl ALTER COLUMN a TYPE SMALLINT;
3446+
ALTER TABLE sts_sch1.tbl ALTER COLUMN c SET EXPRESSION AS (a * 3);
34123447
-- Tidy up
34133448
DROP OPERATOR <<< (int, int);
34143449
DROP FUNCTION op_leak(int, int);
@@ -3421,4 +3456,6 @@ NOTICE: drop cascades to 3 other objects
34213456
DETAIL: drop cascades to table tststats.priv_test_parent_tbl
34223457
drop cascades to table tststats.priv_test_tbl
34233458
drop cascades to view tststats.priv_test_view
3459+
DROP SCHEMA sts_sch1, sts_sch2 CASCADE;
3460+
NOTICE: drop cascades to table sts_sch1.tbl
34243461
DROP USER regress_stats_user1;

‎src/test/regress/sql/stats_ext.sql‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,39 @@ SELECT statistics_name, most_common_vals FROM pg_stats_ext x
17401740
SELECT statistics_name, most_common_valsFROM pg_stats_ext_exprs x
17411741
WHERE tablename='stats_ext_tbl'ORDER BY ROW(x.*);
17421742

1743+
-- CREATE STATISTICS checks for CREATE on the schema
1744+
RESET SESSION AUTHORIZATION;
1745+
CREATESCHEMAsts_sch1 CREATE TABLEsts_sch1.tbl (aINT, bINT, cINT GENERATED ALWAYSAS (b*2) STORED);
1746+
CREATESCHEMAsts_sch2;
1747+
GRANT USAGEON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1;
1748+
ALTERTABLEsts_sch1.tbl OWNER TO regress_stats_user1;
1749+
SET SESSION AUTHORIZATION regress_stats_user1;
1750+
CREATE STATISTICSON a, b, cFROMsts_sch1.tbl;
1751+
CREATE STATISTICSsts_sch2.failON a, b, cFROMsts_sch1.tbl;
1752+
RESET SESSION AUTHORIZATION;
1753+
GRANT CREATEON SCHEMA sts_sch1 TO regress_stats_user1;
1754+
SET SESSION AUTHORIZATION regress_stats_user1;
1755+
CREATE STATISTICSON a, b, cFROMsts_sch1.tbl;
1756+
CREATE STATISTICSsts_sch2.failON a, b, cFROMsts_sch1.tbl;
1757+
RESET SESSION AUTHORIZATION;
1758+
REVOKE CREATEON SCHEMA sts_sch1FROM regress_stats_user1;
1759+
GRANT CREATEON SCHEMA sts_sch2 TO regress_stats_user1;
1760+
SET SESSION AUTHORIZATION regress_stats_user1;
1761+
CREATE STATISTICSON a, b, cFROMsts_sch1.tbl;
1762+
CREATE STATISTICSsts_sch2.pass1ON a, b, cFROMsts_sch1.tbl;
1763+
RESET SESSION AUTHORIZATION;
1764+
GRANT CREATEON SCHEMA sts_sch1, sts_sch2 TO regress_stats_user1;
1765+
SET SESSION AUTHORIZATION regress_stats_user1;
1766+
CREATE STATISTICSON a, b, cFROMsts_sch1.tbl;
1767+
CREATE STATISTICSsts_sch2.pass2ON a, b, cFROMsts_sch1.tbl;
1768+
1769+
-- re-creating statistics via ALTER TABLE bypasses checks for CREATE on schema
1770+
RESET SESSION AUTHORIZATION;
1771+
REVOKE CREATEON SCHEMA sts_sch1, sts_sch2FROM regress_stats_user1;
1772+
SET SESSION AUTHORIZATION regress_stats_user1;
1773+
ALTERTABLEsts_sch1.tbl ALTER COLUMN a TYPESMALLINT;
1774+
ALTERTABLEsts_sch1.tbl ALTER COLUMN cSET EXPRESSIONAS (a*3);
1775+
17431776
-- Tidy up
17441777
DROPOPERATOR<<< (int,int);
17451778
DROPFUNCTION op_leak(int,int);
@@ -1748,4 +1781,5 @@ DROP FUNCTION op_leak(record, record);
17481781
RESET SESSION AUTHORIZATION;
17491782
DROPTABLE stats_ext_tbl;
17501783
DROPSCHEMA tststats CASCADE;
1784+
DROPSCHEMA sts_sch1, sts_sch2 CASCADE;
17511785
DROPUSER regress_stats_user1;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp