Skip to content

Commit d035c1b

Browse files
committed
Add security checks to selectivity estimation functions
Some selectivity estimation functions run user-supplied operators over data obtained from pg_statistic without security checks, which allows those operators to leak pg_statistic data without having privileges on the underlying tables. Fix by checking that one of the following is satisfied: (1) the user has table or column privileges on the table underlying the pg_statistic data, or (2) the function implementing the user-supplied operator is leak-proof. If neither is satisfied, planning will proceed as if there are no statistics available. At least one of these is satisfied in most cases in practice. The only situations that are negatively impacted are user-defined or not-leak-proof operators on a security-barrier view. Reported-by: Robert Haas <[email protected]> Author: Peter Eisentraut <[email protected]> Author: Tom Lane <[email protected]> Security: CVE-2017-7484
1 parent f79531f commit d035c1b

File tree

6 files changed

+354
-32
lines changed

6 files changed

+354
-32
lines changed

doc/src/sgml/planstats.sgml

+60
Original file line numberDiff line numberDiff line change
@@ -448,4 +448,64 @@ rows = (outer_cardinality * inner_cardinality) * selectivity
448448

449449
</sect1>
450450

451+
<sect1 id="planner-stats-security">
452+
<title>Planner Statistics and Security</title>
453+
454+
<para>
455+
Access to the table <structname>pg_statistic</structname> is restricted to
456+
superusers, so that ordinary users cannot learn about the contents of the
457+
tables of other users from it. Some selectivity estimation functions will
458+
use a user-provided operator (either the operator appearing in the query or
459+
a related operator) to analyze the stored statistics. For example, in order
460+
to determine whether a stored most common value is applicable, the
461+
selectivity estimator will have to run the appropriate <literal>=</literal>
462+
operator to compare the constant in the query to the stored value.
463+
Thus the data in <structname>pg_statistic</structname> is potentially
464+
passed to user-defined operators. An appropriately crafted operator can
465+
intentionally leak the passed operands (for example, by logging them
466+
or writing them to a different table), or accidentally leak them by showing
467+
their values in error messages, in either case possibly exposing data from
468+
<structname>pg_statistic</structname> to a user who should not be able to
469+
see it.
470+
</para>
471+
472+
<para>
473+
In order to prevent this, the following applies to all built-in selectivity
474+
estimation functions. When planning a query, in order to be able to use
475+
stored statistics, the current user must either
476+
have <literal>SELECT</literal> privilege on the table or the involved
477+
columns, or the operator used must be <literal>LEAKPROOF</literal> (more
478+
accurately, the function that the operator is based on). If not, then the
479+
selectivity estimator will behave as if no statistics are available, and
480+
the planner will proceed with default or fall-back assumptions.
481+
</para>
482+
483+
<para>
484+
If a user does not have the required privilege on the table or columns,
485+
then in many cases the query will ultimately receive a permission-denied
486+
error, in which case this mechanism is invisible in practice. But if the
487+
user is reading from a security-barrier view, then the planner might wish
488+
to check the statistics of an underlying table that is otherwise
489+
inaccessible to the user. In that case, the operator should be leak-proof
490+
or the statistics will not be used. There is no direct feedback about
491+
that, except that the plan might be suboptimal. If one suspects that this
492+
is the case, one could try running the query as a more privileged user,
493+
to see if a different plan results.
494+
</para>
495+
496+
<para>
497+
This restriction applies only to cases where the planner would need to
498+
execute a user-defined operator on one or more values
499+
from <structname>pg_statistic</structname>. Thus the planner is permitted
500+
to use generic statistical information, such as the fraction of null values
501+
or the number of distinct values in a column, regardless of access
502+
privileges.
503+
</para>
504+
505+
<para>
506+
Selectivity estimation functions contained in third-party extensions that
507+
potentially operate on statistics with user-defined operators should follow
508+
the same security rules. Consult the PostgreSQL source code for guidance.
509+
</para>
510+
</sect1>
451511
</chapter>

src/backend/utils/adt/array_selfuncs.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ scalararraysel_containment(PlannerInfo *root,
130130
useOr = !useOr;
131131

132132
/* Get array element stats for var, if available */
133-
if (HeapTupleIsValid(vardata.statsTuple))
133+
if (HeapTupleIsValid(vardata.statsTuple) &&
134+
statistic_proc_security_check(&vardata, cmpfunc->fn_oid))
134135
{
135136
Form_pg_statistic stats;
136137
Datum *values;
@@ -361,7 +362,8 @@ calc_arraycontsel(VariableStatData *vardata, Datum constval,
361362
*/
362363
array = DatumGetArrayTypeP(constval);
363364

364-
if (HeapTupleIsValid(vardata->statsTuple))
365+
if (HeapTupleIsValid(vardata->statsTuple) &&
366+
statistic_proc_security_check(vardata, cmpfunc->fn_oid))
365367
{
366368
Form_pg_statistic stats;
367369
Datum *values;

0 commit comments

Comments
 (0)