From: Greg Kroah-Hartman Date: Thu, 9 Jul 2026 14:33:58 +0000 (+0200) Subject: 5.15-stable patches X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=fb338f8a104f71786dae0b2bb5fc9c03198eb552;p=thirdparty%2Fkernel%2Fstable-queue.git 5.15-stable patches added patches: mm-fix-copy_from_user_nofault.patch netfilter-nf_tables-restore-set-elements-when-delete-set-fails.patch --- diff --git a/queue-5.15/mm-fix-copy_from_user_nofault.patch b/queue-5.15/mm-fix-copy_from_user_nofault.patch new file mode 100644 index 0000000000..1881c4df45 --- /dev/null +++ b/queue-5.15/mm-fix-copy_from_user_nofault.patch @@ -0,0 +1,84 @@ +From d319f344561de23e810515d109c7278919bff7b0 Mon Sep 17 00:00:00 2001 +From: Alexei Starovoitov +Date: Mon, 10 Apr 2023 19:43:44 +0200 +Subject: mm: Fix copy_from_user_nofault(). + +From: Alexei Starovoitov + +commit d319f344561de23e810515d109c7278919bff7b0 upstream. + +There are several issues with copy_from_user_nofault(): + +- access_ok() is designed for user context only and for that reason +it has WARN_ON_IN_IRQ() which triggers when bpf, kprobe, eprobe +and perf on ppc are calling it from irq. + +- it's missing nmi_uaccess_okay() which is a nop on all architectures +except x86 where it's required. +The comment in arch/x86/mm/tlb.c explains the details why it's necessary. +Calling copy_from_user_nofault() from bpf, [ke]probe without this check is not safe. + +- __copy_from_user_inatomic() under CONFIG_HARDENED_USERCOPY is calling +check_object_size()->__check_object_size()->check_heap_object()->find_vmap_area()->spin_lock() +which is not safe to do from bpf, [ke]probe and perf due to potential deadlock. + +Fix all three issues. At the end the copy_from_user_nofault() becomes +equivalent to copy_from_user_nmi() from safety point of view with +a difference in the return value. + +Reported-by: Hsin-Wei Hung +Signed-off-by: Alexei Starovoitov +Signed-off-by: Florian Lehner +Tested-by: Hsin-Wei Hung +Tested-by: Florian Lehner +Link: https://lore.kernel.org/r/20230410174345.4376-2-dev@der-flo.net +Signed-off-by: Alexei Starovoitov +[ merge conflict fixes: + copy_from_user_nofault: caused by force_uaccess_begin and + force_uaccess_end functions. moved the code around to call those + functions in the same way after the additional checks. + + check_heap_object: completely different implementation in 5.15.y. + removed any changes from this commit as the current implementation + doesn't call the same lock which caused problems. ] +Signed-off-by: Jakov Novak +Signed-off-by: Greg Kroah-Hartman +--- + mm/maccess.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +--- a/mm/maccess.c ++++ b/mm/maccess.c +@@ -5,6 +5,7 @@ + #include + #include + #include ++#include + + bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src, + size_t size) +@@ -221,13 +222,18 @@ long strncpy_from_kernel_nofault(char *d + long copy_from_user_nofault(void *dst, const void __user *src, size_t size) + { + long ret = -EFAULT; +- mm_segment_t old_fs = force_uaccess_begin(); ++ mm_segment_t old_fs; + +- if (access_ok(src, size)) { +- pagefault_disable(); +- ret = __copy_from_user_inatomic(dst, src, size); +- pagefault_enable(); +- } ++ if (!__access_ok(src, size)) ++ return ret; ++ ++ if (!nmi_uaccess_okay()) ++ return ret; ++ ++ old_fs = force_uaccess_begin(); ++ pagefault_disable(); ++ ret = __copy_from_user_inatomic(dst, src, size); ++ pagefault_enable(); + force_uaccess_end(old_fs); + + if (ret) diff --git a/queue-5.15/netfilter-nf_tables-restore-set-elements-when-delete-set-fails.patch b/queue-5.15/netfilter-nf_tables-restore-set-elements-when-delete-set-fails.patch new file mode 100644 index 0000000000..780a838a52 --- /dev/null +++ b/queue-5.15/netfilter-nf_tables-restore-set-elements-when-delete-set-fails.patch @@ -0,0 +1,313 @@ +From e79b47a8615d42c68aaeb68971593333667382ed Mon Sep 17 00:00:00 2001 +From: Pablo Neira Ayuso +Date: Wed, 17 Apr 2024 17:43:11 +0200 +Subject: netfilter: nf_tables: restore set elements when delete set fails + +From: Pablo Neira Ayuso + +commit e79b47a8615d42c68aaeb68971593333667382ed upstream. + +From abort path, nft_mapelem_activate() needs to restore refcounters to +the original state. Currently, it uses the set->ops->walk() to iterate +over these set elements. The existing set iterator skips inactive +elements in the next generation, this does not work from the abort path +to restore the original state since it has to skip active elements +instead (not inactive ones). + +This patch moves the check for inactive elements to the set iterator +callback, then it reverses the logic for the .activate case which +needs to skip active elements. + +Toggle next generation bit for elements when delete set command is +invoked and call nft_clear() from .activate (abort) path to restore the +next generation bit. + +The splat below shows an object in mappings memleak: + +[43929.457523] ------------[ cut here ]------------ +[43929.457532] WARNING: CPU: 0 PID: 1139 at include/net/netfilter/nf_tables.h:1237 nft_setelem_data_deactivate+0xe4/0xf0 [nf_tables] +[...] +[43929.458014] RIP: 0010:nft_setelem_data_deactivate+0xe4/0xf0 [nf_tables] +[43929.458076] Code: 83 f8 01 77 ab 49 8d 7c 24 08 e8 37 5e d0 de 49 8b 6c 24 08 48 8d 7d 50 e8 e9 5c d0 de 8b 45 50 8d 50 ff 89 55 50 85 c0 75 86 <0f> 0b eb 82 0f 0b eb b3 0f 1f 40 00 90 90 90 90 90 90 90 90 90 90 +[43929.458081] RSP: 0018:ffff888140f9f4b0 EFLAGS: 00010246 +[43929.458086] RAX: 0000000000000000 RBX: ffff8881434f5288 RCX: dffffc0000000000 +[43929.458090] RDX: 00000000ffffffff RSI: ffffffffa26d28a7 RDI: ffff88810ecc9550 +[43929.458093] RBP: ffff88810ecc9500 R08: 0000000000000001 R09: ffffed10281f3e8f +[43929.458096] R10: 0000000000000003 R11: ffff0000ffff0000 R12: ffff8881434f52a0 +[43929.458100] R13: ffff888140f9f5f4 R14: ffff888151c7a800 R15: 0000000000000002 +[43929.458103] FS: 00007f0c687c4740(0000) GS:ffff888390800000(0000) knlGS:0000000000000000 +[43929.458107] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +[43929.458111] CR2: 00007f58dbe5b008 CR3: 0000000123602005 CR4: 00000000001706f0 +[43929.458114] Call Trace: +[43929.458118] +[43929.458121] ? __warn+0x9f/0x1a0 +[43929.458127] ? nft_setelem_data_deactivate+0xe4/0xf0 [nf_tables] +[43929.458188] ? report_bug+0x1b1/0x1e0 +[43929.458196] ? handle_bug+0x3c/0x70 +[43929.458200] ? exc_invalid_op+0x17/0x40 +[43929.458211] ? nft_setelem_data_deactivate+0xd7/0xf0 [nf_tables] +[43929.458271] ? nft_setelem_data_deactivate+0xe4/0xf0 [nf_tables] +[43929.458332] nft_mapelem_deactivate+0x24/0x30 [nf_tables] +[43929.458392] nft_rhash_walk+0xdd/0x180 [nf_tables] +[43929.458453] ? __pfx_nft_rhash_walk+0x10/0x10 [nf_tables] +[43929.458512] ? rb_insert_color+0x2e/0x280 +[43929.458520] nft_map_deactivate+0xdc/0x1e0 [nf_tables] +[43929.458582] ? __pfx_nft_map_deactivate+0x10/0x10 [nf_tables] +[43929.458642] ? __pfx_nft_mapelem_deactivate+0x10/0x10 [nf_tables] +[43929.458701] ? __rcu_read_unlock+0x46/0x70 +[43929.458709] nft_delset+0xff/0x110 [nf_tables] +[43929.458769] nft_flush_table+0x16f/0x460 [nf_tables] +[43929.458830] nf_tables_deltable+0x501/0x580 [nf_tables] + +Fixes: 628bd3e49cba ("netfilter: nf_tables: drop map element references from preparation phase") +Signed-off-by: Pablo Neira Ayuso +[Vegard: CVE-2024-27012; fixed conflicts due to missing commits + 0e1ea651c9717ddcd8e0648d8468477a31867b0a ("netfilter: nf_tables: shrink + memory consumption of set elements") and + 9dad402b89e81a0516bad5e0ac009b7a0a80898f ("netfilter: nf_tables: expose + opaque set element as struct nft_elem_priv") so we pass the correct types + and values to nft_setelem_data_deactivate(), nft_setelem_validate(), + nft_set_elem_ext(), etc.] +Signed-off-by: Vegard Nossum +[acsjakub: clean cherry-pick of the commit 164936b2fc88 + ("netfilter: nf_tables: restore set elements when delete set fails") + from 6.6.y. Plus, add "[ Upstream commit .." header to the message] +Signed-off-by: Jakub Acs +[sidk: clean cherry-pick of the commit faa0deee2721 + ("netfilter: nf_tables: restore set elements when delete set fails") + from 6.1.y.] +Signed-off-by: Sid Kumar +Signed-off-by: Greg Kroah-Hartman +--- + net/netfilter/nf_tables_api.c | 41 +++++++++++++++++++++++++++++++++++++---- + net/netfilter/nft_set_bitmap.c | 4 +--- + net/netfilter/nft_set_hash.c | 8 ++------ + net/netfilter/nft_set_pipapo.c | 5 +---- + net/netfilter/nft_set_rbtree.c | 4 +--- + 5 files changed, 42 insertions(+), 20 deletions(-) + +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -594,6 +594,12 @@ static int nft_mapelem_deactivate(const + const struct nft_set_iter *iter, + struct nft_set_elem *elem) + { ++ struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); ++ ++ if (!nft_set_elem_active(ext, iter->genmask)) ++ return 0; ++ ++ nft_set_elem_change_active(ctx->net, set, ext); + nft_setelem_data_deactivate(ctx->net, set, elem); + + return 0; +@@ -619,6 +625,7 @@ static void nft_map_catchall_deactivate( + continue; + + elem.priv = catchall->elem; ++ nft_set_elem_change_active(ctx->net, set, ext); + nft_setelem_data_deactivate(ctx->net, set, &elem); + break; + } +@@ -3522,6 +3529,9 @@ int nft_setelem_validate(const struct nf + const struct nft_data *data; + int err; + ++ if (!nft_set_elem_active(ext, iter->genmask)) ++ return 0; ++ + if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) && + *nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END) + return 0; +@@ -3545,19 +3555,22 @@ int nft_setelem_validate(const struct nf + + int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set) + { +- u8 genmask = nft_genmask_next(ctx->net); ++ struct nft_set_iter dummy_iter = { ++ .genmask = nft_genmask_next(ctx->net), ++ }; + struct nft_set_elem_catchall *catchall; + struct nft_set_elem elem; ++ + struct nft_set_ext *ext; + int ret = 0; + + list_for_each_entry_rcu(catchall, &set->catchall_list, list) { + ext = nft_set_elem_ext(set, catchall->elem); +- if (!nft_set_elem_active(ext, genmask)) ++ if (!nft_set_elem_active(ext, dummy_iter.genmask)) + continue; + + elem.priv = catchall->elem; +- ret = nft_setelem_validate(ctx, set, NULL, &elem); ++ ret = nft_setelem_validate(ctx, set, &dummy_iter, &elem); + if (ret < 0) + return ret; + } +@@ -5032,6 +5045,11 @@ static int nf_tables_bind_check_setelem( + const struct nft_set_iter *iter, + struct nft_set_elem *elem) + { ++ const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); ++ ++ if (!nft_set_elem_active(ext, iter->genmask)) ++ return 0; ++ + return nft_setelem_data_validate(ctx, set, elem); + } + +@@ -5126,6 +5144,13 @@ static int nft_mapelem_activate(const st + const struct nft_set_iter *iter, + struct nft_set_elem *elem) + { ++ struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); ++ ++ /* called from abort path, reverse check to undo changes. */ ++ if (nft_set_elem_active(ext, iter->genmask)) ++ return 0; ++ ++ nft_clear(ctx->net, ext); + nft_setelem_data_activate(ctx->net, set, elem); + + return 0; +@@ -5144,6 +5169,7 @@ static void nft_map_catchall_activate(co + if (nft_set_elem_active(ext, genmask)) + continue; + ++ nft_clear(ctx->net, ext); + elem.priv = catchall->elem; + nft_setelem_data_activate(ctx->net, set, &elem); + break; +@@ -5417,6 +5443,9 @@ static int nf_tables_dump_setelem(const + const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); + struct nft_set_dump_args *args; + ++ if (!nft_set_elem_active(ext, iter->genmask)) ++ return 0; ++ + if (nft_set_elem_expired(ext) || nft_set_elem_is_dead(ext)) + return 0; + +@@ -6103,7 +6132,7 @@ static void nft_setelem_activate(struct + struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv); + + if (nft_setelem_is_catchall(set, elem)) { +- nft_set_elem_change_active(net, set, ext); ++ nft_clear(net, ext); + } else { + set->ops->activate(net, set, elem); + } +@@ -6777,9 +6806,13 @@ static int nft_setelem_flush(const struc + 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_trans *trans; + int err; + ++ if (!nft_set_elem_active(ext, iter->genmask)) ++ return 0; ++ + trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM, + sizeof(struct nft_trans_elem), GFP_ATOMIC); + if (!trans) +--- a/net/netfilter/nft_set_bitmap.c ++++ b/net/netfilter/nft_set_bitmap.c +@@ -171,7 +171,7 @@ static void nft_bitmap_activate(const st + nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off); + /* Enter 11 state. */ + priv->bitmap[idx] |= (genmask << off); +- nft_set_elem_change_active(net, set, &be->ext); ++ nft_clear(net, &be->ext); + } + + static bool nft_bitmap_flush(const struct net *net, +@@ -223,8 +223,6 @@ static void nft_bitmap_walk(const struct + list_for_each_entry_rcu(be, &priv->list, head) { + if (iter->count < iter->skip) + goto cont; +- if (!nft_set_elem_active(&be->ext, iter->genmask)) +- goto cont; + + elem.priv = be; + +--- a/net/netfilter/nft_set_hash.c ++++ b/net/netfilter/nft_set_hash.c +@@ -196,7 +196,7 @@ static void nft_rhash_activate(const str + { + struct nft_rhash_elem *he = elem->priv; + +- nft_set_elem_change_active(net, set, &he->ext); ++ nft_clear(net, &he->ext); + } + + static bool nft_rhash_flush(const struct net *net, +@@ -285,8 +285,6 @@ static void nft_rhash_walk(const struct + + if (iter->count < iter->skip) + goto cont; +- if (!nft_set_elem_active(&he->ext, iter->genmask)) +- goto cont; + + elem.priv = he; + +@@ -615,7 +613,7 @@ static void nft_hash_activate(const stru + { + struct nft_hash_elem *he = elem->priv; + +- nft_set_elem_change_active(net, set, &he->ext); ++ nft_clear(net, &he->ext); + } + + static bool nft_hash_flush(const struct net *net, +@@ -669,8 +667,6 @@ static void nft_hash_walk(const struct n + hlist_for_each_entry_rcu(he, &priv->table[i], node) { + if (iter->count < iter->skip) + goto cont; +- if (!nft_set_elem_active(&he->ext, iter->genmask)) +- goto cont; + + elem.priv = he; + +--- a/net/netfilter/nft_set_pipapo.c ++++ b/net/netfilter/nft_set_pipapo.c +@@ -1819,7 +1819,7 @@ static void nft_pipapo_activate(const st + { + struct nft_pipapo_elem *e = elem->priv; + +- nft_set_elem_change_active(net, set, &e->ext); ++ nft_clear(net, &e->ext); + } + + /** +@@ -2121,9 +2121,6 @@ static void nft_pipapo_walk(const struct + + e = f->mt[r].e; + +- if (!nft_set_elem_active(&e->ext, iter->genmask)) +- goto cont; +- + elem.priv = e; + + iter->err = iter->fn(ctx, set, iter, &elem); +--- a/net/netfilter/nft_set_rbtree.c ++++ b/net/netfilter/nft_set_rbtree.c +@@ -548,7 +548,7 @@ static void nft_rbtree_activate(const st + { + struct nft_rbtree_elem *rbe = elem->priv; + +- nft_set_elem_change_active(net, set, &rbe->ext); ++ nft_clear(net, &rbe->ext); + } + + static bool nft_rbtree_flush(const struct net *net, +@@ -618,8 +618,6 @@ static void nft_rbtree_walk(const struct + + if (iter->count < iter->skip) + goto cont; +- if (!nft_set_elem_active(&rbe->ext, iter->genmask)) +- goto cont; + + elem.priv = rbe; + diff --git a/queue-5.15/series b/queue-5.15/series index 86106a774d..a3ac4a6d72 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -15,3 +15,5 @@ nfsd-move-name-lookup-out-of-nfsd4_list_rec_dir.patch nfsd-change-nfs4_client_to_reclaim-to-allocate-data.patch kvm-replace-guest-triggerable-bug_on-in-ioeventfd-da.patch perf-trace-beauty-fcntl-fix-build-with-older-kernel-headers.patch +mm-fix-copy_from_user_nofault.patch +netfilter-nf_tables-restore-set-elements-when-delete-set-fails.patch