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 bfeddcf09b
commit 668ecfda72

View file

@ -34,6 +34,14 @@
key mechanism, of course, but the module is still useful as an example.)
</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>
<function>check_primary_key()</function> checks the referencing table.
To use, create a <literal>BEFORE INSERT OR UPDATE</literal> trigger using this
@ -44,6 +52,29 @@
keys, create a trigger for each reference.
</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
BEFORE 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>
<function>check_foreign_key()</function> checks the referenced table.
To use, create a <literal>BEFORE DELETE OR UPDATE</literal> trigger using this
@ -53,13 +84,38 @@
(<literal>cascade</literal> &mdash; to delete the referencing row,
<literal>restrict</literal> &mdash; to abort transaction if referencing keys
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
referencing tables as were specified by first argument). Note that the
primary/unique key columns should be marked NOT NULL and should have a
unique index.
</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
BEFORE 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>
There are examples in <filename>refint.example</filename>.
</para>