]> granicus.if.org Git - postgresql/commitdiff
Fix choice of comparison operators for cross-type hashed subplans.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Aug 2019 15:20:21 +0000 (11:20 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 5 Aug 2019 15:20:31 +0000 (11:20 -0400)
Commit bf6c614a2 rearranged the lookup of the comparison operators
needed in a hashed subplan, and in so doing, broke the cross-type
case: it caused the original LHS-vs-RHS operator to be used to compare
hash table entries too (which of course are all of the RHS type).
This leads to C functions being passed a Datum that is not of the
type they expect, with the usual hazards of crashes and unauthorized
server memory disclosure.

For the set of hashable cross-type operators present in v11 core
Postgres, this bug is nearly harmless on 64-bit machines, which
may explain why it escaped earlier detection.  But it is a live
security hazard on 32-bit machines; and of course there may be
extensions that add more hashable cross-type operators, which
would increase the risk.

Reported by Andreas Seltenreich.  Back-patch to v11 where the
problem came in.

Security: CVE-2019-10209

src/backend/executor/nodeSubplan.c
src/test/regress/expected/subselect.out
src/test/regress/sql/subselect.sql

index f6445e286ac81ec51e359c83cf0a3ee28c21aa92..1991b90a55f5b4d7c7038b5e287ff138453f3df8 100644 (file)
@@ -860,6 +860,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                                        i;
                TupleDesc       tupDescLeft;
                TupleDesc       tupDescRight;
+               Oid                *cross_eq_funcoids;
                TupleTableSlot *slot;
                List       *oplist,
                                   *lefttlist,
@@ -923,6 +924,9 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
                sstate->lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
                sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
+               /* we'll need the cross-type equality fns below, but not in sstate */
+               cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
+
                i = 1;
                foreach(l, oplist)
                {
@@ -952,7 +956,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                        righttlist = lappend(righttlist, tle);
 
                        /* Lookup the equality function (potentially cross-type) */
-                       sstate->tab_eq_funcoids[i - 1] = opexpr->opfuncid;
+                       cross_eq_funcoids[i - 1] = opexpr->opfuncid;
                        fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
                        fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
 
@@ -961,7 +965,9 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
                                                                                           NULL, &rhs_eq_oper))
                                elog(ERROR, "could not find compatible hash operator for operator %u",
                                         opexpr->opno);
-                       fmgr_info(get_opcode(rhs_eq_oper), &sstate->tab_eq_funcs[i - 1]);
+                       sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
+                       fmgr_info(sstate->tab_eq_funcoids[i - 1],
+                                         &sstate->tab_eq_funcs[i - 1]);
 
                        /* Lookup the associated hash functions */
                        if (!get_op_hash_functions(opexpr->opno,
@@ -1003,16 +1009,15 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
 
                /*
                 * Create comparator for lookups of rows in the table (potentially
-                * across-type comparison).
+                * cross-type comparisons).
                 */
                sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
                                                                                                         &TTSOpsVirtual, &TTSOpsMinimalTuple,
                                                                                                         ncols,
                                                                                                         sstate->keyColIdx,
-                                                                                                        sstate->tab_eq_funcoids,
+                                                                                                        cross_eq_funcoids,
                                                                                                         sstate->tab_collations,
                                                                                                         parent);
-
        }
 
        return sstate;
index 2d1963d12aedbe9267cbe764cda842c91762d3ea..ee9c5db0d5123e7c53c5c21dc92366fa71485ede 100644 (file)
@@ -764,6 +764,30 @@ select * from outer_text where (f1, f2) not in (select * from inner_text);
  b  | 
 (2 rows)
 
+--
+-- Another test case for cross-type hashed subplans: comparison of
+-- inner-side values must be done with appropriate operator
+--
+explain (verbose, costs off)
+select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
+             QUERY PLAN              
+-------------------------------------
+ Result
+   Output: (hashed SubPlan 1)
+   SubPlan 1
+     ->  Append
+           ->  Result
+                 Output: 'bar'::name
+           ->  Result
+                 Output: 'bar'::name
+(8 rows)
+
+select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
+ ?column? 
+----------
+ f
+(1 row)
+
 --
 -- Test case for premature memory release during hashing of subplan output
 --
index 99ca69791e3ec7744a61358cf4df45e4bab895b5..20c4f99c9c43e1fa426b1dfa03b2fc96e6f9af25 100644 (file)
@@ -452,6 +452,16 @@ insert into inner_text values ('a', null);
 
 select * from outer_text where (f1, f2) not in (select * from inner_text);
 
+--
+-- Another test case for cross-type hashed subplans: comparison of
+-- inner-side values must be done with appropriate operator
+--
+
+explain (verbose, costs off)
+select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
+
+select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
+
 --
 -- Test case for premature memory release during hashing of subplan output
 --