diff --git a/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch b/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch
new file mode 100644
index 0000000..6b26ec5
--- /dev/null
+++ b/SOURCES/rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch
@@ -0,0 +1,184 @@
+From f17aa638649fb8de730fecdbc906dc869b626ba5 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 16 Nov 2021 11:49:18 +0200
+Subject: [PATCH 1/2] Fix spurious %transfiletriggerpostun execution
+ (RhBug:2023311)
+
+If a package has multiple %transfiletriggerpostun triggers, any one
+of them matching would cause all of them to run, due to disconnect
+in the intel gathering stage: we'd gather all the headers with matching
+files into a lump, and then add any postun triggers found in them,
+but this loses the triggering file information and causes all postuns
+to run.
+
+The triggers need to be added while looping over the file matches,
+like runFileTriggers() does. Doing so actually simplifies the code.
+These should really be unified to use the same code, but leaving
+that exercise to another rainy day.
+---
+ lib/rpmtriggers.c | 64 +++++++++++++++++++++++------------------------
+ 1 file changed, 31 insertions(+), 33 deletions(-)
+
+diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c
+index 0827af0c2..dc457f7cc 100644
+--- a/lib/rpmtriggers.c
++++ b/lib/rpmtriggers.c
+@@ -97,19 +97,37 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs)
+     }
+ }
+ 
++static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter)
++{
++    int tix = 0;
++    rpmds ds;
++    rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0);
++
++    while ((ds = rpmdsFilterTi(triggers, tix))) {
++	if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) {
++	    struct rpmtd_s priorities;
++
++	    if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES,
++			&priorities, HEADERGET_MINMEM)) {
++		rpmtdSetIndex(&priorities, tix);
++		rpmtriggersAdd(ts->trigs2run, headerGetInstance(trigH),
++				tix, *rpmtdGetUint32(&priorities));
++	    }
++	}
++	rpmdsFree(ds);
++	tix++;
++    }
++    rpmdsFree(triggers);
++}
++
+ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te)
+ {
+-    rpmdbMatchIterator mi;
+     rpmdbIndexIterator ii;
+-    Header trigH;
+     const void *key;
+     size_t keylen;
+     rpmfiles files;
+-    rpmds rpmdsTriggers;
+-    rpmds rpmdsTrigger;
+ 
+     ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMDBI_TRANSFILETRIGGERNAME);
+-    mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_PACKAGES);
+     files = rpmteFiles(te);
+ 
+     /* Iterate over file triggers in rpmdb */
+@@ -121,39 +139,19 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te)
+ 	rpmfi fi = rpmfilesFindPrefix(files, pfx);
+ 	while (rpmfiNext(fi) >= 0) {
+ 	    if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) {
+-		/* If yes then store it */
+-		rpmdbAppendIterator(mi, rpmdbIndexIteratorPkgOffsets(ii),
+-				rpmdbIndexIteratorNumPkgs(ii));
+-		break;
++		unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii);
++		const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii);
++		/* Save any matching postun triggers */
++		for (int i = 0; i < npkg; i++) {
++		    Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]);
++		    addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN);
++		    headerFree(h);
++		}
+ 	    }
+ 	}
+ 	rpmfiFree(fi);
+     }
+     rpmdbIndexIteratorFree(ii);
+-
+-    if (rpmdbGetIteratorCount(mi)) {
+-	/* Filter triggers and save only trans postun triggers into ts */
+-	while ((trigH = rpmdbNextIterator(mi)) != NULL) {
+-	    int tix = 0;
+-	    rpmdsTriggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0);
+-	    while ((rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, tix))) {
+-		if ((rpmdsNext(rpmdsTrigger) >= 0) &&
+-		    (rpmdsFlags(rpmdsTrigger) & RPMSENSE_TRIGGERPOSTUN)) {
+-		    struct rpmtd_s priorities;
+-
+-		    headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES,
+-				&priorities, HEADERGET_MINMEM);
+-		    rpmtdSetIndex(&priorities, tix);
+-		    rpmtriggersAdd(ts->trigs2run, rpmdbGetIteratorOffset(mi),
+-				    tix, *rpmtdGetUint32(&priorities));
+-		}
+-		rpmdsFree(rpmdsTrigger);
+-		tix++;
+-	    }
+-	    rpmdsFree(rpmdsTriggers);
+-	}
+-    }
+-    rpmdbFreeIterator(mi);
+     rpmfilesFree(files);
+ }
+ 
+-- 
+2.35.1
+
+From e617e7c550d3523998707c55f96b37ede2c48c78 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Wed, 2 Feb 2022 13:46:23 +0200
+Subject: [PATCH 2/2] Really fix spurious %transfiletriggerpostun execution
+ (RhBug:2023311)
+
+Commit b3d672a5523dfec033160e5cc866432a0e808649 got the base reasoning
+in the ballpark but the code all wrong, introducing a severe performance
+regression without actually fixing what it claimed to.
+
+The missing incredient is actually comparing the current prefix with the
+triggers in matched package (trying to describe this makes my head
+spin): a package may have multiple triggers on multiple prefixes and
+we need to make sure we only execute triggers of this type, from this
+prefix.
+
+This stuff really needs more and better testcases.
+
+Fixes: b3d672a5523dfec033160e5cc866432a0e808649
+---
+ lib/rpmtriggers.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/lib/rpmtriggers.c b/lib/rpmtriggers.c
+index dc457f7cc..c652981be 100644
+--- a/lib/rpmtriggers.c
++++ b/lib/rpmtriggers.c
+@@ -97,14 +97,16 @@ static void rpmtriggersSortAndUniq(rpmtriggers trigs)
+     }
+ }
+ 
+-static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter)
++static void addTriggers(rpmts ts, Header trigH, rpmsenseFlags filter,
++			const char *prefix)
+ {
+     int tix = 0;
+     rpmds ds;
+     rpmds triggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0);
+ 
+     while ((ds = rpmdsFilterTi(triggers, tix))) {
+-	if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter)) {
++	if ((rpmdsNext(ds) >= 0) && (rpmdsFlags(ds) & filter) &&
++		strcmp(prefix, rpmdsN(ds)) == 0) {
+ 	    struct rpmtd_s priorities;
+ 
+ 	    if (headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES,
+@@ -141,12 +143,13 @@ void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te)
+ 	    if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) {
+ 		unsigned int npkg = rpmdbIndexIteratorNumPkgs(ii);
+ 		const unsigned int *offs = rpmdbIndexIteratorPkgOffsets(ii);
+-		/* Save any matching postun triggers */
++		/* Save any postun triggers matching this prefix */
+ 		for (int i = 0; i < npkg; i++) {
+ 		    Header h = rpmdbGetHeaderAt(rpmtsGetRdb(ts), offs[i]);
+-		    addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN);
++		    addTriggers(ts, h, RPMSENSE_TRIGGERPOSTUN, pfx);
+ 		    headerFree(h);
+ 		}
++		break;
+ 	    }
+ 	}
+ 	rpmfiFree(fi);
+-- 
+2.35.1
+
diff --git a/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch b/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch
new file mode 100644
index 0000000..ee12010
--- /dev/null
+++ b/SOURCES/rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch
@@ -0,0 +1,40 @@
+From 2e61e5846f8301f85da9d30281538ea736d96fd0 Mon Sep 17 00:00:00 2001
+From: Michal Domonkos <mdomonko@redhat.com>
+Date: Tue, 7 Dec 2021 08:08:37 +0100
+Subject: [PATCH] Skip recorded symlinks in --setperms (RhBug:1900662)
+
+If a package contains a symlink in the buildroot which is declared as a
+ghost or config file but is a regular file or directory on the system
+where it's installed, a --setperms call will reset its permissions to
+those of a symlink (777 on Linux), which almost certainly is not the
+correct thing to do.
+
+To fix that, just skip files that were recorded as symlinks.
+
+This is a special case of a general issue in --setperms; since file
+permission semantics may change depending on the file type, to stay on
+the safe side, any (ghost or config) file whose type changes after
+installation should probably be skipped.  However, symlinks are the most
+prominent case here, so let's just focus on that now and avoid adding
+too much cleverness to a popt alias (this got us into trouble not too
+long ago, see commits 38c2f6e and 0d83637).  We may revisit this in the
+eventual C implementation.
+---
+ rpmpopt.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/rpmpopt.in b/rpmpopt.in
+index 67fcabfb1..e130a5d05 100644
+--- a/rpmpopt.in
++++ b/rpmpopt.in
+@@ -44,6 +44,7 @@ rpm	alias --scripts --qf '\
+ 	--POPTdesc=$"list install/erase scriptlets from package(s)"
+ 
+ rpm	alias --setperms -q --qf '[\[ -L %{FILENAMES:shescape} \] || \
++        \[ -n %{FILELINKTOS:shescape} \] || \
+         ( \[ $((%{FILEFLAGS} & 2#1001000)) != 0 \] && \[ ! -e %{FILENAMES:shescape} \] ) || \
+         chmod %7{FILEMODES:octal} %{FILENAMES:shescape}\n]' \
+ 		   --pipe "grep -v \(none\) | grep '^. -L ' | sed 's/chmod .../chmod /' | sh" \
+-- 
+2.35.1
+
diff --git a/SPECS/rpm.spec b/SPECS/rpm.spec
index c1ae824..7515542 100644
--- a/SPECS/rpm.spec
+++ b/SPECS/rpm.spec
@@ -32,7 +32,7 @@
 
 %global rpmver 4.14.3
 #global snapver rc2
-%global rel 21
+%global rel 22
 
 %global srcver %{version}%{?snapver:-%{snapver}}
 %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x}
@@ -112,6 +112,8 @@ Patch158: rpm-4.14.3-imp-covscan-fixes.patch
 Patch159: rpm-4.14.3-add-path-query-option.patch
 Patch160: rpm-4.14.3-macroize-find-debuginfo-script-location.patch
 Patch161: rpm-4.14.3-validate-and-require-subkey-binding-sigs.patch
+Patch162: rpm-4.14.3-fix-spurious-transfiletriggerpostun-execution.patch
+Patch163: rpm-4.14.3-skip-recorded-symlinks-in-setperms.patch
 
 # Python 3 string API sanity
 Patch500: 0001-In-Python-3-return-all-our-string-data-as-surrogate-.patch
@@ -692,6 +694,10 @@ make check || cat tests/rpmtests.log
 %doc doc/librpm/html/*
 
 %changelog
+* Tue Feb 15 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-22
+- Fix spurious %transfiletriggerpostun execution (#2023693)
+- Skip recorded symlinks in --setperms (#1900662)
+
 * Mon Jan 10 2022 Michal Domonkos <mdomonko@redhat.com> - 4.14.3-21
 - Address covscan issues in binding sigs validation patch (#1958480)