mirror of
https://github.com/postgres/postgres.git
synced 2025-09-03 15:22:11 +03:00
Make relation-enumerating operations be security-restricted operations.
When a feature enumerates relations and runs functions associated with all found relations, the feature's user shall not need to trust every user having permission to create objects. BRIN-specific functionality in autovacuum neglected to account for this, as did pg_amcheck and CLUSTER. An attacker having permission to create non-temp objects in at least one schema could execute arbitrary SQL functions under the identity of the bootstrap superuser. CREATE INDEX (not a relation-enumerating operation) and REINDEX protected themselves too late. This change extends to the non-enumerating amcheck interface. Back-patch to v10 (all supported versions). Sergey Shinderuk, reviewed (in earlier versions) by Alexander Lakhin. Reported by Alexander Lakhin. Security: CVE-2022-1552
This commit is contained in:
@@ -1472,6 +1472,61 @@ SELECT has_table_privilege('regress_priv_user1', 'atest4', 'SELECT WITH GRANT OP
|
||||
-- security-restricted operations
|
||||
\c -
|
||||
CREATE ROLE regress_sro_user;
|
||||
-- Check that index expressions and predicates are run as the table's owner
|
||||
-- A dummy index function checking current_user
|
||||
CREATE FUNCTION sro_ifun(int) RETURNS int AS $$
|
||||
BEGIN
|
||||
-- Below we set the table's owner to regress_sro_user
|
||||
ASSERT current_user = 'regress_sro_user',
|
||||
format('sro_ifun(%s) called by %s', $1, current_user);
|
||||
RETURN $1;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql IMMUTABLE;
|
||||
-- Create a table owned by regress_sro_user
|
||||
CREATE TABLE sro_tab (a int);
|
||||
ALTER TABLE sro_tab OWNER TO regress_sro_user;
|
||||
INSERT INTO sro_tab VALUES (1), (2), (3);
|
||||
-- Create an expression index with a predicate
|
||||
CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
|
||||
WHERE sro_ifun(a + 10) > sro_ifun(10);
|
||||
DROP INDEX sro_idx;
|
||||
-- Do the same concurrently
|
||||
CREATE INDEX CONCURRENTLY sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
|
||||
WHERE sro_ifun(a + 10) > sro_ifun(10);
|
||||
-- REINDEX
|
||||
REINDEX TABLE sro_tab;
|
||||
REINDEX INDEX sro_idx;
|
||||
REINDEX TABLE CONCURRENTLY sro_tab;
|
||||
DROP INDEX sro_idx;
|
||||
-- CLUSTER
|
||||
CREATE INDEX sro_cluster_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)));
|
||||
CLUSTER sro_tab USING sro_cluster_idx;
|
||||
DROP INDEX sro_cluster_idx;
|
||||
-- BRIN index
|
||||
CREATE INDEX sro_brin ON sro_tab USING brin ((sro_ifun(a) + sro_ifun(0)));
|
||||
SELECT brin_desummarize_range('sro_brin', 0);
|
||||
brin_desummarize_range
|
||||
------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT brin_summarize_range('sro_brin', 0);
|
||||
brin_summarize_range
|
||||
----------------------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
DROP TABLE sro_tab;
|
||||
-- Check with a partitioned table
|
||||
CREATE TABLE sro_ptab (a int) PARTITION BY RANGE (a);
|
||||
ALTER TABLE sro_ptab OWNER TO regress_sro_user;
|
||||
CREATE TABLE sro_part PARTITION OF sro_ptab FOR VALUES FROM (1) TO (10);
|
||||
ALTER TABLE sro_part OWNER TO regress_sro_user;
|
||||
INSERT INTO sro_ptab VALUES (1), (2), (3);
|
||||
CREATE INDEX sro_pidx ON sro_ptab ((sro_ifun(a) + sro_ifun(0)))
|
||||
WHERE sro_ifun(a + 10) > sro_ifun(10);
|
||||
REINDEX TABLE sro_ptab;
|
||||
REINDEX INDEX CONCURRENTLY sro_pidx;
|
||||
SET SESSION AUTHORIZATION regress_sro_user;
|
||||
CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
'GRANT regress_priv_group2 TO regress_sro_user';
|
||||
|
@@ -906,6 +906,53 @@ SELECT has_table_privilege('regress_priv_user1', 'atest4', 'SELECT WITH GRANT OP
|
||||
\c -
|
||||
CREATE ROLE regress_sro_user;
|
||||
|
||||
-- Check that index expressions and predicates are run as the table's owner
|
||||
|
||||
-- A dummy index function checking current_user
|
||||
CREATE FUNCTION sro_ifun(int) RETURNS int AS $$
|
||||
BEGIN
|
||||
-- Below we set the table's owner to regress_sro_user
|
||||
ASSERT current_user = 'regress_sro_user',
|
||||
format('sro_ifun(%s) called by %s', $1, current_user);
|
||||
RETURN $1;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql IMMUTABLE;
|
||||
-- Create a table owned by regress_sro_user
|
||||
CREATE TABLE sro_tab (a int);
|
||||
ALTER TABLE sro_tab OWNER TO regress_sro_user;
|
||||
INSERT INTO sro_tab VALUES (1), (2), (3);
|
||||
-- Create an expression index with a predicate
|
||||
CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
|
||||
WHERE sro_ifun(a + 10) > sro_ifun(10);
|
||||
DROP INDEX sro_idx;
|
||||
-- Do the same concurrently
|
||||
CREATE INDEX CONCURRENTLY sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)))
|
||||
WHERE sro_ifun(a + 10) > sro_ifun(10);
|
||||
-- REINDEX
|
||||
REINDEX TABLE sro_tab;
|
||||
REINDEX INDEX sro_idx;
|
||||
REINDEX TABLE CONCURRENTLY sro_tab;
|
||||
DROP INDEX sro_idx;
|
||||
-- CLUSTER
|
||||
CREATE INDEX sro_cluster_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0)));
|
||||
CLUSTER sro_tab USING sro_cluster_idx;
|
||||
DROP INDEX sro_cluster_idx;
|
||||
-- BRIN index
|
||||
CREATE INDEX sro_brin ON sro_tab USING brin ((sro_ifun(a) + sro_ifun(0)));
|
||||
SELECT brin_desummarize_range('sro_brin', 0);
|
||||
SELECT brin_summarize_range('sro_brin', 0);
|
||||
DROP TABLE sro_tab;
|
||||
-- Check with a partitioned table
|
||||
CREATE TABLE sro_ptab (a int) PARTITION BY RANGE (a);
|
||||
ALTER TABLE sro_ptab OWNER TO regress_sro_user;
|
||||
CREATE TABLE sro_part PARTITION OF sro_ptab FOR VALUES FROM (1) TO (10);
|
||||
ALTER TABLE sro_part OWNER TO regress_sro_user;
|
||||
INSERT INTO sro_ptab VALUES (1), (2), (3);
|
||||
CREATE INDEX sro_pidx ON sro_ptab ((sro_ifun(a) + sro_ifun(0)))
|
||||
WHERE sro_ifun(a + 10) > sro_ifun(10);
|
||||
REINDEX TABLE sro_ptab;
|
||||
REINDEX INDEX CONCURRENTLY sro_pidx;
|
||||
|
||||
SET SESSION AUTHORIZATION regress_sro_user;
|
||||
CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
|
||||
'GRANT regress_priv_group2 TO regress_sro_user';
|
||||
|
Reference in New Issue
Block a user