Document security implications of qualified names.

Commit 5770172cb0 documented secure schema
usage, and that advice suffices for using unqualified names securely.
Document, in typeconv-func primarily, the additional issues that arise
with qualified names.  Back-patch to 9.3 (all supported versions).

Reviewed by Jonathan S. Katz.

Discussion: https://postgr.es/m/20180721012446.GA1840594@rfd.leadboat.com
This commit is contained in:
Noah Misch 2018-07-28 20:08:01 -07:00
parent 9a513f8f9e
commit a117c7a7b6
6 changed files with 147 additions and 33 deletions

View File

@ -2380,9 +2380,12 @@ REVOKE CREATE ON SCHEMA public FROM PUBLIC;
using <literal>ALTER ROLE <replaceable>user</replaceable> SET using <literal>ALTER ROLE <replaceable>user</replaceable> SET
search_path = "$user"</literal>. Everyone retains the ability to search_path = "$user"</literal>. Everyone retains the ability to
create objects in the public schema, but only qualified names will create objects in the public schema, but only qualified names will
choose those objects. A user holding the <literal>CREATEROLE</literal> choose those objects. While qualified table references are fine, calls
privilege can undo this setting and issue arbitrary queries under the to functions in the public schema <link linkend="typeconv-func">will be
identity of users relying on the setting. If you unsafe or unreliable</link>. Also, a user holding
the <literal>CREATEROLE</literal> privilege can undo this setting and
issue arbitrary queries under the identity of users relying on the
setting. If you create functions or extensions in the public schema or
grant <literal>CREATEROLE</literal> to users not warranting this grant <literal>CREATEROLE</literal> to users not warranting this
almost-superuser ability, use the first pattern instead. almost-superuser ability, use the first pattern instead.
</para> </para>
@ -2393,8 +2396,10 @@ REVOKE CREATE ON SCHEMA public FROM PUBLIC;
Remove the public schema from <varname>search_path</varname> in Remove the public schema from <varname>search_path</varname> in
<link linkend="config-setting-configuration-file"><filename>postgresql.conf</filename></link>. <link linkend="config-setting-configuration-file"><filename>postgresql.conf</filename></link>.
The ensuing user experience matches the previous pattern. In addition The ensuing user experience matches the previous pattern. In addition
to that pattern's implications for <literal>CREATEROLE</literal>, this to that pattern's implications for functions
trusts database owners the same way. If you assign and <literal>CREATEROLE</literal>, this trusts database owners
like <literal>CREATEROLE</literal>. If you create functions or
extensions in the public schema or assign
the <literal>CREATEROLE</literal> the <literal>CREATEROLE</literal>
privilege, <literal>CREATEDB</literal> privilege or individual database privilege, <literal>CREATEDB</literal> privilege or individual database
ownership to users not warranting almost-superuser access, use the ownership to users not warranting almost-superuser access, use the

View File

@ -545,8 +545,11 @@ CREATE [ OR REPLACE ] FUNCTION
as for the <xref linkend="sql-load"/> command. The string as for the <xref linkend="sql-load"/> command. The string
<replaceable class="parameter">link_symbol</replaceable> is the <replaceable class="parameter">link_symbol</replaceable> is the
function's link symbol, that is, the name of the function in the C function's link symbol, that is, the name of the function in the C
language source code. If the link symbol is omitted, it is assumed language source code. If the link symbol is omitted, it is assumed to
to be the same as the name of the SQL function being defined. be the same as the name of the SQL function being defined. The C names
of all functions must be different, so you must give overloaded C
functions different C names (for example, use the argument types as
part of the C names).
</para> </para>
<para> <para>
@ -575,10 +578,9 @@ CREATE [ OR REPLACE ] FUNCTION
<productname>PostgreSQL</productname> allows function <productname>PostgreSQL</productname> allows function
<firstterm>overloading</firstterm>; that is, the same name can be <firstterm>overloading</firstterm>; that is, the same name can be
used for several different functions so long as they have distinct used for several different functions so long as they have distinct
input argument types. However, the C names of all functions must be input argument types. Whether or not you use it, this capability entails
different, so you must give overloaded C functions different C security precautions when calling functions in databases where some users
names (for example, use the argument types as part of the C mistrust other users; see <xref linkend="typeconv-func"/>.
names).
</para> </para>
<para> <para>

View File

@ -1518,6 +1518,12 @@ sqrt(2)
Other functions can be added by the user. Other functions can be added by the user.
</para> </para>
<para>
When issuing queries in a database where some users mistrust other users,
observe security precautions from <xref linkend="typeconv-func"/> when
writing function calls.
</para>
<para> <para>
The arguments can optionally have names attached. The arguments can optionally have names attached.
See <xref linkend="sql-syntax-calling-funcs"/> for details. See <xref linkend="sql-syntax-calling-funcs"/> for details.
@ -2590,6 +2596,8 @@ SELECT CASE WHEN min(employees) > 0
its argument values in the same order as they are defined in the function its argument values in the same order as they are defined in the function
declaration. In named notation, the arguments are matched to the declaration. In named notation, the arguments are matched to the
function parameters by name and can be written in any order. function parameters by name and can be written in any order.
For each notation, also consider the effect of function argument types,
documented in <xref linkend="typeconv-func"/>.
</para> </para>
<para> <para>

View File

@ -246,7 +246,19 @@ search path position.
<para> <para>
Check for an operator accepting exactly the input argument types. Check for an operator accepting exactly the input argument types.
If one exists (there can be only one exact match in the set of If one exists (there can be only one exact match in the set of
operators considered), use it. operators considered), use it. Lack of an exact match creates a security
hazard when calling, via qualified name
<footnote id="op-qualified-security">
<!-- If you edit this, consider editing func-qualified-security. -->
<para>
The hazard does not arise with a non-schema-qualified name, because a
search path containing schemas that permit untrusted users to create
objects is not a <link linkend="ddl-schemas-patterns">secure schema usage
pattern</link>.
</para>
</footnote>
(not typical), any operator found in a schema that permits untrusted users to
create objects. In such situations, cast arguments to force an exact match.
</para> </para>
<substeps> <substeps>
@ -589,6 +601,26 @@ function. In that case the function appearing earlier in the search path is
used, or if the two functions are in the same schema, the non-variadic one is used, or if the two functions are in the same schema, the non-variadic one is
preferred. preferred.
</para> </para>
<para>
This creates a security hazard when calling, via qualified name
<footnote id="func-qualified-security">
<!-- If you edit this, consider editing op-qualified-security. -->
<para>
The hazard does not arise with a non-schema-qualified name, because a
search path containing schemas that permit untrusted users to create
objects is not a <link linkend="ddl-schemas-patterns">secure schema usage
pattern</link>.
</para>
</footnote>,
a variadic function found in a schema that permits untrusted users to create
objects. A malicious user can take control and execute arbitrary SQL
functions as though you executed them. Substitute a call bearing
the <literal>VARIADIC</literal> keyword, which bypasses this hazard. Calls
populating <literal>VARIADIC "any"</literal> parameters often have no
equivalent formulation containing the <literal>VARIADIC</literal> keyword. To
issue those calls safely, the function's schema must permit only trusted users
to create objects.
</para>
</step> </step>
<step performance="optional"> <step performance="optional">
<para> <para>
@ -602,6 +634,15 @@ will not be able to determine which to prefer, and so an <quote>ambiguous
function call</quote> error will result if no better match to the call can be function call</quote> error will result if no better match to the call can be
found. found.
</para> </para>
<para>
This creates an availability hazard when calling, via qualified
name<footnoteref linkend="func-qualified-security"/>, any function found in a
schema that permits untrusted users to create objects. A malicious user can
create a function with the name of an existing function, replicating that
function's parameters and appending novel parameters having default values.
This precludes new calls to the original function. To forestall this hazard,
place functions in schemas that permit only trusted users to create objects.
</para>
</step> </step>
</substeps> </substeps>
</step> </step>
@ -610,9 +651,12 @@ found.
<para> <para>
Check for a function accepting exactly the input argument types. Check for a function accepting exactly the input argument types.
If one exists (there can be only one exact match in the set of If one exists (there can be only one exact match in the set of
functions considered), use it. functions considered), use it. Lack of an exact match creates a security
(Cases involving <type>unknown</type> will never find a match at hazard when calling, via qualified
this step.) name<footnoteref linkend="func-qualified-security"/>, a function found in a
schema that permits untrusted users to create objects. In such situations,
cast arguments to force an exact match. (Cases involving <type>unknown</type>
will never find a match at this step.)
</para> </para>
</step> </step>
@ -750,6 +794,57 @@ SELECT round(4.0, 4);
</para> </para>
</example> </example>
<example>
<title>Variadic Function Resolution</title>
<para>
<screen>
CREATE FUNCTION public.variadic_example(VARIADIC numeric[]) RETURNS int
LANGUAGE sql AS 'SELECT 1';
CREATE FUNCTION
</screen>
This function accepts, but does not require, the VARIADIC keyword. It
tolerates both integer and numeric arguments:
<screen>
SELECT public.variadic_example(0),
public.variadic_example(0.0),
public.variadic_example(VARIADIC array[0.0]);
variadic_example | variadic_example | variadic_example
------------------+------------------+------------------
1 | 1 | 1
(1 row)
</screen>
However, the first and second calls will prefer more-specific functions, if
available:
<screen>
CREATE FUNCTION public.variadic_example(numeric) RETURNS int
LANGUAGE sql AS 'SELECT 2';
CREATE FUNCTION
CREATE FUNCTION public.variadic_example(int) RETURNS int
LANGUAGE sql AS 'SELECT 3';
CREATE FUNCTION
SELECT public.variadic_example(0),
public.variadic_example(0.0),
public.variadic_example(VARIADIC array[0.0]);
variadic_example | variadic_example | variadic_example
------------------+------------------+------------------
3 | 2 | 1
(1 row)
</screen>
Given the default configuration and only the first function existing, the
first and second calls are insecure. Any user could intercept them by
creating the second or third function. By matching the argument type exactly
and using the <literal>VARIADIC</literal> keyword, the third call is secure.
</para>
</example>
<example> <example>
<title>Substring Function Type Resolution</title> <title>Substring Function Type Resolution</title>

View File

@ -764,8 +764,11 @@ SELECT mleast(ARRAY[10, -1, 5, 4.4]); -- doesn't work
<para> <para>
Sometimes it is useful to be able to pass an already-constructed array Sometimes it is useful to be able to pass an already-constructed array
to a variadic function; this is particularly handy when one variadic to a variadic function; this is particularly handy when one variadic
function wants to pass on its array parameter to another one. You can function wants to pass on its array parameter to another one. Also,
do that by specifying <literal>VARIADIC</literal> in the call: this is the only secure way to call a variadic function found in a schema
that permits untrusted users to create objects; see
<xref linkend="typeconv-func"/>. You can do this by
specifying <literal>VARIADIC</literal> in the call:
<screen> <screen>
SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]); SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);
@ -827,7 +830,10 @@ SELECT mleast(arr =&gt; ARRAY[10, -1, 5, 4.4]);
parameters after a parameter with a default value have to have parameters after a parameter with a default value have to have
default values as well. (Although the use of named argument notation default values as well. (Although the use of named argument notation
could allow this restriction to be relaxed, it's still enforced so that could allow this restriction to be relaxed, it's still enforced so that
positional argument notation works sensibly.) positional argument notation works sensibly.) Whether or not you use it,
this capability creates a need for precautions when calling functions in
databases where some users mistrust other users; see
<xref linkend="typeconv-func"/>.
</para> </para>
<para> <para>
@ -1399,11 +1405,14 @@ $$ LANGUAGE SQL;
<para> <para>
More than one function can be defined with the same SQL name, so long More than one function can be defined with the same SQL name, so long
as the arguments they take are different. In other words, as the arguments they take are different. In other words,
function names can be <firstterm>overloaded</firstterm>. When a function names can be <firstterm>overloaded</firstterm>. Whether or not
query is executed, the server will determine which function to you use it, this capability entails security precautions when calling
call from the data types and the number of the provided arguments. functions in databases where some users mistrust other users; see
Overloading can also be used to simulate functions with a variable <xref linkend="typeconv-func"/>. When a query is executed, the server
number of arguments, up to a finite maximum number. will determine which function to call from the data types and the number
of the provided arguments. Overloading can also be used to simulate
functions with a variable number of arguments, up to a finite maximum
number.
</para> </para>
<para> <para>

View File

@ -10761,16 +10761,11 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes,
* Determine whether VARIADIC should be printed. We must do this first * Determine whether VARIADIC should be printed. We must do this first
* since it affects the lookup rules in func_get_detail(). * since it affects the lookup rules in func_get_detail().
* *
* Currently, we always print VARIADIC if the function has a merged * We always print VARIADIC if the function has a merged variadic-array
* variadic-array argument. Note that this is always the case for * argument. Note that this is always the case for functions taking a
* functions taking a VARIADIC argument type other than VARIADIC ANY. * VARIADIC argument type other than VARIADIC ANY. If we omitted VARIADIC
* * and printed the array elements as separate arguments, the call could
* In principle, if VARIADIC wasn't originally specified and the array * match a newer non-VARIADIC function.
* actual argument is deconstructable, we could print the array elements
* separately and not print VARIADIC, thus more nearly reproducing the
* original input. For the moment that seems like too much complication
* for the benefit, and anyway we do not know whether VARIADIC was
* originally specified if it's a non-ANY type.
*/ */
if (use_variadic_p) if (use_variadic_p)
{ {