From c9b961e7eb1ec75c1ccb2b29467a214905fe39b1 Mon Sep 17 00:00:00 2001 From: wang_yue111 <648774160@qq.com> Date: Mon, 1 Mar 2021 15:43:28 +0800 Subject: [PATCH] Fix CVE-2021-20229 --- CVE-2020-25695.patch | 39 +++++------ CVE-2020-25696.patch | 21 +++--- CVE-2021-20229.patch | 163 +++++++++++++++++++++++++++++++++++++++++++ postgresql.spec | 19 ++--- 4 files changed, 196 insertions(+), 46 deletions(-) create mode 100644 CVE-2021-20229.patch diff --git a/CVE-2020-25695.patch b/CVE-2020-25695.patch index 59e6196..6fd067c 100644 --- a/CVE-2020-25695.patch +++ b/CVE-2020-25695.patch @@ -1,4 +1,4 @@ -From 0c3185e963d9f9dd0608214f7d732b84aa0888fe Mon Sep 17 00:00:00 2001 +From f97ecea1ed7b09c6f1398540a1d72a57eee70c9f Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Mon, 9 Nov 2020 07:32:09 -0800 Subject: [PATCH] In security-restricted operations, block enqueue of at-commit @@ -29,7 +29,7 @@ Security: CVE-2020-25695 6 files changed, 104 insertions(+), 6 deletions(-) diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c -index be4ec07cf9..09ffb21d48 100644 +index 885bd075798c..5dcff3d07624 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -645,6 +645,10 @@ pgfdw_report_error(int elevel, PGresult *res, PGconn *conn, @@ -44,10 +44,10 @@ index be4ec07cf9..09ffb21d48 100644 static void pgfdw_xact_callback(XactEvent event, void *arg) diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c -index 9004e38e6d..e2ca8a5d2e 100644 +index 37f31a2c31ea..00cec50e8402 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c -@@ -1961,9 +1961,10 @@ CommitTransaction(void) +@@ -1994,9 +1994,10 @@ CommitTransaction(void) /* * Do pre-commit processing that involves calling user-defined code, such @@ -61,7 +61,7 @@ index 9004e38e6d..e2ca8a5d2e 100644 */ for (;;) { -@@ -1981,9 +1982,6 @@ CommitTransaction(void) +@@ -2014,9 +2015,6 @@ CommitTransaction(void) break; } @@ -71,7 +71,7 @@ index 9004e38e6d..e2ca8a5d2e 100644 /* * The remaining actions cannot call any user-defined code, so it's safe * to start shutting down within-transaction services. But note that most -@@ -1991,6 +1989,9 @@ CommitTransaction(void) +@@ -2024,6 +2022,9 @@ CommitTransaction(void) * the transaction-abort path. */ @@ -82,7 +82,7 @@ index 9004e38e6d..e2ca8a5d2e 100644 if (IsInParallelMode()) AtEOXact_Parallel(true); diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c -index 46369cf3db..3d01a782da 100644 +index 46369cf3dbee..3d01a782da06 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -27,6 +27,7 @@ @@ -105,10 +105,10 @@ index 46369cf3db..3d01a782da 100644 /* * Parse analysis was done already, but we still have to run the rule diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c -index 2886aebef4..896cb20051 100644 +index f83840625348..9c04eee48422 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c -@@ -4142,6 +4142,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, +@@ -4144,6 +4144,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, bool immediate_only) { bool found = false; @@ -116,7 +116,7 @@ index 2886aebef4..896cb20051 100644 AfterTriggerEvent event; AfterTriggerEventChunk *chunk; -@@ -4177,6 +4178,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, +@@ -4179,6 +4180,7 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, */ if (defer_it && move_list != NULL) { @@ -124,7 +124,7 @@ index 2886aebef4..896cb20051 100644 /* add it to move_list */ afterTriggerAddEvent(move_list, event, evtshared); /* mark original copy "done" so we don't do it again */ -@@ -4184,6 +4186,16 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, +@@ -4186,6 +4188,16 @@ afterTriggerMarkEvents(AfterTriggerEventList *events, } } @@ -142,10 +142,10 @@ index 2886aebef4..896cb20051 100644 } diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out -index 65d950f15b..f7f9252a05 100644 +index dacc98450514..26ee16a0c370 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out -@@ -1138,6 +1138,48 @@ SELECT has_table_privilege('regress_user1', 'atest4', 'SELECT WITH GRANT OPTION' +@@ -1253,6 +1253,48 @@ SELECT has_table_privilege('regress_user1', 'atest4', 'SELECT WITH GRANT OPTION' t (1 row) @@ -154,7 +154,7 @@ index 65d950f15b..f7f9252a05 100644 +CREATE ROLE regress_sro_user; +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS -+ 'GRANT regress_priv_group2 TO regress_sro_user'; ++ 'GRANT regress_group2 TO regress_sro_user'; +CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS + 'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true'; +-- REFRESH of this MV will queue a GRANT at end of transaction @@ -184,7 +184,7 @@ index 65d950f15b..f7f9252a05 100644 +ERROR: cannot fire deferred trigger within security-restricted operation +CONTEXT: SQL function "mv_action" statement 1 +BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT; -+ERROR: must have admin option on role "regress_priv_group2" ++ERROR: must have admin option on role "regress_group2" +CONTEXT: SQL function "unwanted_grant" statement 1 +SQL statement "SELECT unwanted_grant()" +PL/pgSQL function sro_trojan() line 1 at PERFORM @@ -195,10 +195,10 @@ index 65d950f15b..f7f9252a05 100644 SET SESSION AUTHORIZATION regress_user4; CREATE FUNCTION dogrant_ok() RETURNS void LANGUAGE sql SECURITY DEFINER AS diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql -index 902f64c747..baa521bcaf 100644 +index 4263315a2d87..f979cccea03f 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql -@@ -726,6 +726,40 @@ SELECT has_table_privilege('regress_user3', 'atest4', 'SELECT'); -- false +@@ -761,6 +761,40 @@ SELECT has_table_privilege('regress_user3', 'atest4', 'SELECT'); -- false SELECT has_table_privilege('regress_user1', 'atest4', 'SELECT WITH GRANT OPTION'); -- true @@ -208,7 +208,7 @@ index 902f64c747..baa521bcaf 100644 + +SET SESSION AUTHORIZATION regress_sro_user; +CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS -+ 'GRANT regress_priv_group2 TO regress_sro_user'; ++ 'GRANT regress_group2 TO regress_sro_user'; +CREATE FUNCTION mv_action() RETURNS bool LANGUAGE sql AS + 'DECLARE c CURSOR WITH HOLD FOR SELECT unwanted_grant(); SELECT true'; +-- REFRESH of this MV will queue a GRANT at end of transaction @@ -239,6 +239,3 @@ index 902f64c747..baa521bcaf 100644 -- Admin options SET SESSION AUTHORIZATION regress_user4; --- -2.23.0 - diff --git a/CVE-2020-25696.patch b/CVE-2020-25696.patch index 1b56845..71c7e54 100644 --- a/CVE-2020-25696.patch +++ b/CVE-2020-25696.patch @@ -1,4 +1,4 @@ -From 098fb00799ffb026ff12c64bd21635f963cfc609 Mon Sep 17 00:00:00 2001 +From a498db87be103f93856dd515a574b2d67d3c1237 Mon Sep 17 00:00:00 2001 From: Noah Misch Date: Mon, 9 Nov 2020 07:32:09 -0800 Subject: [PATCH] Ignore attempts to \gset into specially treated variables. @@ -24,17 +24,17 @@ Security: CVE-2020-25696 5 files changed, 41 insertions(+) diff --git a/src/bin/psql/common.c b/src/bin/psql/common.c -index a41932ff27..f3d966d7cf 100644 +index d04a7943d6a9..4e342c180a6c 100644 --- a/src/bin/psql/common.c +++ b/src/bin/psql/common.c -@@ -878,6 +878,13 @@ StoreQueryTuple(const PGresult *result) +@@ -894,6 +894,13 @@ StoreQueryTuple(const PGresult *result) /* concatenate prefix and column name */ varname = psprintf("%s%s", pset.gset_prefix, colname); + if (VariableHasHook(pset.vars, varname)) + { -+ pg_log_warning("attempt to \\gset into specially treated variable \"%s\" ignored", -+ varname); ++ psql_error("attempt to \\gset into specially treated variable \"%s\" ignored\n", ++ varname); + continue; + } + @@ -42,7 +42,7 @@ index a41932ff27..f3d966d7cf 100644 value = PQgetvalue(result, 0, i); else diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c -index 120b25c696..0d28ba9c92 100644 +index 120b25c69661..0d28ba9c92bb 100644 --- a/src/bin/psql/variables.c +++ b/src/bin/psql/variables.c @@ -360,6 +360,32 @@ SetVariableHooks(VariableSpace space, const char *name, @@ -79,7 +79,7 @@ index 120b25c696..0d28ba9c92 100644 * Convenience function to set a variable's value to "on". */ diff --git a/src/bin/psql/variables.h b/src/bin/psql/variables.h -index 02d85b1bc2..8dc5c20ee8 100644 +index 02d85b1bc2e4..8dc5c20ee8fc 100644 --- a/src/bin/psql/variables.h +++ b/src/bin/psql/variables.h @@ -90,6 +90,7 @@ bool DeleteVariable(VariableSpace space, const char *name); @@ -91,7 +91,7 @@ index 02d85b1bc2..8dc5c20ee8 100644 void PsqlVarEnumError(const char *name, const char *value, const char *suggestions); diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out -index 0c94144575..1ae81912c7 100644 +index 0c94144575af..1ae81912c734 100644 --- a/src/test/regress/expected/psql.out +++ b/src/test/regress/expected/psql.out @@ -84,6 +84,10 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_ @@ -106,7 +106,7 @@ index 0c94144575..1ae81912c7 100644 select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x 1 diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql -index 4a676c3119..7f8ab2e5c2 100644 +index 4a676c311955..7f8ab2e5c218 100644 --- a/src/test/regress/sql/psql.sql +++ b/src/test/regress/sql/psql.sql @@ -48,6 +48,9 @@ select 10 as test01, 20 as test02, 'Hello' as test03 \gset pref01_ @@ -119,6 +119,3 @@ index 4a676c3119..7f8ab2e5c2 100644 -- multiple backslash commands in one line select 1 as x, 2 as y \gset pref01_ \\ \echo :pref01_x select 3 as x, 4 as y \gset pref01_ \echo :pref01_x \echo :pref01_y --- -2.23.0 - 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 b0f1462..61b78d4 100644 --- a/postgresql.spec +++ b/postgresql.spec @@ -4,7 +4,7 @@ Name: postgresql Version: 10.5 -Release: 18 +Release: 19 Summary: PostgreSQL client programs License: PostgreSQL URL: http://www.postgresql.org/ @@ -42,6 +42,7 @@ Patch16: CVE-2020-25694-2.patch Patch17: CVE-2020-25694-3.patch Patch18: CVE-2020-25695.patch Patch19: CVE-2020-25696.patch +Patch20: 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 @@ -167,18 +168,7 @@ that want to run build-time testsuite against running PostgreSQL server. cd "$(dirname "%{SOURCE0}")" sha256sum -c %{SOURCE3} ) -%setup -q -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 +%autosetup -n %{name}-%{version} -p1 %build if [ x"`id -u`" = x0 ]; then @@ -443,6 +433,9 @@ find_lang_bins pltcl.lst pltcl %attr(-,postgres,postgres) %{_libdir}/pgsql/test %changelog +* Fri Feb 26 2021 wangyue - 10.5-19 +- Fix CVE-2021-20229 + * Tue Dec 8 2020 wangxiao - 10.5-18 - Fix CVE-2020-25694 CVE-2020-25695 CVE-2020-25696 -- Gitee