From 49af5251ce962e325041821e4c814a51d516dfab Mon Sep 17 00:00:00 2001 From: wang_yue111 <648774160@qq.com> Date: Fri, 26 Feb 2021 16:35:18 +0800 Subject: [PATCH] fix CVE-2021-20229 --- CVE-2021-20229.patch | 163 +++++++++++++++++++++++++++++++++++++++++++ postgresql.spec | 7 +- 2 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 CVE-2021-20229.patch diff --git a/CVE-2021-20229.patch b/CVE-2021-20229.patch new file mode 100644 index 0000000..1c03e9d --- /dev/null +++ b/CVE-2021-20229.patch @@ -0,0 +1,163 @@ +From eeede2470a8ec902c80de449d2c4822330c689ca Mon Sep 17 00:00:00 2001 +From: wang_yue111 <648774160@qq.com> +Date: Fri, 26 Feb 2021 12:57:48 +0800 +Subject: [PATCH] Fix mishandling of column-level SELECT privileges for join + aliases. + +scanNSItemForColumn, expandNSItemAttrs, and ExpandSingleTable would +pass the wrong RTE to markVarForSelectPriv when dealing with a join +ParseNamespaceItem: they'd pass the join RTE, when what we need to +mark is the base table that the join column came from. The end +result was to not fill the base table's selectedCols bitmap correctly, +resulting in an understatement of the set of columns that are read +by the query. The executor would still insist on there being at +least one selectable column; but with a correctly crafted query, +a user having SELECT privilege on just one column of a table would +nonetheless be allowed to read all its columns. + +To fix, make markRTEForSelectPriv fetch the correct RTE for itself, +ignoring the possibly-mismatched RTE passed by the caller. Later, +we'll get rid of some now-unused RTE arguments, but that risks +API breaks so we won't do it in released branches. + +This problem was introduced by commit 9ce77d75c, so back-patch +to v13 where that came in. Thanks to Sven Klemm for reporting +the problem. + +Security: CVE-2021-20229 + +--- + src/backend/parser/parse_relation.c | 40 ++++++++++----------- + src/backend/parser/parse_target.c | 8 +++-- + 4 files changed, 91 insertions(+), 22 deletions(-) + +diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c +index bbbb0b6..7ab4ba7 100644 +--- a/src/backend/parser/parse_relation.c ++++ b/src/backend/parser/parse_relation.c +@@ -43,7 +43,8 @@ static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid, + int location); + static void check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem, + int location); +-static void markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, ++static void markRTEForSelectPriv(ParseState *pstate, ++ + int rtindex, AttrNumber col); + static void expandRelation(Oid relid, Alias *eref, + int rtindex, int sublevels_up, +@@ -897,20 +898,15 @@ searchRangeTableForCol(ParseState *pstate, const char *alias, char *colname, + + /* + * markRTEForSelectPriv +- * Mark the specified column of an RTE as requiring SELECT privilege ++ * Mark the specified column of the RTE with index rtindex ++ * as requiring SELECT privilege + * + * col == InvalidAttrNumber means a "whole row" reference +- * +- * The caller should pass the actual RTE if it has it handy; otherwise pass +- * NULL, and we'll look it up here. (This uglification of the API is +- * worthwhile because nearly all external callers have the RTE at hand.) + */ + static void +-markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, +- int rtindex, AttrNumber col) ++markRTEForSelectPriv(ParseState *pstate, int rtindex, AttrNumber col) + { +- if (rte == NULL) +- rte = rt_fetch(rtindex, pstate->p_rtable); ++ RangeTblEntry *rte = rt_fetch(rtindex, pstate->p_rtable); + + if (rte->rtekind == RTE_RELATION) + { +@@ -942,13 +938,13 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, + { + int varno = ((RangeTblRef *) j->larg)->rtindex; + +- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); ++ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber); + } + else if (IsA(j->larg, JoinExpr)) + { + int varno = ((JoinExpr *) j->larg)->rtindex; + +- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); ++ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber); + } + else + elog(ERROR, "unrecognized node type: %d", +@@ -957,13 +953,13 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, + { + int varno = ((RangeTblRef *) j->rarg)->rtindex; + +- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); ++ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber); + } + else if (IsA(j->rarg, JoinExpr)) + { + int varno = ((JoinExpr *) j->rarg)->rtindex; + +- markRTEForSelectPriv(pstate, NULL, varno, InvalidAttrNumber); ++ markRTEForSelectPriv(pstate, varno, InvalidAttrNumber); + } + else + elog(ERROR, "unrecognized node type: %d", +@@ -994,10 +990,10 @@ markRTEForSelectPriv(ParseState *pstate, RangeTblEntry *rte, + + /* + * markVarForSelectPriv +- * Mark the RTE referenced by a Var as requiring SELECT privilege ++ * Mark the RTE referenced by the Var as requiring SELECT privilege ++ * for the Var's column (the Var could be a whole-row Var, too) + * +- * The caller should pass the Var's referenced RTE if it has it handy +- * (nearly all do); otherwise pass NULL. ++ * The rte argument is unused and will be removed later. + */ + void + markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte) +@@ -1008,7 +1004,7 @@ markVarForSelectPriv(ParseState *pstate, Var *var, RangeTblEntry *rte) + /* Find the appropriate pstate if it's an uplevel Var */ + for (lv = 0; lv < var->varlevelsup; lv++) + pstate = pstate->parentParseState; +- markRTEForSelectPriv(pstate, rte, var->varno, var->varattno); ++ markRTEForSelectPriv(pstate, var->varno, var->varattno); + } + + /* +@@ -2629,9 +2625,13 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte, + /* + * Require read access to the table. This is normally redundant with the + * markVarForSelectPriv calls below, but not if the table has zero +- * columns. ++ * columns. We need not do anything if the nsitem is for a join: its ++ * component tables will have been marked ACL_SELECT when they were added ++ * to the rangetable. (This step changes things only for the target ++ * relation of UPDATE/DELETE, which cannot be under a join.) + */ +- rte->requiredPerms |= ACL_SELECT; ++ if (rte->rtekind == RTE_RELATION) ++ rte->requiredPerms |= ACL_SELECT; + + forboth(name, names, var, vars) + { +diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c +index 64a1b75..c7165cb 100644 +--- a/src/backend/parser/parse_target.c ++++ b/src/backend/parser/parse_target.c +@@ -1328,9 +1328,13 @@ ExpandSingleTable(ParseState *pstate, RangeTblEntry *rte, + /* + * Require read access to the table. This is normally redundant with + * the markVarForSelectPriv calls below, but not if the table has zero +- * columns. ++ * columns. We need not do anything if the nsitem is for a join: its ++ * component tables will have been marked ACL_SELECT when they were ++ * added to the rangetable. (This step changes things only for the ++ * target relation of UPDATE/DELETE, which cannot be under a join.) + */ +- rte->requiredPerms |= ACL_SELECT; ++ if (rte->rtekind == RTE_RELATION) ++ rte->requiredPerms |= ACL_SELECT; + + /* Require read access to each column */ + foreach(l, vars) diff --git a/postgresql.spec b/postgresql.spec index f8eeb65..52cbdbe 100644 --- a/postgresql.spec +++ b/postgresql.spec @@ -4,7 +4,7 @@ Name: postgresql Version: 10.5 -Release: 20 +Release: 21 Summary: PostgreSQL client programs License: PostgreSQL URL: http://www.postgresql.org/ @@ -44,7 +44,7 @@ Patch6010: CVE-2020-25694-2.patch Patch6011: CVE-2020-25694-3.patch Patch6012: CVE-2020-25695.patch Patch6013: CVE-2020-25696.patch - +Patch6014: CVE-2021-20229.patch BuildRequires: gcc perl(ExtUtils::MakeMaker) glibc-devel bison flex gawk perl(ExtUtils::Embed) BuildRequires: perl-devel perl-generators readline-devel zlib-devel systemd systemd-devel @@ -435,6 +435,9 @@ find_lang_bins pltcl.lst pltcl %attr(-,postgres,postgres) %{_libdir}/pgsql/test %changelog +* Fri Feb 26 2021 wangyue - 10.5-21 +- Fix CVE-2021-20229 + * Fri Jan 29 2021 lingsheng - 10.5-20 - Add docbook-style-xsl to BuildRequires -- Gitee