Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/tleextension.c
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,25 @@ check_valid_version_name(const char *versionname)
errdetail("Version names must not contain directory separator characters.")));
}

/*
* pg_tle represents each extension artifact as a function whose name is
* derived from the extension name and version (e.g. "<name>.control" or
* "<name>--<version>.sql"). PostgreSQL silently truncates identifiers at
* NAMEDATALEN, so a derived name that exceeds that limit would collide with
* other artifacts of the same extension once truncated. Reject such names up
* front with a clear message rather than create colliding functions.
*/
static void
check_generated_function_name(const char *funcname)
{
if (strlen(funcname) >= NAMEDATALEN)
ereport(ERROR,
(errcode(ERRCODE_NAME_TOO_LONG),
errmsg("generated function name \"%s\" is too long", funcname),
errdetail("pg_tle function names must be less than %d bytes.",
NAMEDATALEN)));
}

/*
* Utility functions to handle extension-related path names
*/
Expand Down Expand Up @@ -4641,6 +4660,8 @@ pg_tle_install_extension(PG_FUNCTION_ARGS)
*/
sqlname = psprintf("%s--%s.sql", extname, extvers);
ctlname = psprintf("%s.control", extname);
check_generated_function_name(sqlname);
check_generated_function_name(ctlname);

/*
* Check if PG_TLE_EXTNAME is in the list of requirements. Meanwhile, also
Expand Down Expand Up @@ -4859,6 +4880,7 @@ pg_tle_install_extension_version_sql(PG_FUNCTION_ARGS)
* Build appropriate function names based on extension name and version
*/
sqlname = psprintf("%s--%s.sql", extname, extvers);
check_generated_function_name(sqlname);

/*
* Validate that there are no injections using the dollar-quoted strings
Expand Down Expand Up @@ -5012,6 +5034,7 @@ pg_tle_install_update_path(PG_FUNCTION_ARGS)
errhint("This may be an attempt at a SQL injection attack. Please verify your installation file.")));

sqlname = psprintf("%s--%s--%s.sql", extname, fromvers, tovers);
check_generated_function_name(sqlname);
sqlsql = psprintf(
"CREATE FUNCTION %s.%s() RETURNS TEXT AS %s"
"SELECT %s%s%s%s LANGUAGE SQL",
Expand Down
91 changes: 91 additions & 0 deletions test/expected/pg_tle_management.out
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,97 @@ SELECT pgtle.uninstall_extension('foo@bar');
t
(1 row)

-- pg_tle represents each extension artifact as a function whose name is
-- derived from the extension name and version (e.g. "<name>.control" or
-- "<name>--<version>.sql"). PostgreSQL truncates identifiers at NAMEDATALEN
-- (63 bytes), so a derived name longer than that would collide with the
-- extension's other artifacts once truncated. These must be rejected up
-- front rather than silently create colliding functions.
-- An extension name that overflows the generated function name is rejected
-- and nothing is created.
SELECT pgtle.install_extension
(
'test9greaterthanNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALEN',
'0.1',
'comment',
$_pgtle_$ SELECT 1; $_pgtle_$
);
ERROR: generated function name "test9greaterthanNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALEN--0.1.sql" is too long
DETAIL: pg_tle function names must be less than 64 bytes.
SELECT count(*) AS leftover_funcs FROM pg_proc
WHERE pronamespace = 'pgtle'::regnamespace AND proname LIKE 'test9%';
leftover_funcs
----------------
0
(1 row)

-- A long version on a short name overflows the "--<version>.sql" form and is
-- likewise rejected, both via install_extension and install_extension_version.
SELECT pgtle.install_extension
(
'shortname',
'012345678901234567890123456789012345678901234567890123456789',
'comment',
$_pgtle_$ SELECT 1; $_pgtle_$
);
ERROR: generated function name "shortname--012345678901234567890123456789012345678901234567890123456789.sql" is too long
DETAIL: pg_tle function names must be less than 64 bytes.
SELECT pgtle.install_extension('shortname', '1.0', 'comment', $_pgtle_$ SELECT 1; $_pgtle_$);
install_extension
-------------------
t
(1 row)

SELECT pgtle.install_extension_version_sql
(
'shortname',
'012345678901234567890123456789012345678901234567890123456789',
$_pgtle_$ SELECT 1; $_pgtle_$
);
ERROR: generated function name "shortname--012345678901234567890123456789012345678901234567890123456789.sql" is too long
DETAIL: pg_tle function names must be less than 64 bytes.
-- ... and the "--<from>--<to>.sql" update-path form too.
SELECT pgtle.install_update_path
(
'shortname',
'1.0',
'012345678901234567890123456789012345678901234567890123456789',
$_pgtle_$ SELECT 1; $_pgtle_$
);
ERROR: generated function name "shortname--1.0--012345678901234567890123456789012345678901234567890123456789.sql" is too long
DETAIL: pg_tle function names must be less than 64 bytes.
SELECT pgtle.uninstall_extension('shortname');
uninstall_extension
---------------------
t
(1 row)

-- A name at the limit (the generated ".sql" name is 63 bytes) still works.
SELECT pgtle.install_extension
(
'n5456789012345678901234567890123456789012345678901234',
'1.0',
'comment',
$_pgtle_$ SELECT 1; $_pgtle_$
);
install_extension
-------------------
t
(1 row)

SELECT name FROM pgtle.available_extensions()
WHERE name = 'n5456789012345678901234567890123456789012345678901234';
name
-------------------------------------------------------
n5456789012345678901234567890123456789012345678901234
(1 row)

SELECT pgtle.uninstall_extension('n5456789012345678901234567890123456789012345678901234');
uninstall_extension
---------------------
t
(1 row)

-- Skip TransactionStmts
BEGIN;
SELECT pgtle.available_extension_versions();
Expand Down
57 changes: 57 additions & 0 deletions test/sql/pg_tle_management.sql
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,63 @@ SELECT at_func();
DROP EXTENSION "foo@bar";
SELECT pgtle.uninstall_extension('foo@bar');

-- pg_tle represents each extension artifact as a function whose name is
-- derived from the extension name and version (e.g. "<name>.control" or
-- "<name>--<version>.sql"). PostgreSQL truncates identifiers at NAMEDATALEN
-- (63 bytes), so a derived name longer than that would collide with the
-- extension's other artifacts once truncated. These must be rejected up
-- front rather than silently create colliding functions.

-- An extension name that overflows the generated function name is rejected
-- and nothing is created.
SELECT pgtle.install_extension
(
'test9greaterthanNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALENNAMEDATALEN',
'0.1',
'comment',
$_pgtle_$ SELECT 1; $_pgtle_$
);
SELECT count(*) AS leftover_funcs FROM pg_proc
WHERE pronamespace = 'pgtle'::regnamespace AND proname LIKE 'test9%';

-- A long version on a short name overflows the "--<version>.sql" form and is
-- likewise rejected, both via install_extension and install_extension_version.
SELECT pgtle.install_extension
(
'shortname',
'012345678901234567890123456789012345678901234567890123456789',
'comment',
$_pgtle_$ SELECT 1; $_pgtle_$
);
SELECT pgtle.install_extension('shortname', '1.0', 'comment', $_pgtle_$ SELECT 1; $_pgtle_$);
SELECT pgtle.install_extension_version_sql
(
'shortname',
'012345678901234567890123456789012345678901234567890123456789',
$_pgtle_$ SELECT 1; $_pgtle_$
);
-- ... and the "--<from>--<to>.sql" update-path form too.
SELECT pgtle.install_update_path
(
'shortname',
'1.0',
'012345678901234567890123456789012345678901234567890123456789',
$_pgtle_$ SELECT 1; $_pgtle_$
);
SELECT pgtle.uninstall_extension('shortname');

-- A name at the limit (the generated ".sql" name is 63 bytes) still works.
SELECT pgtle.install_extension
(
'n5456789012345678901234567890123456789012345678901234',
'1.0',
'comment',
$_pgtle_$ SELECT 1; $_pgtle_$
);
SELECT name FROM pgtle.available_extensions()
WHERE name = 'n5456789012345678901234567890123456789012345678901234';
SELECT pgtle.uninstall_extension('n5456789012345678901234567890123456789012345678901234');

-- Skip TransactionStmts
BEGIN;
SELECT pgtle.available_extension_versions();
Expand Down
Loading