+++ /dev/null
-From 24138933b97b055d486e8064b4a1721702442a9b Mon Sep 17 00:00:00 2001
-From: Florian Westphal <fw@strlen.de>
-Date: Wed, 9 Aug 2023 14:31:15 +0200
-Subject: netfilter: nf_tables: don't skip expired elements during walk
-
-From: Florian Westphal <fw@strlen.de>
-
-commit 24138933b97b055d486e8064b4a1721702442a9b upstream.
-
-There is an asymmetry between commit/abort and preparation phase if the
-following conditions are met:
-
-1. set is a verdict map ("1.2.3.4 : jump foo")
-2. timeouts are enabled
-
-In this case, following sequence is problematic:
-
-1. element E in set S refers to chain C
-2. userspace requests removal of set S
-3. kernel does a set walk to decrement chain->use count for all elements
- from preparation phase
-4. kernel does another set walk to remove elements from the commit phase
- (or another walk to do a chain->use increment for all elements from
- abort phase)
-
-If E has already expired in 1), it will be ignored during list walk, so its use count
-won't have been changed.
-
-Then, when set is culled, ->destroy callback will zap the element via
-nf_tables_set_elem_destroy(), but this function is only safe for
-elements that have been deactivated earlier from the preparation phase:
-lack of earlier deactivate removes the element but leaks the chain use
-count, which results in a WARN splat when the chain gets removed later,
-plus a leak of the nft_chain structure.
-
-Update pipapo_get() not to skip expired elements, otherwise flush
-command reports bogus ENOENT errors.
-
-Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
-Fixes: 8d8540c4f5e0 ("netfilter: nft_set_rbtree: add timeout support")
-Fixes: 9d0982927e79 ("netfilter: nft_hash: add support for timeouts")
-Signed-off-by: Florian Westphal <fw@strlen.de>
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- net/netfilter/nf_tables_api.c | 4 ++++
- net/netfilter/nft_set_hash.c | 2 --
- net/netfilter/nft_set_pipapo.c | 18 ++++++++++++------
- net/netfilter/nft_set_rbtree.c | 2 --
- 4 files changed, 16 insertions(+), 10 deletions(-)
-
---- a/net/netfilter/nf_tables_api.c
-+++ b/net/netfilter/nf_tables_api.c
-@@ -4911,8 +4911,12 @@ static int nf_tables_dump_setelem(const
- const struct nft_set_iter *iter,
- struct nft_set_elem *elem)
- {
-+ const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
- struct nft_set_dump_args *args;
-
-+ if (nft_set_elem_expired(ext))
-+ return 0;
-+
- args = container_of(iter, struct nft_set_dump_args, iter);
- return nf_tables_fill_setelem(args->skb, set, elem);
- }
---- a/net/netfilter/nft_set_hash.c
-+++ b/net/netfilter/nft_set_hash.c
-@@ -277,8 +277,6 @@ static void nft_rhash_walk(const struct
-
- if (iter->count < iter->skip)
- goto cont;
-- if (nft_set_elem_expired(&he->ext))
-- goto cont;
- if (!nft_set_elem_active(&he->ext, iter->genmask))
- goto cont;
-
---- a/net/netfilter/nft_set_pipapo.c
-+++ b/net/netfilter/nft_set_pipapo.c
-@@ -566,8 +566,7 @@ next_match:
- goto out;
-
- if (last) {
-- if (nft_set_elem_expired(&f->mt[b].e->ext) ||
-- (genmask &&
-+ if ((genmask &&
- !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
- goto next_match;
-
-@@ -601,8 +600,17 @@ out:
- static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
- const struct nft_set_elem *elem, unsigned int flags)
- {
-- return pipapo_get(net, set, (const u8 *)elem->key.val.data,
-- nft_genmask_cur(net));
-+ struct nft_pipapo_elem *ret;
-+
-+ ret = pipapo_get(net, set, (const u8 *)elem->key.val.data,
-+ nft_genmask_cur(net));
-+ if (IS_ERR(ret))
-+ return ret;
-+
-+ if (nft_set_elem_expired(&ret->ext))
-+ return ERR_PTR(-ENOENT);
-+
-+ return ret;
- }
-
- /**
-@@ -1981,8 +1989,6 @@ static void nft_pipapo_walk(const struct
- goto cont;
-
- e = f->mt[r].e;
-- if (nft_set_elem_expired(&e->ext))
-- goto cont;
-
- elem.priv = e;
-
---- a/net/netfilter/nft_set_rbtree.c
-+++ b/net/netfilter/nft_set_rbtree.c
-@@ -551,8 +551,6 @@ static void nft_rbtree_walk(const struct
-
- if (iter->count < iter->skip)
- goto cont;
-- if (nft_set_elem_expired(&rbe->ext))
-- goto cont;
- if (!nft_set_elem_active(&rbe->ext, iter->genmask))
- goto cont;
-
fallthrough;
default:
nf_tables_unbind_set(ctx, set, binding,
-@@ -5348,7 +5365,7 @@ void nft_set_elem_destroy(const struct n
+@@ -5344,7 +5361,7 @@ void nft_set_elem_destroy(const struct n
nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
kfree(elem);
}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
-@@ -5522,8 +5539,16 @@ static int nft_add_set_elem(struct nft_c
+@@ -5518,8 +5535,16 @@ static int nft_add_set_elem(struct nft_c
set->objtype, genmask);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
}
-@@ -5588,10 +5613,8 @@ static int nft_add_set_elem(struct nft_c
+@@ -5584,10 +5609,8 @@ static int nft_add_set_elem(struct nft_c
udata->len = ulen - 1;
nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
}
err = nft_set_elem_expr_setup(ctx, ext, expr);
if (err < 0)
-@@ -5647,14 +5670,14 @@ err_set_full:
+@@ -5643,14 +5666,14 @@ err_set_full:
err_element_clash:
kfree(trans);
err_elem_expr:
nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
err_parse_key:
nft_data_release(&elem.key.val, NFT_DATA_VALUE);
-@@ -5726,7 +5749,7 @@ void nft_data_hold(const struct nft_data
+@@ -5722,7 +5745,7 @@ void nft_data_hold(const struct nft_data
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
break;
}
}
-@@ -5741,7 +5764,7 @@ static void nft_setelem_data_activate(co
+@@ -5737,7 +5760,7 @@ static void nft_setelem_data_activate(co
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_hold(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
}
static void nft_setelem_data_deactivate(const struct net *net,
-@@ -5753,7 +5776,7 @@ static void nft_setelem_data_deactivate(
+@@ -5749,7 +5772,7 @@ static void nft_setelem_data_deactivate(
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_release(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
}
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
-@@ -6220,9 +6243,14 @@ static int nf_tables_newobj(struct net *
+@@ -6216,9 +6239,14 @@ static int nf_tables_newobj(struct net *
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
if (IS_ERR(obj)) {
-@@ -6256,7 +6284,7 @@ static int nf_tables_newobj(struct net *
+@@ -6252,7 +6280,7 @@ static int nf_tables_newobj(struct net *
goto err_obj_ht;
list_add_tail_rcu(&obj->list, &table->objects);
return 0;
err_obj_ht:
/* queued in transaction log */
-@@ -6272,6 +6300,9 @@ err_strdup:
+@@ -6268,6 +6296,9 @@ err_strdup:
kfree(obj);
err_init:
module_put(type->owner);
return err;
}
-@@ -6662,7 +6693,7 @@ void nf_tables_deactivate_flowtable(cons
+@@ -6658,7 +6689,7 @@ void nf_tables_deactivate_flowtable(cons
case NFT_TRANS_PREPARE:
case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE:
fallthrough;
default:
return;
-@@ -6999,9 +7030,14 @@ static int nf_tables_newflowtable(struct
+@@ -6995,9 +7026,14 @@ static int nf_tables_newflowtable(struct
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
flowtable->table = table;
flowtable->handle = nf_tables_alloc_handle(table);
-@@ -7056,7 +7092,6 @@ static int nf_tables_newflowtable(struct
+@@ -7052,7 +7088,6 @@ static int nf_tables_newflowtable(struct
goto err5;
list_add_tail_rcu(&flowtable->list, &table->flowtables);
return 0;
err5:
-@@ -7073,6 +7108,9 @@ err2:
+@@ -7069,6 +7104,9 @@ err2:
kfree(flowtable->name);
err1:
kfree(flowtable);
return err;
}
-@@ -8258,7 +8296,7 @@ static int nf_tables_commit(struct net *
+@@ -8254,7 +8292,7 @@ static int nf_tables_commit(struct net *
*/
if (nft_set_is_anonymous(nft_trans_set(trans)) &&
!list_empty(&nft_trans_set(trans)->bindings))
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_NEWSET, GFP_KERNEL);
-@@ -8442,7 +8480,7 @@ static int __nf_tables_abort(struct net
+@@ -8438,7 +8476,7 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
nft_chain_del(trans->ctx.chain);
nf_tables_unregister_hook(trans->ctx.net,
trans->ctx.table,
-@@ -8450,7 +8488,7 @@ static int __nf_tables_abort(struct net
+@@ -8446,7 +8484,7 @@ static int __nf_tables_abort(struct net
}
break;
case NFT_MSG_DELCHAIN:
nft_clear(trans->ctx.net, trans->ctx.chain);
nft_trans_destroy(trans);
break;
-@@ -8459,20 +8497,20 @@ static int __nf_tables_abort(struct net
+@@ -8455,20 +8493,20 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
if (nft_trans_set_bound(trans)) {
nft_trans_destroy(trans);
break;
-@@ -8480,7 +8518,7 @@ static int __nf_tables_abort(struct net
+@@ -8476,7 +8514,7 @@ static int __nf_tables_abort(struct net
list_del_rcu(&nft_trans_set(trans)->list);
break;
case NFT_MSG_DELSET:
nft_clear(trans->ctx.net, nft_trans_set(trans));
if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_activate(&trans->ctx, nft_trans_set(trans));
-@@ -8510,12 +8548,12 @@ static int __nf_tables_abort(struct net
+@@ -8506,12 +8544,12 @@ static int __nf_tables_abort(struct net
nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans));
nft_trans_destroy(trans);
} else {
nft_clear(trans->ctx.net, nft_trans_obj(trans));
nft_trans_destroy(trans);
break;
-@@ -8524,7 +8562,7 @@ static int __nf_tables_abort(struct net
+@@ -8520,7 +8558,7 @@ static int __nf_tables_abort(struct net
nft_unregister_flowtable_net_hooks(net,
&nft_trans_flowtable_hooks(trans));
} else {
list_del_rcu(&nft_trans_flowtable(trans)->list);
nft_unregister_flowtable_net_hooks(net,
&nft_trans_flowtable(trans)->hook_list);
-@@ -8535,7 +8573,7 @@ static int __nf_tables_abort(struct net
+@@ -8531,7 +8569,7 @@ static int __nf_tables_abort(struct net
list_splice(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
} else {
nft_clear(trans->ctx.net, nft_trans_flowtable(trans));
}
nft_trans_destroy(trans);
-@@ -8973,8 +9011,9 @@ static int nft_verdict_init(const struct
+@@ -8969,8 +9007,9 @@ static int nft_verdict_init(const struct
if (desc->flags & NFT_DATA_DESC_SETELEM &&
chain->flags & NFT_CHAIN_BINDING)
return -EINVAL;
data->verdict.chain = chain;
break;
}
-@@ -8992,7 +9031,7 @@ static void nft_verdict_uninit(const str
+@@ -8988,7 +9027,7 @@ static void nft_verdict_uninit(const str
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
break;
}
}
-@@ -9161,11 +9200,11 @@ int __nft_release_basechain(struct nft_c
+@@ -9157,11 +9196,11 @@ int __nft_release_basechain(struct nft_c
nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
list_del(&rule->list);
nf_tables_chain_destroy(ctx);
return 0;
-@@ -9205,18 +9244,18 @@ static void __nft_release_table(struct n
+@@ -9201,18 +9240,18 @@ static void __nft_release_table(struct n
ctx.chain = chain;
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
list_del(&rule->list);
if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_deactivate(&ctx, set);
-@@ -9224,13 +9263,13 @@ static void __nft_release_table(struct n
+@@ -9220,13 +9259,13 @@ static void __nft_release_table(struct n
}
list_for_each_entry_safe(obj, ne, &table->objects, list) {
nft_obj_del(obj);
x86-speculation-add-cpu_show_gds-prototype.patch
x86-move-gds_ucode_mitigated-declaration-to-header.patch
drm-nouveau-disp-revert-a-null-check-inside-nouveau_connector_get_modes.patch
-netfilter-nf_tables-don-t-skip-expired-elements-during-walk.patch
selftests-rseq-fix-build-with-undefined-__weak.patch
selftests-forwarding-add-a-helper-to-skip-test-when-using-veth-pairs.patch
selftests-forwarding-ethtool-skip-when-using-veth-pairs.patch
+++ /dev/null
-From 24138933b97b055d486e8064b4a1721702442a9b Mon Sep 17 00:00:00 2001
-From: Florian Westphal <fw@strlen.de>
-Date: Wed, 9 Aug 2023 14:31:15 +0200
-Subject: netfilter: nf_tables: don't skip expired elements during walk
-
-From: Florian Westphal <fw@strlen.de>
-
-commit 24138933b97b055d486e8064b4a1721702442a9b upstream.
-
-There is an asymmetry between commit/abort and preparation phase if the
-following conditions are met:
-
-1. set is a verdict map ("1.2.3.4 : jump foo")
-2. timeouts are enabled
-
-In this case, following sequence is problematic:
-
-1. element E in set S refers to chain C
-2. userspace requests removal of set S
-3. kernel does a set walk to decrement chain->use count for all elements
- from preparation phase
-4. kernel does another set walk to remove elements from the commit phase
- (or another walk to do a chain->use increment for all elements from
- abort phase)
-
-If E has already expired in 1), it will be ignored during list walk, so its use count
-won't have been changed.
-
-Then, when set is culled, ->destroy callback will zap the element via
-nf_tables_set_elem_destroy(), but this function is only safe for
-elements that have been deactivated earlier from the preparation phase:
-lack of earlier deactivate removes the element but leaks the chain use
-count, which results in a WARN splat when the chain gets removed later,
-plus a leak of the nft_chain structure.
-
-Update pipapo_get() not to skip expired elements, otherwise flush
-command reports bogus ENOENT errors.
-
-Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
-Fixes: 8d8540c4f5e0 ("netfilter: nft_set_rbtree: add timeout support")
-Fixes: 9d0982927e79 ("netfilter: nft_hash: add support for timeouts")
-Signed-off-by: Florian Westphal <fw@strlen.de>
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- net/netfilter/nf_tables_api.c | 4 ++++
- net/netfilter/nft_set_hash.c | 2 --
- net/netfilter/nft_set_pipapo.c | 18 ++++++++++++------
- net/netfilter/nft_set_rbtree.c | 2 --
- 4 files changed, 16 insertions(+), 10 deletions(-)
-
---- a/net/netfilter/nf_tables_api.c
-+++ b/net/netfilter/nf_tables_api.c
-@@ -5274,8 +5274,12 @@ static int nf_tables_dump_setelem(const
- const struct nft_set_iter *iter,
- struct nft_set_elem *elem)
- {
-+ const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
- struct nft_set_dump_args *args;
-
-+ if (nft_set_elem_expired(ext))
-+ return 0;
-+
- args = container_of(iter, struct nft_set_dump_args, iter);
- return nf_tables_fill_setelem(args->skb, set, elem);
- }
---- a/net/netfilter/nft_set_hash.c
-+++ b/net/netfilter/nft_set_hash.c
-@@ -278,8 +278,6 @@ static void nft_rhash_walk(const struct
-
- if (iter->count < iter->skip)
- goto cont;
-- if (nft_set_elem_expired(&he->ext))
-- goto cont;
- if (!nft_set_elem_active(&he->ext, iter->genmask))
- goto cont;
-
---- a/net/netfilter/nft_set_pipapo.c
-+++ b/net/netfilter/nft_set_pipapo.c
-@@ -566,8 +566,7 @@ next_match:
- goto out;
-
- if (last) {
-- if (nft_set_elem_expired(&f->mt[b].e->ext) ||
-- (genmask &&
-+ if ((genmask &&
- !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
- goto next_match;
-
-@@ -601,8 +600,17 @@ out:
- static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
- const struct nft_set_elem *elem, unsigned int flags)
- {
-- return pipapo_get(net, set, (const u8 *)elem->key.val.data,
-- nft_genmask_cur(net));
-+ struct nft_pipapo_elem *ret;
-+
-+ ret = pipapo_get(net, set, (const u8 *)elem->key.val.data,
-+ nft_genmask_cur(net));
-+ if (IS_ERR(ret))
-+ return ret;
-+
-+ if (nft_set_elem_expired(&ret->ext))
-+ return ERR_PTR(-ENOENT);
-+
-+ return ret;
- }
-
- /**
-@@ -2006,8 +2014,6 @@ static void nft_pipapo_walk(const struct
- goto cont;
-
- e = f->mt[r].e;
-- if (nft_set_elem_expired(&e->ext))
-- goto cont;
-
- elem.priv = e;
-
---- a/net/netfilter/nft_set_rbtree.c
-+++ b/net/netfilter/nft_set_rbtree.c
-@@ -552,8 +552,6 @@ static void nft_rbtree_walk(const struct
-
- if (iter->count < iter->skip)
- goto cont;
-- if (nft_set_elem_expired(&rbe->ext))
-- goto cont;
- if (!nft_set_elem_active(&rbe->ext, iter->genmask))
- goto cont;
-
fallthrough;
default:
nf_tables_unbind_set(ctx, set, binding,
-@@ -5803,7 +5818,7 @@ void nft_set_elem_destroy(const struct n
+@@ -5799,7 +5814,7 @@ void nft_set_elem_destroy(const struct n
nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
kfree(elem);
}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
-@@ -6294,8 +6309,16 @@ static int nft_add_set_elem(struct nft_c
+@@ -6290,8 +6305,16 @@ static int nft_add_set_elem(struct nft_c
set->objtype, genmask);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
err = nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
if (err < 0)
goto err_parse_key_end;
-@@ -6367,10 +6390,9 @@ static int nft_add_set_elem(struct nft_c
+@@ -6363,10 +6386,9 @@ static int nft_add_set_elem(struct nft_c
udata->len = ulen - 1;
nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
}
err = nft_set_elem_expr_setup(ctx, ext, expr_array, num_exprs);
if (err < 0)
goto err_elem_expr;
-@@ -6425,14 +6447,14 @@ err_set_full:
+@@ -6421,14 +6443,14 @@ err_set_full:
err_element_clash:
kfree(trans);
err_elem_expr:
nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
err_parse_key:
nft_data_release(&elem.key.val, NFT_DATA_VALUE);
-@@ -6511,7 +6533,7 @@ void nft_data_hold(const struct nft_data
+@@ -6507,7 +6529,7 @@ void nft_data_hold(const struct nft_data
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
break;
}
}
-@@ -6526,7 +6548,7 @@ static void nft_setelem_data_activate(co
+@@ -6522,7 +6544,7 @@ static void nft_setelem_data_activate(co
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_hold(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
}
static void nft_setelem_data_deactivate(const struct net *net,
-@@ -6538,7 +6560,7 @@ static void nft_setelem_data_deactivate(
+@@ -6534,7 +6556,7 @@ static void nft_setelem_data_deactivate(
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_release(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
}
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
-@@ -7073,9 +7095,14 @@ static int nf_tables_newobj(struct sk_bu
+@@ -7069,9 +7091,14 @@ static int nf_tables_newobj(struct sk_bu
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
if (IS_ERR(obj)) {
-@@ -7109,7 +7136,7 @@ static int nf_tables_newobj(struct sk_bu
+@@ -7105,7 +7132,7 @@ static int nf_tables_newobj(struct sk_bu
goto err_obj_ht;
list_add_tail_rcu(&obj->list, &table->objects);
return 0;
err_obj_ht:
/* queued in transaction log */
-@@ -7125,6 +7152,9 @@ err_strdup:
+@@ -7121,6 +7148,9 @@ err_strdup:
kfree(obj);
err_init:
module_put(type->owner);
return err;
}
-@@ -7515,7 +7545,7 @@ void nf_tables_deactivate_flowtable(cons
+@@ -7511,7 +7541,7 @@ void nf_tables_deactivate_flowtable(cons
case NFT_TRANS_PREPARE:
case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE:
fallthrough;
default:
return;
-@@ -7863,9 +7893,14 @@ static int nf_tables_newflowtable(struct
+@@ -7859,9 +7889,14 @@ static int nf_tables_newflowtable(struct
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
flowtable->table = table;
flowtable->handle = nf_tables_alloc_handle(table);
-@@ -7920,7 +7955,6 @@ static int nf_tables_newflowtable(struct
+@@ -7916,7 +7951,6 @@ static int nf_tables_newflowtable(struct
goto err5;
list_add_tail_rcu(&flowtable->list, &table->flowtables);
return 0;
err5:
-@@ -7937,6 +7971,9 @@ err2:
+@@ -7933,6 +7967,9 @@ err2:
kfree(flowtable->name);
err1:
kfree(flowtable);
return err;
}
-@@ -9173,7 +9210,7 @@ static int nf_tables_commit(struct net *
+@@ -9169,7 +9206,7 @@ static int nf_tables_commit(struct net *
*/
if (nft_set_is_anonymous(nft_trans_set(trans)) &&
!list_empty(&nft_trans_set(trans)->bindings))
}
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_NEWSET, GFP_KERNEL);
-@@ -9392,7 +9429,7 @@ static int __nf_tables_abort(struct net
+@@ -9388,7 +9425,7 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
nft_chain_del(trans->ctx.chain);
nf_tables_unregister_hook(trans->ctx.net,
trans->ctx.table,
-@@ -9400,7 +9437,7 @@ static int __nf_tables_abort(struct net
+@@ -9396,7 +9433,7 @@ static int __nf_tables_abort(struct net
}
break;
case NFT_MSG_DELCHAIN:
nft_clear(trans->ctx.net, trans->ctx.chain);
nft_trans_destroy(trans);
break;
-@@ -9409,7 +9446,7 @@ static int __nf_tables_abort(struct net
+@@ -9405,7 +9442,7 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
list_del_rcu(&nft_trans_rule(trans)->list);
nft_rule_expr_deactivate(&trans->ctx,
nft_trans_rule(trans),
-@@ -9418,7 +9455,7 @@ static int __nf_tables_abort(struct net
+@@ -9414,7 +9451,7 @@ static int __nf_tables_abort(struct net
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
break;
case NFT_MSG_DELRULE:
nft_clear(trans->ctx.net, nft_trans_rule(trans));
nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
-@@ -9431,7 +9468,7 @@ static int __nf_tables_abort(struct net
+@@ -9427,7 +9464,7 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
if (nft_trans_set_bound(trans)) {
nft_trans_destroy(trans);
break;
-@@ -9439,7 +9476,7 @@ static int __nf_tables_abort(struct net
+@@ -9435,7 +9472,7 @@ static int __nf_tables_abort(struct net
list_del_rcu(&nft_trans_set(trans)->list);
break;
case NFT_MSG_DELSET:
nft_clear(trans->ctx.net, nft_trans_set(trans));
if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_activate(&trans->ctx, nft_trans_set(trans));
-@@ -9482,12 +9519,12 @@ static int __nf_tables_abort(struct net
+@@ -9478,12 +9515,12 @@ static int __nf_tables_abort(struct net
nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans));
nft_trans_destroy(trans);
} else {
nft_clear(trans->ctx.net, nft_trans_obj(trans));
nft_trans_destroy(trans);
break;
-@@ -9496,7 +9533,7 @@ static int __nf_tables_abort(struct net
+@@ -9492,7 +9529,7 @@ static int __nf_tables_abort(struct net
nft_unregister_flowtable_net_hooks(net,
&nft_trans_flowtable_hooks(trans));
} else {
list_del_rcu(&nft_trans_flowtable(trans)->list);
nft_unregister_flowtable_net_hooks(net,
&nft_trans_flowtable(trans)->hook_list);
-@@ -9507,7 +9544,7 @@ static int __nf_tables_abort(struct net
+@@ -9503,7 +9540,7 @@ static int __nf_tables_abort(struct net
list_splice(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
} else {
nft_clear(trans->ctx.net, nft_trans_flowtable(trans));
}
nft_trans_destroy(trans);
-@@ -9960,8 +9997,9 @@ static int nft_verdict_init(const struct
+@@ -9956,8 +9993,9 @@ static int nft_verdict_init(const struct
if (desc->flags & NFT_DATA_DESC_SETELEM &&
chain->flags & NFT_CHAIN_BINDING)
return -EINVAL;
data->verdict.chain = chain;
break;
}
-@@ -9979,7 +10017,7 @@ static void nft_verdict_uninit(const str
+@@ -9975,7 +10013,7 @@ static void nft_verdict_uninit(const str
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
break;
}
}
-@@ -10148,11 +10186,11 @@ int __nft_release_basechain(struct nft_c
+@@ -10144,11 +10182,11 @@ int __nft_release_basechain(struct nft_c
nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
list_del(&rule->list);
nf_tables_chain_destroy(ctx);
return 0;
-@@ -10205,18 +10243,18 @@ static void __nft_release_table(struct n
+@@ -10201,18 +10239,18 @@ static void __nft_release_table(struct n
ctx.chain = chain;
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
list_del(&rule->list);
if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_deactivate(&ctx, set);
-@@ -10224,13 +10262,13 @@ static void __nft_release_table(struct n
+@@ -10220,13 +10258,13 @@ static void __nft_release_table(struct n
}
list_for_each_entry_safe(obj, ne, &table->objects, list) {
nft_obj_del(obj);
x86-speculation-add-cpu_show_gds-prototype.patch
x86-move-gds_ucode_mitigated-declaration-to-header.patch
drm-nouveau-disp-revert-a-null-check-inside-nouveau_connector_get_modes.patch
-netfilter-nf_tables-don-t-skip-expired-elements-during-walk.patch
selftests-rseq-fix-build-with-undefined-__weak.patch
selftests-forwarding-add-a-helper-to-skip-test-when-using-veth-pairs.patch
selftests-forwarding-ethtool-skip-when-using-veth-pairs.patch
+++ /dev/null
-From 24138933b97b055d486e8064b4a1721702442a9b Mon Sep 17 00:00:00 2001
-From: Florian Westphal <fw@strlen.de>
-Date: Wed, 9 Aug 2023 14:31:15 +0200
-Subject: netfilter: nf_tables: don't skip expired elements during walk
-
-From: Florian Westphal <fw@strlen.de>
-
-commit 24138933b97b055d486e8064b4a1721702442a9b upstream.
-
-There is an asymmetry between commit/abort and preparation phase if the
-following conditions are met:
-
-1. set is a verdict map ("1.2.3.4 : jump foo")
-2. timeouts are enabled
-
-In this case, following sequence is problematic:
-
-1. element E in set S refers to chain C
-2. userspace requests removal of set S
-3. kernel does a set walk to decrement chain->use count for all elements
- from preparation phase
-4. kernel does another set walk to remove elements from the commit phase
- (or another walk to do a chain->use increment for all elements from
- abort phase)
-
-If E has already expired in 1), it will be ignored during list walk, so its use count
-won't have been changed.
-
-Then, when set is culled, ->destroy callback will zap the element via
-nf_tables_set_elem_destroy(), but this function is only safe for
-elements that have been deactivated earlier from the preparation phase:
-lack of earlier deactivate removes the element but leaks the chain use
-count, which results in a WARN splat when the chain gets removed later,
-plus a leak of the nft_chain structure.
-
-Update pipapo_get() not to skip expired elements, otherwise flush
-command reports bogus ENOENT errors.
-
-Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
-Fixes: 8d8540c4f5e0 ("netfilter: nft_set_rbtree: add timeout support")
-Fixes: 9d0982927e79 ("netfilter: nft_hash: add support for timeouts")
-Signed-off-by: Florian Westphal <fw@strlen.de>
-Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- net/netfilter/nf_tables_api.c | 4 ++++
- net/netfilter/nft_set_hash.c | 2 --
- net/netfilter/nft_set_pipapo.c | 18 ++++++++++++------
- net/netfilter/nft_set_rbtree.c | 2 --
- 4 files changed, 16 insertions(+), 10 deletions(-)
-
---- a/net/netfilter/nf_tables_api.c
-+++ b/net/netfilter/nf_tables_api.c
-@@ -5371,8 +5371,12 @@ static int nf_tables_dump_setelem(const
- const struct nft_set_iter *iter,
- struct nft_set_elem *elem)
- {
-+ const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
- struct nft_set_dump_args *args;
-
-+ if (nft_set_elem_expired(ext))
-+ return 0;
-+
- args = container_of(iter, struct nft_set_dump_args, iter);
- return nf_tables_fill_setelem(args->skb, set, elem);
- }
---- a/net/netfilter/nft_set_hash.c
-+++ b/net/netfilter/nft_set_hash.c
-@@ -278,8 +278,6 @@ static void nft_rhash_walk(const struct
-
- if (iter->count < iter->skip)
- goto cont;
-- if (nft_set_elem_expired(&he->ext))
-- goto cont;
- if (!nft_set_elem_active(&he->ext, iter->genmask))
- goto cont;
-
---- a/net/netfilter/nft_set_pipapo.c
-+++ b/net/netfilter/nft_set_pipapo.c
-@@ -566,8 +566,7 @@ next_match:
- goto out;
-
- if (last) {
-- if (nft_set_elem_expired(&f->mt[b].e->ext) ||
-- (genmask &&
-+ if ((genmask &&
- !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
- goto next_match;
-
-@@ -601,8 +600,17 @@ out:
- static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
- const struct nft_set_elem *elem, unsigned int flags)
- {
-- return pipapo_get(net, set, (const u8 *)elem->key.val.data,
-- nft_genmask_cur(net));
-+ struct nft_pipapo_elem *ret;
-+
-+ ret = pipapo_get(net, set, (const u8 *)elem->key.val.data,
-+ nft_genmask_cur(net));
-+ if (IS_ERR(ret))
-+ return ret;
-+
-+ if (nft_set_elem_expired(&ret->ext))
-+ return ERR_PTR(-ENOENT);
-+
-+ return ret;
- }
-
- /**
-@@ -2006,8 +2014,6 @@ static void nft_pipapo_walk(const struct
- goto cont;
-
- e = f->mt[r].e;
-- if (nft_set_elem_expired(&e->ext))
-- goto cont;
-
- elem.priv = e;
-
---- a/net/netfilter/nft_set_rbtree.c
-+++ b/net/netfilter/nft_set_rbtree.c
-@@ -552,8 +552,6 @@ static void nft_rbtree_walk(const struct
-
- if (iter->count < iter->skip)
- goto cont;
-- if (nft_set_elem_expired(&rbe->ext))
-- goto cont;
- if (!nft_set_elem_active(&rbe->ext, iter->genmask))
- goto cont;
-
fallthrough;
default:
nf_tables_unbind_set(ctx, set, binding,
-@@ -5937,7 +5952,7 @@ void nft_set_elem_destroy(const struct n
+@@ -5933,7 +5948,7 @@ void nft_set_elem_destroy(const struct n
nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
kfree(elem);
}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
-@@ -6439,8 +6454,16 @@ static int nft_add_set_elem(struct nft_c
+@@ -6435,8 +6450,16 @@ static int nft_add_set_elem(struct nft_c
set->objtype, genmask);
if (IS_ERR(obj)) {
err = PTR_ERR(obj);
err = nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
if (err < 0)
goto err_parse_key_end;
-@@ -6509,10 +6532,9 @@ static int nft_add_set_elem(struct nft_c
+@@ -6505,10 +6528,9 @@ static int nft_add_set_elem(struct nft_c
if (flags)
*nft_set_ext_flags(ext) = flags;
if (ulen > 0) {
if (nft_set_ext_check(&tmpl, NFT_SET_EXT_USERDATA, ulen) < 0) {
err = -EINVAL;
-@@ -6577,12 +6599,13 @@ err_element_clash:
+@@ -6573,12 +6595,13 @@ err_element_clash:
kfree(trans);
err_elem_free:
nf_tables_set_elem_destroy(ctx, set, elem.priv);
nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
err_parse_key:
nft_data_release(&elem.key.val, NFT_DATA_VALUE);
-@@ -6663,7 +6686,7 @@ void nft_data_hold(const struct nft_data
+@@ -6659,7 +6682,7 @@ void nft_data_hold(const struct nft_data
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
break;
}
}
-@@ -6678,7 +6701,7 @@ static void nft_setelem_data_activate(co
+@@ -6674,7 +6697,7 @@ static void nft_setelem_data_activate(co
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_hold(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
}
static void nft_setelem_data_deactivate(const struct net *net,
-@@ -6690,7 +6713,7 @@ static void nft_setelem_data_deactivate(
+@@ -6686,7 +6709,7 @@ static void nft_setelem_data_deactivate(
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_release(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
}
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
-@@ -7229,9 +7252,14 @@ static int nf_tables_newobj(struct sk_bu
+@@ -7225,9 +7248,14 @@ static int nf_tables_newobj(struct sk_bu
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
if (IS_ERR(obj)) {
-@@ -7265,7 +7293,7 @@ static int nf_tables_newobj(struct sk_bu
+@@ -7261,7 +7289,7 @@ static int nf_tables_newobj(struct sk_bu
goto err_obj_ht;
list_add_tail_rcu(&obj->list, &table->objects);
return 0;
err_obj_ht:
/* queued in transaction log */
-@@ -7281,6 +7309,9 @@ err_strdup:
+@@ -7277,6 +7305,9 @@ err_strdup:
kfree(obj);
err_init:
module_put(type->owner);
return err;
}
-@@ -7671,7 +7702,7 @@ void nf_tables_deactivate_flowtable(cons
+@@ -7667,7 +7698,7 @@ void nf_tables_deactivate_flowtable(cons
case NFT_TRANS_PREPARE:
case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE:
fallthrough;
default:
return;
-@@ -8019,9 +8050,14 @@ static int nf_tables_newflowtable(struct
+@@ -8015,9 +8046,14 @@ static int nf_tables_newflowtable(struct
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
flowtable->table = table;
flowtable->handle = nf_tables_alloc_handle(table);
-@@ -8076,7 +8112,6 @@ static int nf_tables_newflowtable(struct
+@@ -8072,7 +8108,6 @@ static int nf_tables_newflowtable(struct
goto err5;
list_add_tail_rcu(&flowtable->list, &table->flowtables);
return 0;
err5:
-@@ -8093,6 +8128,9 @@ err2:
+@@ -8089,6 +8124,9 @@ err2:
kfree(flowtable->name);
err1:
kfree(flowtable);
return err;
}
-@@ -9378,7 +9416,7 @@ static int nf_tables_commit(struct net *
+@@ -9374,7 +9412,7 @@ static int nf_tables_commit(struct net *
*/
if (nft_set_is_anonymous(nft_trans_set(trans)) &&
!list_empty(&nft_trans_set(trans)->bindings))
}
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_NEWSET, GFP_KERNEL);
-@@ -9597,7 +9635,7 @@ static int __nf_tables_abort(struct net
+@@ -9593,7 +9631,7 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
nft_chain_del(trans->ctx.chain);
nf_tables_unregister_hook(trans->ctx.net,
trans->ctx.table,
-@@ -9605,7 +9643,7 @@ static int __nf_tables_abort(struct net
+@@ -9601,7 +9639,7 @@ static int __nf_tables_abort(struct net
}
break;
case NFT_MSG_DELCHAIN:
nft_clear(trans->ctx.net, trans->ctx.chain);
nft_trans_destroy(trans);
break;
-@@ -9614,7 +9652,7 @@ static int __nf_tables_abort(struct net
+@@ -9610,7 +9648,7 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
list_del_rcu(&nft_trans_rule(trans)->list);
nft_rule_expr_deactivate(&trans->ctx,
nft_trans_rule(trans),
-@@ -9623,7 +9661,7 @@ static int __nf_tables_abort(struct net
+@@ -9619,7 +9657,7 @@ static int __nf_tables_abort(struct net
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
break;
case NFT_MSG_DELRULE:
nft_clear(trans->ctx.net, nft_trans_rule(trans));
nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
if (trans->ctx.chain->flags & NFT_CHAIN_HW_OFFLOAD)
-@@ -9636,7 +9674,7 @@ static int __nf_tables_abort(struct net
+@@ -9632,7 +9670,7 @@ static int __nf_tables_abort(struct net
nft_trans_destroy(trans);
break;
}
if (nft_trans_set_bound(trans)) {
nft_trans_destroy(trans);
break;
-@@ -9644,7 +9682,7 @@ static int __nf_tables_abort(struct net
+@@ -9640,7 +9678,7 @@ static int __nf_tables_abort(struct net
list_del_rcu(&nft_trans_set(trans)->list);
break;
case NFT_MSG_DELSET:
nft_clear(trans->ctx.net, nft_trans_set(trans));
if (nft_trans_set(trans)->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_activate(&trans->ctx, nft_trans_set(trans));
-@@ -9687,12 +9725,12 @@ static int __nf_tables_abort(struct net
+@@ -9683,12 +9721,12 @@ static int __nf_tables_abort(struct net
nft_obj_destroy(&trans->ctx, nft_trans_obj_newobj(trans));
nft_trans_destroy(trans);
} else {
nft_clear(trans->ctx.net, nft_trans_obj(trans));
nft_trans_destroy(trans);
break;
-@@ -9701,7 +9739,7 @@ static int __nf_tables_abort(struct net
+@@ -9697,7 +9735,7 @@ static int __nf_tables_abort(struct net
nft_unregister_flowtable_net_hooks(net,
&nft_trans_flowtable_hooks(trans));
} else {
list_del_rcu(&nft_trans_flowtable(trans)->list);
nft_unregister_flowtable_net_hooks(net,
&nft_trans_flowtable(trans)->hook_list);
-@@ -9712,7 +9750,7 @@ static int __nf_tables_abort(struct net
+@@ -9708,7 +9746,7 @@ static int __nf_tables_abort(struct net
list_splice(&nft_trans_flowtable_hooks(trans),
&nft_trans_flowtable(trans)->hook_list);
} else {
nft_clear(trans->ctx.net, nft_trans_flowtable(trans));
}
nft_trans_destroy(trans);
-@@ -10165,8 +10203,9 @@ static int nft_verdict_init(const struct
+@@ -10161,8 +10199,9 @@ static int nft_verdict_init(const struct
if (desc->flags & NFT_DATA_DESC_SETELEM &&
chain->flags & NFT_CHAIN_BINDING)
return -EINVAL;
data->verdict.chain = chain;
break;
}
-@@ -10184,7 +10223,7 @@ static void nft_verdict_uninit(const str
+@@ -10180,7 +10219,7 @@ static void nft_verdict_uninit(const str
case NFT_JUMP:
case NFT_GOTO:
chain = data->verdict.chain;
break;
}
}
-@@ -10353,11 +10392,11 @@ int __nft_release_basechain(struct nft_c
+@@ -10349,11 +10388,11 @@ int __nft_release_basechain(struct nft_c
nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
list_del(&rule->list);
nf_tables_chain_destroy(ctx);
return 0;
-@@ -10410,18 +10449,18 @@ static void __nft_release_table(struct n
+@@ -10406,18 +10445,18 @@ static void __nft_release_table(struct n
ctx.chain = chain;
list_for_each_entry_safe(rule, nr, &chain->rules, list) {
list_del(&rule->list);
if (set->flags & (NFT_SET_MAP | NFT_SET_OBJECT))
nft_map_deactivate(&ctx, set);
-@@ -10429,13 +10468,13 @@ static void __nft_release_table(struct n
+@@ -10425,13 +10464,13 @@ static void __nft_release_table(struct n
}
list_for_each_entry_safe(obj, ne, &table->objects, list) {
nft_obj_del(obj);
x86-speculation-add-cpu_show_gds-prototype.patch
x86-move-gds_ucode_mitigated-declaration-to-header.patch
drm-nouveau-disp-revert-a-null-check-inside-nouveau_connector_get_modes.patch
-netfilter-nf_tables-don-t-skip-expired-elements-during-walk.patch
iio-core-prevent-invalid-memory-access-when-there-is-no-parent.patch
interconnect-qcom-add-support-for-mask-based-bcms.patch
interconnect-qcom-sm8450-add-enable_mask-for-bcm-nodes.patch