Skip to content

Commit c72d688

Browse files
authored
Merge pull request #222 from kulaginm/CVE-2020-14350
CVE-2020-14350
2 parents f8a9633 + e0171c8 commit c72d688

9 files changed

+346
-145
lines changed

Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ REGRESS = pathman_array_qual \
6161
pathman_update_triggers \
6262
pathman_upd_del \
6363
pathman_utility_stmt \
64-
pathman_views
64+
pathman_views \
65+
pathman_CVE-2020-14350
6566

6667

6768
EXTRA_REGRESS_OPTS=--temp-config=$(top_srcdir)/$(subdir)/conf.add

README.md

+15-7
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,19 @@ shared_preload_libraries = 'pg_pathman'
9595
9696
It is essential to restart the PostgreSQL instance. After that, execute the following query in psql:
9797
```plpgsql
98-
CREATE EXTENSION pg_pathman;
98+
CREATE SCHEMA pathman;
99+
GRANT USAGE ON SCHEMA pathman TO PUBLIC;
100+
CREATE EXTENSION pg_pathman WITH SCHEMA pathman;
99101
```
100102

101103
Done! Now it's time to setup your partitioning schemes.
102104

105+
> **Security notice**: pg_pathman is believed to be secure against
106+
search-path-based attacks mentioned in Postgres
107+
[documentation](https://www.postgresql.org/docs/current/sql-createextension.html). However,
108+
if *your* calls of pathman's functions doesn't exactly match the signature, they
109+
might be vulnerable to malicious overloading. If in doubt, install pathman to clean schema where nobody except superusers have CREATE object permission to avoid problems.
110+
103111
> **Windows-specific**: pg_pathman imports several symbols (e.g. None_Receiver, InvalidObjectAddress) from PostgreSQL, which is fine by itself, but requires that those symbols are marked as `PGDLLIMPORT`. Unfortunately, some of them are not exported from vanilla PostgreSQL, which means that you have to either use Postgres Pro Standard/Enterprise (which includes all necessary patches), or patch and build your own distribution of PostgreSQL.
104112
105113
## How to update
@@ -611,7 +619,7 @@ SELECT tableoid::regclass AS partition, * FROM partitioned_table;
611619
- All running concurrent partitioning tasks can be listed using the `pathman_concurrent_part_tasks` view:
612620
```plpgsql
613621
SELECT * FROM pathman_concurrent_part_tasks;
614-
userid | pid | dbid | relid | processed | status
622+
userid | pid | dbid | relid | processed | status
615623
--------+------+-------+-------+-----------+---------
616624
dmitry | 7367 | 16384 | test | 472000 | working
617625
(1 row)
@@ -625,7 +633,7 @@ WHERE parent = 'part_test'::regclass AND range_min::int < 500;
625633
NOTICE: 1 rows copied from part_test_11
626634
NOTICE: 100 rows copied from part_test_1
627635
NOTICE: 100 rows copied from part_test_2
628-
drop_range_partition
636+
drop_range_partition
629637
----------------------
630638
dummy_test_11
631639
dummy_test_1
@@ -780,8 +788,8 @@ All sections and data will remain unchanged and will be handled by the standard
780788
Do not hesitate to post your issues, questions and new ideas at the [issues](https://github.com/postgrespro/pg_pathman/issues) page.
781789

782790
## Authors
783-
[Ildar Musin](https://github.com/zilder)
784-
Alexander Korotkov <a.korotkov(at)postgrespro.ru> Postgres Professional Ltd., Russia
785-
[Dmitry Ivanov](https://github.com/funbringer)
786-
Maksim Milyutin <m.milyutin(at)postgrespro.ru> Postgres Professional Ltd., Russia
791+
[Ildar Musin](https://github.com/zilder)
792+
Alexander Korotkov <a.korotkov(at)postgrespro.ru> Postgres Professional Ltd., Russia
793+
[Dmitry Ivanov](https://github.com/funbringer)
794+
Maksim Milyutin <m.milyutin(at)postgrespro.ru> Postgres Professional Ltd., Russia
787795
[Ildus Kurbangaliev](https://github.com/ildus)

expected/pathman_CVE-2020-14350.out

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Check fix for CVE-2020-14350.
3+
* See also 7eeb1d986 postgresql commit.
4+
*/
5+
SET client_min_messages = 'warning';
6+
DROP FUNCTION IF EXISTS _partition_data_concurrent(oid,integer);
7+
DROP FUNCTION IF EXISTS create_single_range_partition(TEXT,ANYELEMENT,ANYELEMENT,TEXT);
8+
DROP TABLE IF EXISTS test1 CASCADE;
9+
DROP TABLE IF EXISTS test2 CASCADE;
10+
DROP ROLE IF EXISTS regress_hacker;
11+
SET client_min_messages = 'notice';
12+
CREATE EXTENSION pg_pathman;
13+
CREATE ROLE regress_hacker LOGIN;
14+
-- Test 1
15+
RESET ROLE;
16+
ALTER ROLE regress_hacker NOSUPERUSER;
17+
SET ROLE regress_hacker;
18+
SHOW is_superuser;
19+
is_superuser
20+
--------------
21+
off
22+
(1 row)
23+
24+
CREATE FUNCTION _partition_data_concurrent(relation oid, p_limit INT, OUT p_total BIGINT)
25+
RETURNS bigint
26+
AS $$
27+
BEGIN
28+
ALTER ROLE regress_hacker SUPERUSER;
29+
SELECT _partition_data_concurrent(relation, NULL::text, NULL::text, p_limit) INTO p_total;
30+
END
31+
$$ LANGUAGE plpgsql;
32+
CREATE TABLE test1(i INT4 NOT NULL);
33+
INSERT INTO test1 SELECT generate_series(1, 500);
34+
SELECT create_hash_partitions('test1', 'i', 5, false);
35+
create_hash_partitions
36+
------------------------
37+
5
38+
(1 row)
39+
40+
RESET ROLE;
41+
SELECT partition_table_concurrently('test1', 10, 1);
42+
NOTICE: worker started, you can stop it with the following command: select public.stop_concurrent_part_task('test1');
43+
partition_table_concurrently
44+
------------------------------
45+
46+
(1 row)
47+
48+
SELECT pg_sleep(1);
49+
pg_sleep
50+
----------
51+
52+
(1 row)
53+
54+
-- Test result (must be 'off')
55+
SET ROLE regress_hacker;
56+
SHOW is_superuser;
57+
is_superuser
58+
--------------
59+
off
60+
(1 row)
61+
62+
-- Test 2
63+
RESET ROLE;
64+
ALTER ROLE regress_hacker NOSUPERUSER;
65+
SET ROLE regress_hacker;
66+
SHOW is_superuser;
67+
is_superuser
68+
--------------
69+
off
70+
(1 row)
71+
72+
CREATE FUNCTION create_single_range_partition(parent_relid TEXT, start_value ANYELEMENT, end_value ANYELEMENT, partition_name TEXT)
73+
RETURNS REGCLASS
74+
AS $$
75+
BEGIN
76+
ALTER ROLE regress_hacker SUPERUSER;
77+
RETURN create_single_range_partition(parent_relid, start_value, end_value, partition_name, NULL::text);
78+
END
79+
$$ LANGUAGE plpgsql;
80+
RESET ROLE;
81+
CREATE TABLE test2(i INT4 NOT NULL);
82+
INSERT INTO test2 VALUES(0);
83+
SELECT create_range_partitions('test2', 'i', 0, 1);
84+
create_range_partitions
85+
-------------------------
86+
1
87+
(1 row)
88+
89+
INSERT INTO test2 values(1);
90+
-- Test result (must be 'off')
91+
SET ROLE regress_hacker;
92+
SHOW is_superuser;
93+
is_superuser
94+
--------------
95+
off
96+
(1 row)
97+
98+
-- Cleanup
99+
RESET ROLE;
100+
DROP FUNCTION _partition_data_concurrent(oid,integer);
101+
DROP FUNCTION create_single_range_partition(TEXT,ANYELEMENT,ANYELEMENT,TEXT);
102+
DROP TABLE test1 CASCADE;
103+
NOTICE: drop cascades to 5 other objects
104+
DETAIL: drop cascades to table test1_0
105+
drop cascades to table test1_1
106+
drop cascades to table test1_2
107+
drop cascades to table test1_3
108+
drop cascades to table test1_4
109+
DROP TABLE test2 CASCADE;
110+
NOTICE: drop cascades to 3 other objects
111+
DETAIL: drop cascades to sequence test2_seq
112+
drop cascades to table test2_1
113+
drop cascades to table test2_2
114+
DROP ROLE regress_hacker;
115+
DROP EXTENSION pg_pathman;

hash.sql

+11-11
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
* hash.sql
44
* HASH partitioning functions
55
*
6-
* Copyright (c) 2015-2016, Postgres Professional
6+
* Copyright (c) 2015-2020, Postgres Professional
77
*
88
* ------------------------------------------------------------------------
99
*/
1010

1111
/*
1212
* Creates hash partitions for specified relation
1313
*/
14-
CREATE OR REPLACE FUNCTION @[email protected]_hash_partitions(
14+
CREATE FUNCTION @[email protected]_hash_partitions(
1515
parent_relid REGCLASS,
1616
expression TEXT,
1717
partitions_count INT4,
@@ -53,7 +53,7 @@ SET client_min_messages = WARNING;
5353
*
5454
* lock_parent - should we take an exclusive lock?
5555
*/
56-
CREATE OR REPLACE FUNCTION @[email protected]_hash_partition(
56+
CREATE FUNCTION @[email protected]_hash_partition(
5757
old_partition REGCLASS,
5858
new_partition REGCLASS,
5959
lock_parent BOOL DEFAULT TRUE)
@@ -110,18 +110,18 @@ BEGIN
110110

111111
/* Fetch definition of old_partition's HASH constraint */
112112
SELECT pg_catalog.pg_get_constraintdef(oid) FROM pg_catalog.pg_constraint
113-
WHERE conrelid = old_partition AND quote_ident(conname) = old_constr_name
113+
WHERE conrelid = old_partition AND pg_catalog.quote_ident(conname) = old_constr_name
114114
INTO old_constr_def;
115115

116116
/* Detach old partition */
117-
EXECUTE format('ALTER TABLE %s NO INHERIT %s', old_partition, parent_relid);
118-
EXECUTE format('ALTER TABLE %s DROP CONSTRAINT %s',
117+
EXECUTE pg_catalog.format('ALTER TABLE %s NO INHERIT %s', old_partition, parent_relid);
118+
EXECUTE pg_catalog.format('ALTER TABLE %s DROP CONSTRAINT %s',
119119
old_partition,
120120
old_constr_name);
121121

122122
/* Attach the new one */
123-
EXECUTE format('ALTER TABLE %s INHERIT %s', new_partition, parent_relid);
124-
EXECUTE format('ALTER TABLE %s ADD CONSTRAINT %s %s',
123+
EXECUTE pg_catalog.format('ALTER TABLE %s INHERIT %s', new_partition, parent_relid);
124+
EXECUTE pg_catalog.format('ALTER TABLE %s ADD CONSTRAINT %s %s',
125125
new_partition,
126126
@[email protected]_check_constraint_name(new_partition::REGCLASS),
127127
old_constr_def);
@@ -146,7 +146,7 @@ $$ LANGUAGE plpgsql;
146146
/*
147147
* Just create HASH partitions, called by create_hash_partitions().
148148
*/
149-
CREATE OR REPLACE FUNCTION @[email protected]_hash_partitions_internal(
149+
CREATE FUNCTION @[email protected]_hash_partitions_internal(
150150
parent_relid REGCLASS,
151151
attribute TEXT,
152152
partitions_count INT4,
@@ -158,14 +158,14 @@ LANGUAGE C;
158158
/*
159159
* Calculates hash for integer value
160160
*/
161-
CREATE OR REPLACE FUNCTION @[email protected]_hash_part_idx(INT4, INT4)
161+
CREATE FUNCTION @[email protected]_hash_part_idx(INT4, INT4)
162162
RETURNS INTEGER AS 'pg_pathman', 'get_hash_part_idx'
163163
LANGUAGE C STRICT;
164164

165165
/*
166166
* Build hash condition for a CHECK CONSTRAINT
167167
*/
168-
CREATE OR REPLACE FUNCTION @[email protected]_hash_condition(
168+
CREATE FUNCTION @[email protected]_hash_condition(
169169
attribute_type REGTYPE,
170170
attribute TEXT,
171171
partitions_count INT4,

0 commit comments

Comments
 (0)