Fix RelationBuildPartitionKey's processing of partition key expressions.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Feb 2018 15:37:30 +0000 (10:37 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Feb 2018 15:37:30 +0000 (10:37 -0500)
Failure to advance the list pointer while reading partition expressions
from a list results in invoking an input function with inappropriate data,
possibly leading to crashes or, with carefully crafted input, disclosure
of arbitrary backend memory.

Bug discovered independently by Γlvaro Herrera and David Rowley.
This patch is by Γlvaro but owes something to David's proposed fix.
Back-patch to v10 where the issue was introduced.

Security: CVE-2018-1052

src/backend/utils/cache/relcache.c
src/test/regress/expected/create_table.out
src/test/regress/sql/create_table.sql

index c081b88b7334d5ada81a7a271e1c463234d308ab..d5cc246156bf10a8c7d90f2d4608402cbccb21a2 100644 (file)
@@ -983,9 +983,14 @@ RelationBuildPartitionKey(Relation relation)
        }
        else
        {
+           if (partexprs_item == NULL)
+               elog(ERROR, "wrong number of partition key expressions");
+
            key->parttypid[i] = exprType(lfirst(partexprs_item));
            key->parttypmod[i] = exprTypmod(lfirst(partexprs_item));
            key->parttypcoll[i] = exprCollation(lfirst(partexprs_item));
+
+           partexprs_item = lnext(partexprs_item);
        }
        get_typlenbyvalalign(key->parttypid[i],
                             &key->parttyplen[i],
index e554ec484449f49d52c2ae35d52197aee81ecca1..f5e56365f58809a679f3d7550d55daeeef876153 100644 (file)
@@ -419,8 +419,9 @@ DETAIL:  table partitioned depends on function plusone(integer)
 HINT:  Use DROP ... CASCADE to drop the dependent objects too.
 -- partitioned table cannot participate in regular inheritance
 CREATE TABLE partitioned2 (
-   a int
-) PARTITION BY LIST ((a+1));
+   a int,
+   b text
+) PARTITION BY RANGE ((a+1), substr(b, 1, 5));
 CREATE TABLE fail () INHERITS (partitioned2);
 ERROR:  cannot inherit from partitioned table "partitioned2"
 -- Partition key in describe output
@@ -436,13 +437,27 @@ Partition key: RANGE (a oid_ops, plusone(b), c, d COLLATE "C")
 Number of partitions: 0
 
 \d+ partitioned2
-                               Table "public.partitioned2"
- Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
---------+---------+-----------+----------+---------+---------+--------------+-------------
- a      | integer |           |          |         | plain   |              | 
-Partition key: LIST (((a + 1)))
+                                Table "public.partitioned2"
+ Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a      | integer |           |          |         | plain    |              | 
+ b      | text    |           |          |         | extended |              | 
+Partition key: RANGE (((a + 1)), substr(b, 1, 5))
 Number of partitions: 0
 
+INSERT INTO partitioned2 VALUES (1, 'hello');
+ERROR:  no partition of relation "partitioned2" found for row
+DETAIL:  Partition key of the failing row contains ((a + 1), substr(b, 1, 5)) = (2, hello).
+CREATE TABLE part2_1 PARTITION OF partitioned2 FOR VALUES FROM (-1, 'aaaaa') TO (100, 'ccccc');
+\d+ part2_1
+                                  Table "public.part2_1"
+ Column |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+--------+---------+-----------+----------+---------+----------+--------------+-------------
+ a      | integer |           |          |         | plain    |              | 
+ b      | text    |           |          |         | extended |              | 
+Partition of: partitioned2 FOR VALUES FROM ('-1', 'aaaaa') TO (100, 'ccccc')
+Partition constraint: (((a + 1) IS NOT NULL) AND (substr(b, 1, 5) IS NOT NULL) AND (((a + 1) > '-1'::integer) OR (((a + 1) = '-1'::integer) AND (substr(b, 1, 5) >= 'aaaaa'::text))) AND (((a + 1) < 100) OR (((a + 1) = 100) AND (substr(b, 1, 5) < 'ccccc'::text))))
+
 DROP TABLE partitioned, partitioned2;
 --
 -- Partitions
index a71d9ae7abc337f5389d3a158cca310073cb6283..fdd6d141044e786719dbbefcbe309a58e385ed03 100644 (file)
@@ -419,14 +419,19 @@ DROP FUNCTION plusone(int);
 
 -- partitioned table cannot participate in regular inheritance
 CREATE TABLE partitioned2 (
-   a int
-) PARTITION BY LIST ((a+1));
+   a int,
+   b text
+) PARTITION BY RANGE ((a+1), substr(b, 1, 5));
 CREATE TABLE fail () INHERITS (partitioned2);
 
 -- Partition key in describe output
 \d partitioned
 \d+ partitioned2
 
+INSERT INTO partitioned2 VALUES (1, 'hello');
+CREATE TABLE part2_1 PARTITION OF partitioned2 FOR VALUES FROM (-1, 'aaaaa') TO (100, 'ccccc');
+\d+ part2_1
+
 DROP TABLE partitioned, partitioned2;
 
 --