Blame SOURCES/CVE-2023-32233-full.patch

b9644d
From 432fd316587463b7ecb99dd24807776bea6f3c22 Mon Sep 17 00:00:00 2001
b9644d
From: Joe Lawrence <joe.lawrence@redhat.com>
b9644d
Date: Thu, 10 Aug 2023 15:16:18 -0400
b9644d
Subject: [KPATCH CVE-2023-32233] kpatch fixes for CVE-2023-32233
b9644d
b9644d
Kernels:
b9644d
3.10.0-1160.83.1.el7
b9644d
3.10.0-1160.88.1.el7
b9644d
3.10.0-1160.90.1.el7
b9644d
3.10.0-1160.92.1.el7
b9644d
b9644d
b9644d
Kpatch-MR: https://gitlab.com/redhat/prdsc/rhel/src/kpatch/rhel-7/-/merge_requests/58
b9644d
Approved-by: Yannick Cote (@ycote1)
b9644d
Changes since last build:
b9644d
[x86_64]:
b9644d
cls_u32.o: changed function: u32_set_parms.isra.21
b9644d
nf_tables_api.o: changed function: nf_tables_newsetelem
b9644d
nf_tables_api.o: changed function: nf_tables_set_lookup
b9644d
nf_tables_api.o: changed function: nf_tables_set_lookup_byid
b9644d
nft_byteorder.o: changed function: nft_byteorder_eval
b9644d
nft_dynset.o: changed function: nft_dynset_init
b9644d
nft_lookup.o: changed function: nft_lookup_init
b9644d
b9644d
[ppc64le]:
b9644d
cls_u32.o: changed function: u32_set_parms.isra.21
b9644d
nf_tables_api.o: changed function: nf_tables_delset
b9644d
nf_tables_api.o: changed function: nf_tables_dump_set
b9644d
nf_tables_api.o: changed function: nf_tables_getset
b9644d
nf_tables_api.o: changed function: nf_tables_getsetelem
b9644d
nf_tables_api.o: changed function: nf_tables_newsetelem
b9644d
nf_tables_api.o: changed function: nf_tables_set_lookup
b9644d
nf_tables_api.o: changed function: nf_tables_set_lookup_byid
b9644d
nft_byteorder.o: changed function: nft_byteorder_eval
b9644d
nft_dynset.o: changed function: nft_dynset_init
b9644d
nft_lookup.o: changed function: nft_lookup_init
b9644d
b9644d
---------------------------
b9644d
b9644d
Modifications:
b9644d
- Use KLP_CVE_2023_32233 shadow variable for set->removed
b9644d
- For ppc64le, add -fno-optimize-sibling-calls attribute for
b9644d
  nf_tables_api.c :: nf_tables_getsetelem()
b9644d
b9644d
commit cde71785485c5f12520ed90f93e3e2f78270a7b7
b9644d
Author: Florian Westphal <fwestpha@redhat.com>
b9644d
Date:   Thu Jul 13 16:10:39 2023 +0200
b9644d
b9644d
    netfilter: nf_tables: do not allow SET_ID to refer to another table
b9644d
b9644d
    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2196159
b9644d
    Upstream Status: commit 470ee20e069a6
b9644d
b9644d
    Conflicts:
b9644d
    net/netfilter/nf_tables_api.c
b9644d
b9644d
    We lack commit 6ab3443e9e796 ("netfilter: nf_tables: pass ctx to nf_tables_expr_destroy()"),
b9644d
    which added the "nft_table" pointer to struct nft_set.
b9644d
    We can't easily pick this one up becaue it makes the kabi checker trip over
b9644d
    the nft_set layout change, and RH_KABI_EXTEND can't be used at the structures
b9644d
    end because nft_set last member is a VLA.
b9644d
b9644d
    Fortunately we can work around it by changing
b9644d
    "set->table" to "trans->ctx.table", we only need this check in the transaction phase.
b9644d
b9644d
    commit 470ee20e069a6d05ae549f7d0ef2bdbcee6a81b2
b9644d
    Author: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
b9644d
    Date:   Tue Aug 9 14:01:46 2022 -0300
b9644d
b9644d
        netfilter: nf_tables: do not allow SET_ID to refer to another table
b9644d
b9644d
        When doing lookups for sets on the same batch by using its ID, a set from a
b9644d
        different table can be used.
b9644d
b9644d
        Then, when the table is removed, a reference to the set may be kept after
b9644d
        the set is freed, leading to a potential use-after-free.
b9644d
b9644d
        When looking for sets by ID, use the table that was used for the lookup by
b9644d
        name, and only return sets belonging to that same table.
b9644d
b9644d
        This fixes CVE-2022-2586, also reported as ZDI-CAN-17470.
b9644d
b9644d
        Reported-by: Team Orca of Sea Security (@seasecresponse)
b9644d
        Fixes: 958bee14d071 ("netfilter: nf_tables: use new transaction infrastructure to handle sets")
b9644d
        Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
b9644d
        Cc: <stable@vger.kernel.org>
b9644d
        Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
b9644d
b9644d
    Signed-off-by: Florian Westphal <fwestpha@redhat.com>
b9644d
b9644d
commit 6a38a385344448ab2f4e68e833fcf9a7e3d62128
b9644d
Author: Florian Westphal <fwestpha@redhat.com>
b9644d
Date:   Thu Jul 13 16:11:38 2023 +0200
b9644d
b9644d
    netfilter: nf_tables: skip deactivated anonymous sets during lookups
b9644d
b9644d
    Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2196159
b9644d
    Upstream Status: RHEL7 only
b9644d
    CVE: CVE-2023-32233
b9644d
b9644d
    The fix for the above CVE was incomplete in *RHEL7*.
b9644d
    its not enough to check if the set is scheduled for removal when
b9644d
    an element is supposed to be deleted, this check needs to be done
b9644d
    for all other element operations too, e.g. when an element is
b9644d
    supposed to be *added* to a set.
b9644d
b9644d
    Move the check to the two functions that do the set lookup.
b9644d
    sets that are scheduled for removal/pending in the transaction
b9644d
    are no longer found if they have the "removed" bit set.
b9644d
b9644d
    Fixes: ffb7eb4b21c69 ("netfilter: nf_tables: deactivate anonymous set from preparation phase")
b9644d
    Reported-by: Phil Sutter <psutter@redhat.com>
b9644d
    Signed-off-by: Florian Westphal <fwestpha@redhat.com>
b9644d
b9644d
Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com>
b9644d
---
b9644d
 include/net/netfilter/nf_tables.h |  1 +
b9644d
 net/netfilter/nf_tables_api.c     | 40 +++++++++++++++++++++++--------
b9644d
 net/netfilter/nft_dynset.c        |  1 +
b9644d
 net/netfilter/nft_lookup.c        |  1 +
b9644d
 4 files changed, 33 insertions(+), 10 deletions(-)
b9644d
b9644d
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
b9644d
index 2ea0683b5860..3e356aba44ea 100644
b9644d
--- a/include/net/netfilter/nf_tables.h
b9644d
+++ b/include/net/netfilter/nf_tables.h
b9644d
@@ -390,6 +390,7 @@ static inline struct nft_set *nft_set_container_of(const void *priv)
b9644d
 struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
b9644d
 				     const struct nlattr *nla);
b9644d
 struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
b9644d
+					  const struct nft_table *table,
b9644d
 					  const struct nlattr *nla);
b9644d
 
b9644d
 static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
b9644d
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
b9644d
index feff3b92a617..ed8a787ac400 100644
b9644d
--- a/net/netfilter/nf_tables_api.c
b9644d
+++ b/net/netfilter/nf_tables_api.c
b9644d
@@ -2450,22 +2450,45 @@ struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
b9644d
 		return ERR_PTR(-EINVAL);
b9644d
 
b9644d
 	list_for_each_entry(set, &table->sets, list) {
b9644d
-		if (!nla_strcmp(nla, set->name))
b9644d
-			return set;
b9644d
+
b9644d
+		u16 *klp_removed;
b9644d
+
b9644d
+		klp_removed = klp_shadow_get(set, KLP_CVE_2023_32233);
b9644d
+		if (klp_removed) {
b9644d
+			if (!nla_strcmp(nla, set->name) && !(*klp_removed))
b9644d
+				return set;
b9644d
+		} else {
b9644d
+			if (!nla_strcmp(nla, set->name))
b9644d
+				return set;
b9644d
+		}
b9644d
 	}
b9644d
 	return ERR_PTR(-ENOENT);
b9644d
 }
b9644d
 
b9644d
 struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
b9644d
+					  const struct nft_table *table,
b9644d
 					  const struct nlattr *nla)
b9644d
 {
b9644d
 	struct nft_trans *trans;
b9644d
 	u32 id = ntohl(nla_get_be32(nla));
b9644d
 
b9644d
 	list_for_each_entry(trans, &net->nft.commit_list, list) {
b9644d
-		if (trans->msg_type == NFT_MSG_NEWSET &&
b9644d
-		    id == nft_trans_set_id(trans))
b9644d
-			return nft_trans_set(trans);
b9644d
+		if (trans->msg_type == NFT_MSG_NEWSET) {
b9644d
+			struct nft_set *set = nft_trans_set(trans);
b9644d
+			u16 *klp_removed;
b9644d
+			klp_removed = klp_shadow_get(set, KLP_CVE_2023_32233);
b9644d
+
b9644d
+			if (klp_removed) {
b9644d
+				if (id == nft_trans_set_id(trans) &&
b9644d
+				    trans->ctx.table == table &&
b9644d
+				    !(*klp_removed))
b9644d
+					return set;
b9644d
+			} else {
b9644d
+				if (id == nft_trans_set_id(trans) &&
b9644d
+				    trans->ctx.table == table)
b9644d
+					return set;
b9644d
+			}
b9644d
+		}
b9644d
 	}
b9644d
 	return ERR_PTR(-ENOENT);
b9644d
 }
b9644d
@@ -3335,6 +3358,7 @@ nla_put_failure:
b9644d
 	return -ENOSPC;
b9644d
 }
b9644d
 
b9644d
+__attribute__((optimize("-fno-optimize-sibling-calls")))
b9644d
 static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
b9644d
 				const struct nlmsghdr *nlh,
b9644d
 				const struct nlattr * const nla[])
b9644d
@@ -3680,6 +3704,7 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
b9644d
 	if (IS_ERR(set)) {
b9644d
 		if (nla[NFTA_SET_ELEM_LIST_SET_ID]) {
b9644d
 			set = nf_tables_set_lookup_byid(net,
b9644d
+					ctx.table,
b9644d
 					nla[NFTA_SET_ELEM_LIST_SET_ID]);
b9644d
 		}
b9644d
 		if (IS_ERR(set))
b9644d
@@ -3791,7 +3816,6 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
b9644d
 	struct nft_set *set;
b9644d
 	struct nft_ctx ctx;
b9644d
 	int rem, err = 0;
b9644d
-	u16 *klp_removed;
b9644d
 
b9644d
 	err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla);
b9644d
 	if (err < 0)
b9644d
@@ -3803,10 +3827,6 @@ static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
b9644d
 	if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
b9644d
 		return -EBUSY;
b9644d
 
b9644d
-	klp_removed = klp_shadow_get(set, KLP_CVE_2023_32233);
b9644d
-	if (klp_removed && *klp_removed)
b9644d
-		return -ENOENT;
b9644d
-
b9644d
 	if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL) {
b9644d
 		struct nft_set_dump_args args = {
b9644d
 			.iter	= {
b9644d
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
b9644d
index 4d6d3af26a5b..211e5beab83f 100644
b9644d
--- a/net/netfilter/nft_dynset.c
b9644d
+++ b/net/netfilter/nft_dynset.c
b9644d
@@ -119,6 +119,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
b9644d
 	if (IS_ERR(set)) {
b9644d
 		if (tb[NFTA_DYNSET_SET_ID])
b9644d
 			set = nf_tables_set_lookup_byid(ctx->net,
b9644d
+							ctx->table,
b9644d
 							tb[NFTA_DYNSET_SET_ID]);
b9644d
 		if (IS_ERR(set))
b9644d
 			return PTR_ERR(set);
b9644d
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
b9644d
index ab98a5cb7128..63eff5caae5a 100644
b9644d
--- a/net/netfilter/nft_lookup.c
b9644d
+++ b/net/netfilter/nft_lookup.c
b9644d
@@ -74,6 +74,7 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
b9644d
 	if (IS_ERR(set)) {
b9644d
 		if (tb[NFTA_LOOKUP_SET_ID]) {
b9644d
 			set = nf_tables_set_lookup_byid(ctx->net,
b9644d
+							ctx->table,
b9644d
 							tb[NFTA_LOOKUP_SET_ID]);
b9644d
 		}
b9644d
 		if (IS_ERR(set))
b9644d
-- 
b9644d
2.40.1
b9644d
b9644d