Skip to content

Commit 4766dce

Browse files
committed
Fix choice of comparison operators for cross-type hashed subplans.
Commit bf6c614 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
1 parent ffa2d37 commit 4766dce

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

src/backend/executor/nodeSubplan.c

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
860860
i;
861861
TupleDesc tupDescLeft;
862862
TupleDesc tupDescRight;
863+
Oid *cross_eq_funcoids;
863864
TupleTableSlot *slot;
864865
List *oplist,
865866
*lefttlist,
@@ -923,6 +924,9 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
923924
sstate->tab_collations = (Oid *) palloc(ncols * sizeof(Oid));
924925
sstate->lhs_hash_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
925926
sstate->cur_eq_funcs = (FmgrInfo *) palloc(ncols * sizeof(FmgrInfo));
927+
/* we'll need the cross-type equality fns below, but not in sstate */
928+
cross_eq_funcoids = (Oid *) palloc(ncols * sizeof(Oid));
929+
926930
i = 1;
927931
foreach(l, oplist)
928932
{
@@ -952,7 +956,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
952956
righttlist = lappend(righttlist, tle);
953957

954958
/* Lookup the equality function (potentially cross-type) */
955-
sstate->tab_eq_funcoids[i - 1] = opexpr->opfuncid;
959+
cross_eq_funcoids[i - 1] = opexpr->opfuncid;
956960
fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
957961
fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
958962

@@ -961,7 +965,9 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
961965
NULL, &rhs_eq_oper))
962966
elog(ERROR, "could not find compatible hash operator for operator %u",
963967
opexpr->opno);
964-
fmgr_info(get_opcode(rhs_eq_oper), &sstate->tab_eq_funcs[i - 1]);
968+
sstate->tab_eq_funcoids[i - 1] = get_opcode(rhs_eq_oper);
969+
fmgr_info(sstate->tab_eq_funcoids[i - 1],
970+
&sstate->tab_eq_funcs[i - 1]);
965971

966972
/* Lookup the associated hash functions */
967973
if (!get_op_hash_functions(opexpr->opno,
@@ -1003,16 +1009,15 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
10031009

10041010
/*
10051011
* Create comparator for lookups of rows in the table (potentially
1006-
* across-type comparison).
1012+
* cross-type comparisons).
10071013
*/
10081014
sstate->cur_eq_comp = ExecBuildGroupingEqual(tupDescLeft, tupDescRight,
10091015
&TTSOpsVirtual, &TTSOpsMinimalTuple,
10101016
ncols,
10111017
sstate->keyColIdx,
1012-
sstate->tab_eq_funcoids,
1018+
cross_eq_funcoids,
10131019
sstate->tab_collations,
10141020
parent);
1015-
10161021
}
10171022

10181023
return sstate;

src/test/regress/expected/subselect.out

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,30 @@ select * from outer_text where (f1, f2) not in (select * from inner_text);
764764
b |
765765
(2 rows)
766766

767+
--
768+
-- Another test case for cross-type hashed subplans: comparison of
769+
-- inner-side values must be done with appropriate operator
770+
--
771+
explain (verbose, costs off)
772+
select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
773+
QUERY PLAN
774+
-------------------------------------
775+
Result
776+
Output: (hashed SubPlan 1)
777+
SubPlan 1
778+
-> Append
779+
-> Result
780+
Output: 'bar'::name
781+
-> Result
782+
Output: 'bar'::name
783+
(8 rows)
784+
785+
select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
786+
?column?
787+
----------
788+
f
789+
(1 row)
790+
767791
--
768792
-- Test case for premature memory release during hashing of subplan output
769793
--

src/test/regress/sql/subselect.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,16 @@ insert into inner_text values ('a', null);
452452

453453
select * from outer_text where (f1, f2) not in (select * from inner_text);
454454

455+
--
456+
-- Another test case for cross-type hashed subplans: comparison of
457+
-- inner-side values must be done with appropriate operator
458+
--
459+
460+
explain (verbose, costs off)
461+
select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
462+
463+
select 'foo'::text in (select 'bar'::name union all select 'bar'::name);
464+
455465
--
456466
-- Test case for premature memory release during hashing of subplan output
457467
--

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy