summaryrefslogtreecommitdiff
path: root/contrib
diff options
context:
space:
mode:
authorNoah Misch <noah@leadboat.com>2023-05-08 06:14:07 -0700
committerNoah Misch <noah@leadboat.com>2023-05-08 06:14:07 -0700
commit681d9e4621aac0a9c71364b6f54f00f6d8c4337f (patch)
tree058735d8b659a1a69e6e296be14d59d45ff70b21 /contrib
parentb8c3f6df85e78e09c9709fc895aced719aebd7f9 (diff)
downloadpostgresql-681d9e4621aac0a9c71364b6f54f00f6d8c4337f.tar.gz
Replace last PushOverrideSearchPath() call with set_config_option().
The two methods don't cooperate, so set_config_option("search_path", ...) has been ineffective under non-empty overrideStack. This defect enabled an attacker having database-level CREATE privilege to execute arbitrary code as the bootstrap superuser. While that particular attack requires v13+ for the trusted extension attribute, other attacks are feasible in all supported versions. Standardize on the combination of NewGUCNestLevel() and set_config_option("search_path", ...). It is newer than PushOverrideSearchPath(), more-prevalent, and has no known disadvantages. The "override" mechanism remains for now, for compatibility with out-of-tree code. Users should update such code, which likely suffers from the same sort of vulnerability closed here. Back-patch to v11 (all supported versions). Alexander Lakhin. Reported by Alexander Lakhin. Security: CVE-2023-2454
Diffstat (limited to 'contrib')
-rw-r--r--contrib/seg/Makefile2
-rw-r--r--contrib/seg/expected/security.out32
-rw-r--r--contrib/seg/sql/security.sql32
3 files changed, 65 insertions, 1 deletions
diff --git a/contrib/seg/Makefile b/contrib/seg/Makefile
index c6c134b8f1..a1e49bf051 100644
--- a/contrib/seg/Makefile
+++ b/contrib/seg/Makefile
@@ -14,7 +14,7 @@ PGFILEDESC = "seg - line segment data type"
HEADERS = segdata.h
-REGRESS = seg
+REGRESS = security seg
EXTRA_CLEAN = y.tab.c y.tab.h
diff --git a/contrib/seg/expected/security.out b/contrib/seg/expected/security.out
new file mode 100644
index 0000000000..b47598d039
--- /dev/null
+++ b/contrib/seg/expected/security.out
@@ -0,0 +1,32 @@
+--
+-- Test extension script protection against search path overriding
+--
+CREATE ROLE regress_seg_role;
+SELECT current_database() AS datname \gset
+GRANT CREATE ON DATABASE :"datname" TO regress_seg_role;
+SET ROLE regress_seg_role;
+CREATE SCHEMA regress_seg_schema;
+CREATE FUNCTION regress_seg_schema.exfun(i int) RETURNS int AS $$
+BEGIN
+ CREATE EXTENSION seg VERSION '1.2';
+
+ CREATE FUNCTION regress_seg_schema.compare(oid, regclass) RETURNS boolean AS
+ 'BEGIN RAISE EXCEPTION ''overloaded compare() called by %'', current_user; END;' LANGUAGE plpgsql;
+
+ CREATE OPERATOR = (LEFTARG = oid, RIGHTARG = regclass, PROCEDURE = regress_seg_schema.compare);
+
+ ALTER EXTENSION seg UPDATE TO '1.3';
+
+ RETURN i;
+END; $$ LANGUAGE plpgsql;
+CREATE SCHEMA test_schema
+CREATE TABLE t(i int) PARTITION BY RANGE (i)
+CREATE TABLE p1 PARTITION OF t FOR VALUES FROM (1) TO (regress_seg_schema.exfun(2));
+DROP SCHEMA test_schema CASCADE;
+NOTICE: drop cascades to 3 other objects
+DETAIL: drop cascades to table test_schema.t
+drop cascades to extension seg
+drop cascades to operator test_schema.=(oid,regclass)
+RESET ROLE;
+DROP OWNED BY regress_seg_role;
+DROP ROLE regress_seg_role;
diff --git a/contrib/seg/sql/security.sql b/contrib/seg/sql/security.sql
new file mode 100644
index 0000000000..7dfbbaa304
--- /dev/null
+++ b/contrib/seg/sql/security.sql
@@ -0,0 +1,32 @@
+--
+-- Test extension script protection against search path overriding
+--
+
+CREATE ROLE regress_seg_role;
+SELECT current_database() AS datname \gset
+GRANT CREATE ON DATABASE :"datname" TO regress_seg_role;
+SET ROLE regress_seg_role;
+CREATE SCHEMA regress_seg_schema;
+
+CREATE FUNCTION regress_seg_schema.exfun(i int) RETURNS int AS $$
+BEGIN
+ CREATE EXTENSION seg VERSION '1.2';
+
+ CREATE FUNCTION regress_seg_schema.compare(oid, regclass) RETURNS boolean AS
+ 'BEGIN RAISE EXCEPTION ''overloaded compare() called by %'', current_user; END;' LANGUAGE plpgsql;
+
+ CREATE OPERATOR = (LEFTARG = oid, RIGHTARG = regclass, PROCEDURE = regress_seg_schema.compare);
+
+ ALTER EXTENSION seg UPDATE TO '1.3';
+
+ RETURN i;
+END; $$ LANGUAGE plpgsql;
+
+CREATE SCHEMA test_schema
+CREATE TABLE t(i int) PARTITION BY RANGE (i)
+CREATE TABLE p1 PARTITION OF t FOR VALUES FROM (1) TO (regress_seg_schema.exfun(2));
+
+DROP SCHEMA test_schema CASCADE;
+RESET ROLE;
+DROP OWNED BY regress_seg_role;
+DROP ROLE regress_seg_role;