doc: Expand on proper use of refint.

The security team has received a couple of reports about potential
SQL injection via refint's trigger arguments.  We discussed this
while preparing CVE-2026-6637 and concluded that forcibly quoting
these arguments is more likely to break working code than to
prevent exploits.  Unlike data values, the table/column names come
from trigger arguments, and there is little reason for a trigger
author to put hostile inputs into those arguments.  So, let's
document it accordingly.

Reported-by: Nikolay Samokhvalov <nik@postgres.ai>
Reported-by: Alex Young <alex000young@gmail.com>
Reported-by: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Suggested-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Noah Misch <noah@leadboat.com>
Reviewed-by: Fujii Masao <masao.fujii@oss.nttdata.com>
Reviewed-by: Christoph Berg <myon@debian.org>
Reviewed-by: Satyanarayana Narlapuram <satyanarlapuram@gmail.com>
Discussion: https://postgr.es/m/ahXP7z7nsfGPOZ3T%40nathan
Backpatch-through: 14
This commit is contained in:
Nathan Bossart 2026-06-08 10:33:52 -05:00
parent f58623faa8
commit 1541d91d1c

View file

@ -34,6 +34,14 @@
key mechanism, of course, but the module is still useful as an example.) key mechanism, of course, but the module is still useful as an example.)
</para> </para>
<note>
<para>
<filename>refint</filename> requires a
<link linkend="ddl-schemas-patterns">secure schema usage pattern</link> and
data types where the equality operator is named <literal>=</literal>.
</para>
</note>
<para> <para>
<function>check_primary_key()</function> checks the referencing table. <function>check_primary_key()</function> checks the referencing table.
To use, create an <literal>AFTER INSERT OR UPDATE</literal> trigger using this To use, create an <literal>AFTER INSERT OR UPDATE</literal> trigger using this
@ -44,6 +52,29 @@
keys, create a trigger for each reference. keys, create a trigger for each reference.
</para> </para>
<note>
<para>
The <emphasis>referenced</emphasis> table name and column name arguments to
<function>check_primary_key()</function> are copied as-is into internally
generated SQL statements and therefore must be double-quoted by the user as
necessary in the <command>CREATE TRIGGER</command> command. See
<xref linkend="sql-syntax-identifiers"/> for more information about quoting
SQL identifiers. Conversely, the <emphasis>referencing</emphasis> table
column name arguments should not be double quoted. See the following mock
example of proper use of <function>check_primary_key()</function>:
<programlisting>
CREATE TRIGGER mytrigger
AFTER INSERT OR UPDATE ON referencing_table
FOR EACH ROW EXECUTE PROCEDURE
check_primary_key (
'column A', 'column B', -- referencing table columns
'myschema."referenced table"', -- referenced table
'"column A"', '"column B"' -- referenced table columns
);
</programlisting>
</para>
</note>
<para> <para>
<function>check_foreign_key()</function> checks the referenced table. <function>check_foreign_key()</function> checks the referenced table.
To use, create an <literal>AFTER DELETE OR UPDATE</literal> trigger using this To use, create an <literal>AFTER DELETE OR UPDATE</literal> trigger using this
@ -53,13 +84,38 @@
(<literal>cascade</literal> &mdash; to delete the referencing row, (<literal>cascade</literal> &mdash; to delete the referencing row,
<literal>restrict</literal> &mdash; to abort transaction if referencing keys <literal>restrict</literal> &mdash; to abort transaction if referencing keys
exist, <literal>setnull</literal> &mdash; to set referencing key fields to null), exist, <literal>setnull</literal> &mdash; to set referencing key fields to null),
the triggered table's column names which form the primary/unique key, then the referenced table's column names which form the primary/unique key, then
the referencing table name and column names (repeated for as many the referencing table name and column names (repeated for as many
referencing tables as were specified by first argument). Note that the referencing tables as were specified by first argument). Note that the
primary/unique key columns should be marked NOT NULL and should have a primary/unique key columns should be marked NOT NULL and should have a
unique index. unique index.
</para> </para>
<note>
<para>
The <emphasis>referencing</emphasis> table name and column name arguments
to <function>check_foreign_key()</function> are copied as-is into
internally generated SQL statements and therefore must be double-quoted by
the user as necessary in the <command>CREATE TRIGGER</command> command.
See <xref linkend="sql-syntax-identifiers"/> for more information about
quoting SQL identifiers. Conversely, the <emphasis>referenced</emphasis>
table column name arguments should not be double quoted. See the following
mock example of proper use of <function>check_foreign_key()</function>:
<programlisting>
CREATE TRIGGER mytrigger
AFTER DELETE OR UPDATE ON referenced_table
FOR EACH ROW EXECUTE PROCEDURE
check_foreign_key (
1, -- number of referencing tables
'cascade', -- action
'column A', 'column B', -- referenced table columns
'myschema."referencing table"', -- referencing table
'"column A"', '"column B"' -- referencing table columns
);
</programlisting>
</para>
</note>
<para> <para>
Note that if these triggers are executed from Note that if these triggers are executed from
another <literal>BEFORE</literal> trigger, they can fail unexpectedly. For another <literal>BEFORE</literal> trigger, they can fail unexpectedly. For