This is an automated email from the ASF dual-hosted git repository.

yjhjstz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit 2207ae98c5e9abb943520dda305badfc6bc4118e
Author: Noah Misch <[email protected]>
AuthorDate: Mon Aug 7 06:05:56 2023 -0700

    Reject substituting extension schemas or owners matching ["$'\].
    
    Substituting such values in extension scripts facilitated SQL injection
    when @extowner@, @extschema@, or @extschema:...@ appeared inside a
    quoting construct (dollar quoting, '', or "").  No bundled extension was
    vulnerable.  Vulnerable uses do appear in a documentation example and in
    non-bundled extensions.  Hence, the attack prerequisite was an
    administrator having installed files of a vulnerable, trusted,
    non-bundled extension.  Subject to that prerequisite, this enabled an
    attacker having database-level CREATE privilege to execute arbitrary
    code as the bootstrap superuser.  By blocking this attack in the core
    server, there's no need to modify individual extensions.  Back-patch to
    v11 (all supported versions).
    
    Reported by Micah Gate, Valerie Woolard, Tim Carey-Smith, and Christoph
    Berg.
    
    Security: CVE-2023-39417
    (cherry picked from commit eb044d8f0aee1ba4950b0867f6ca9328374318db)
---
 src/backend/commands/extension.c                   | 16 ++++++++++++
 src/test/modules/test_extensions/Makefile          |  6 +++--
 .../test_extensions/expected/test_extensions.out   | 30 ++++++++++++++--------
 .../test_extensions/sql/test_extensions.sql        | 17 +++++++++---
 .../test_extensions/test_ext_extschema--1.0.sql    |  5 ++++
 .../test_extensions/test_ext_extschema.control     |  3 +++
 6 files changed, 60 insertions(+), 17 deletions(-)

diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 08c3a9b569..b39461794c 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1040,6 +1040,16 @@ execute_extension_script(Node *stmt,
                char       *c_sql = read_extension_script_file(control, 
filename);
                Datum           t_sql;
 
+               /*
+                * We filter each substitution through quote_identifier().  
When the
+                * arg contains one of the following characters, no one 
collection of
+                * quoting can work inside $$dollar-quoted string literals$$,
+                * 'single-quoted string literals', and outside of any literal. 
 To
+                * avoid a security snare for extension authors, error on 
substitution
+                * for arguments containing these.
+                */
+               const char *quoting_relevant_chars = "\"$'\\";
+
                /* We use various functions that want to operate on text datums 
*/
                t_sql = CStringGetTextDatum(c_sql);
 
@@ -1080,6 +1090,7 @@ execute_extension_script(Node *stmt,
                 */
                if (!control->relocatable)
                {
+                       Datum           old = t_sql;
                        const char *qSchemaName = quote_identifier(schemaName);
 
                        t_sql = DirectFunctionCall3Coll(replace_text,
@@ -1087,6 +1098,11 @@ execute_extension_script(Node *stmt,
                                                                                
        t_sql,
                                                                                
        CStringGetTextDatum("@extschema@"),
                                                                                
        CStringGetTextDatum(qSchemaName));
+                       if (t_sql != old && strpbrk(schemaName, 
quoting_relevant_chars))
+                               ereport(ERROR,
+                                               
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+                                                errmsg("invalid character in 
extension \"%s\" schema: must not contain any of \"%s\"",
+                                                               control->name, 
quoting_relevant_chars)));
                }
 
                /*
diff --git a/src/test/modules/test_extensions/Makefile 
b/src/test/modules/test_extensions/Makefile
index b6a783c011..c5a240e8ec 100644
--- a/src/test/modules/test_extensions/Makefile
+++ b/src/test/modules/test_extensions/Makefile
@@ -5,13 +5,15 @@ PGFILEDESC = "test_extensions - regression testing for 
EXTENSION support"
 
 EXTENSION = test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 test_ext6 \
             test_ext7 test_ext8 test_ext_cine test_ext_cor \
-            test_ext_cyclic1 test_ext_cyclic2
+            test_ext_cyclic1 test_ext_cyclic2 \
+            test_ext_extschema
 DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \
        test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \
        test_ext7--1.0.sql test_ext7--1.0--2.0.sql test_ext8--1.0.sql \
        test_ext_cine--1.0.sql test_ext_cine--1.0--1.1.sql \
        test_ext_cor--1.0.sql \
-       test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql
+       test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql \
+       test_ext_extschema--1.0.sql
 
 
 REGRESS = test_extensions #test_extdepend TODO: enable this test after 
https://github.com/greenplum-db/gpdb/issues/14532
diff --git a/src/test/modules/test_extensions/expected/test_extensions.out 
b/src/test/modules/test_extensions/expected/test_extensions.out
index 69ef3077a4..b722dfc59c 100644
--- a/src/test/modules/test_extensions/expected/test_extensions.out
+++ b/src/test/modules/test_extensions/expected/test_extensions.out
@@ -1,3 +1,4 @@
+CREATE SCHEMA has$dollar;
 -- test some errors
 CREATE EXTENSION test_ext1;
 ERROR:  required extension "test_ext2" is not installed
@@ -6,35 +7,35 @@ CREATE EXTENSION test_ext1 SCHEMA test_ext1;
 ERROR:  schema "test_ext1" does not exist
 CREATE EXTENSION test_ext1 SCHEMA test_ext;
 ERROR:  schema "test_ext" does not exist
-CREATE SCHEMA test_ext;
-CREATE EXTENSION test_ext1 SCHEMA test_ext;
+CREATE EXTENSION test_ext1 SCHEMA has$dollar;
 ERROR:  extension "test_ext1" must be installed in schema "test_ext1"
 -- finally success
-CREATE EXTENSION test_ext1 SCHEMA test_ext CASCADE;
+CREATE EXTENSION test_ext1 SCHEMA has$dollar CASCADE;
 NOTICE:  installing required extension "test_ext2"
 NOTICE:  installing required extension "test_ext3"
 NOTICE:  installing required extension "test_ext5"
 NOTICE:  installing required extension "test_ext4"
 SELECT extname, nspname, extversion, extrelocatable FROM pg_extension e, 
pg_namespace n WHERE extname LIKE 'test_ext%' AND e.extnamespace = n.oid ORDER 
BY 1;
-  extname  |  nspname  | extversion | extrelocatable 
------------+-----------+------------+----------------
- test_ext1 | test_ext1 | 1.0        | f
- test_ext2 | test_ext  | 1.0        | t
- test_ext3 | test_ext  | 1.0        | t
- test_ext4 | test_ext  | 1.0        | t
- test_ext5 | test_ext  | 1.0        | t
+  extname  |  nspname   | extversion | extrelocatable 
+-----------+------------+------------+----------------
+ test_ext1 | test_ext1  | 1.0        | f
+ test_ext2 | has$dollar | 1.0        | t
+ test_ext3 | has$dollar | 1.0        | t
+ test_ext4 | has$dollar | 1.0        | t
+ test_ext5 | has$dollar | 1.0        | t
 (5 rows)
 
 CREATE EXTENSION test_ext_cyclic1 CASCADE;
 NOTICE:  installing required extension "test_ext_cyclic2"
 ERROR:  cyclic dependency detected between extensions "test_ext_cyclic1" and 
"test_ext_cyclic2"
-DROP SCHEMA test_ext CASCADE;
+DROP SCHEMA has$dollar CASCADE;
 NOTICE:  drop cascades to 5 other objects
 DETAIL:  drop cascades to extension test_ext3
 drop cascades to extension test_ext5
 drop cascades to extension test_ext2
 drop cascades to extension test_ext4
 drop cascades to extension test_ext1
+CREATE SCHEMA has$dollar;
 CREATE EXTENSION test_ext6;
 DROP EXTENSION test_ext6;
 CREATE EXTENSION test_ext6;
@@ -312,3 +313,10 @@ Objects in extension "test_ext_cine"
  table ext_cine_tab3
 (9 rows)
 
+--
+-- Test @extschema@ syntax.
+--
+CREATE SCHEMA "has space";
+CREATE EXTENSION test_ext_extschema SCHEMA has$dollar;
+ERROR:  invalid character in extension "test_ext_extschema" schema: must not 
contain any of ""$'\"
+CREATE EXTENSION test_ext_extschema SCHEMA "has space";
diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql 
b/src/test/modules/test_extensions/sql/test_extensions.sql
index 946c8f25a8..804173df4a 100644
--- a/src/test/modules/test_extensions/sql/test_extensions.sql
+++ b/src/test/modules/test_extensions/sql/test_extensions.sql
@@ -1,18 +1,20 @@
+CREATE SCHEMA has$dollar;
+
 -- test some errors
 CREATE EXTENSION test_ext1;
 CREATE EXTENSION test_ext1 SCHEMA test_ext1;
 CREATE EXTENSION test_ext1 SCHEMA test_ext;
-CREATE SCHEMA test_ext;
-CREATE EXTENSION test_ext1 SCHEMA test_ext;
+CREATE EXTENSION test_ext1 SCHEMA has$dollar;
 
 -- finally success
-CREATE EXTENSION test_ext1 SCHEMA test_ext CASCADE;
+CREATE EXTENSION test_ext1 SCHEMA has$dollar CASCADE;
 
 SELECT extname, nspname, extversion, extrelocatable FROM pg_extension e, 
pg_namespace n WHERE extname LIKE 'test_ext%' AND e.extnamespace = n.oid ORDER 
BY 1;
 
 CREATE EXTENSION test_ext_cyclic1 CASCADE;
 
-DROP SCHEMA test_ext CASCADE;
+DROP SCHEMA has$dollar CASCADE;
+CREATE SCHEMA has$dollar;
 
 CREATE EXTENSION test_ext6;
 DROP EXTENSION test_ext6;
@@ -204,3 +206,10 @@ CREATE EXTENSION test_ext_cine;
 ALTER EXTENSION test_ext_cine UPDATE TO '1.1';
 
 \dx+ test_ext_cine
+
+--
+-- Test @extschema@ syntax.
+--
+CREATE SCHEMA "has space";
+CREATE EXTENSION test_ext_extschema SCHEMA has$dollar;
+CREATE EXTENSION test_ext_extschema SCHEMA "has space";
\ No newline at end of file
diff --git a/src/test/modules/test_extensions/test_ext_extschema--1.0.sql 
b/src/test/modules/test_extensions/test_ext_extschema--1.0.sql
new file mode 100644
index 0000000000..aed53830aa
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_extschema--1.0.sql
@@ -0,0 +1,5 @@
+/* src/test/modules/test_extensions/test_ext_extschema--1.0.sql */
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_ext_extschema" to load this file. \quit
+
+SELECT 1 AS @extschema@;
diff --git a/src/test/modules/test_extensions/test_ext_extschema.control 
b/src/test/modules/test_extensions/test_ext_extschema.control
new file mode 100644
index 0000000000..b124d492c0
--- /dev/null
+++ b/src/test/modules/test_extensions/test_ext_extschema.control
@@ -0,0 +1,3 @@
+comment = 'test @extschema@'
+default_version = '1.0'
+relocatable = false


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to