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