From: Sasha Levin Date: Fri, 31 Jul 2026 02:39:37 +0000 (-0400) Subject: Fixes for all trees X-Git-Tag: v6.6.148~12^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=66001a4791f78c02b92a66187099b26b71ba8543;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/staging-6.1/io_uring-rw-fix-missing-erestartsys-conversion-in-re.patch b/staging-6.1/io_uring-rw-fix-missing-erestartsys-conversion-in-re.patch new file mode 100644 index 0000000000..85eee1104c --- /dev/null +++ b/staging-6.1/io_uring-rw-fix-missing-erestartsys-conversion-in-re.patch @@ -0,0 +1,89 @@ +From e80be64690b11276f3e38b4b25875f2f2c8fa60f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 22 Jul 2026 20:45:51 +0800 +Subject: io_uring/rw: fix missing ERESTARTSYS conversion in read paths + +From: Yitang Yang + +Commit ab05caca123c6d0b41850b7c05b246e4dca4a770 upstream. + +Both read and write may receive internal restart error codes from +the filesystem layer and should be converted to -EINTR. However, +when multishot read support was added, the error code normalization +was lost for both io_read() and io_read_mshot(). + +Extract the conversion into io_fixup_restart_res() and apply it +in all three locations: io_rw_done(), io_read(), and io_read_mshot(). + +Fixes: a08d195b586a ("io_uring/rw: split io_read() into a helper") +Cc: stable@vger.kernel.org +Signed-off-by: Yitang Yang +Link: https://patch.msgid.link/20260722124551.130563-1-yi1tang.yang@gmail.com +Signed-off-by: Jens Axboe +Signed-off-by: Sasha Levin +--- + io_uring/rw.c | 28 +++++++++++++++++++--------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +diff --git a/io_uring/rw.c b/io_uring/rw.c +index b75f62dccce6..cbd3ee9a9373 100644 +--- a/io_uring/rw.c ++++ b/io_uring/rw.c +@@ -129,27 +129,37 @@ void io_readv_writev_cleanup(struct io_kiocb *req) + kfree(io->free_iovec); + } + +-static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret) ++static inline ssize_t io_fixup_restart_res(ssize_t ret) + { + switch (ret) { +- case -EIOCBQUEUED: +- break; + case -ERESTARTSYS: + case -ERESTARTNOINTR: + case -ERESTARTNOHAND: + case -ERESTART_RESTARTBLOCK: + /* + * We can't just restart the syscall, since previously +- * submitted sqes may already be in progress. Just fail this +- * IO with EINTR. ++ * submitted sqes may already be in progress. Just fail ++ * this IO with EINTR. + */ +- ret = -EINTR; +- fallthrough; ++ return -EINTR; + default: +- kiocb->ki_complete(kiocb, ret); ++ return ret; + } + } + ++static inline void io_rw_done(struct kiocb *kiocb, ssize_t ret) ++{ ++ /* IO was queued async, completion will happen later */ ++ if (ret == -EIOCBQUEUED) ++ return; ++ ++ /* transform internal restart error codes */ ++ if (unlikely(ret < 0)) ++ ret = io_fixup_restart_res(ret); ++ ++ kiocb->ki_complete(kiocb, ret); ++} ++ + static inline loff_t *io_kiocb_update_pos(struct io_kiocb *req) + { + struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw); +@@ -854,7 +864,7 @@ int io_read(struct io_kiocb *req, unsigned int issue_flags) + if (ret >= 0) + return kiocb_done(req, ret, issue_flags); + +- return ret; ++ return io_fixup_restart_res(ret); + } + + static bool io_kiocb_start_write(struct io_kiocb *req, struct kiocb *kiocb) +-- +2.53.0 + diff --git a/staging-6.1/mm-damon-core-disallow-overlapping-input-ranges-for-.patch b/staging-6.1/mm-damon-core-disallow-overlapping-input-ranges-for-.patch new file mode 100644 index 0000000000..086873076a --- /dev/null +++ b/staging-6.1/mm-damon-core-disallow-overlapping-input-ranges-for-.patch @@ -0,0 +1,77 @@ +From af70be1962666d603abd5411e68bd92456280e9c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 18:20:58 -0700 +Subject: mm/damon/core: disallow overlapping input ranges for + damon_set_regions() + +From: SJ Park + +commit 954157679ec34661c2e87e7eb796104a797c32db upstream. + +damon_set_regions() assumes the input ranges are sorted by the address and +don't overlap each other. Hence the assumption was initially to be +explicitly validated. But commit 97d482f4592f ("mm/damon/sysfs: reuse +damon_set_regions() for regions setting") has mistakenly removed the +validation. + +This can make DAMON behave in unexpected ways. At the best, the +monitoring results snapshot will just look weird since there will be +overlapping regions. DAMOS will also work weirdly, applying the same +action multiple times for overlapping regions, and make DAMOS quota weird. +More seriously, depending on the setup and regions updates sequence, +negative size regions can be made. It will trigger WARN_ONCE() if the +kernel is built with CONFIG_DAMON_DEBUG_SANITY=y. Depending on the +monitoring results, the negative size region can further trigger division +by zero in damon_merge_two_regions(). + +Note that some of the consequences including the WARN_ONCE() and the +divide by zero depend on commits that were introduced after the root cause +commit 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for +regions setting"). + +Fix the problems by checking the assumption and returning an error if +the input ranges don't meet the assumption. + +The issue was discovered [1] by Sashiko. + +Link: https://lore.kernel.org/20260703165610.92894-1-sj@kernel.org +Link: https://lore.kernel.org/20260630041806.151124-1-sj@kernel.org [1] +Fixes: 97d482f4592f ("mm/damon/sysfs: reuse damon_set_regions() for regions setting") +Signed-off-by: SJ Park +Cc: # 5.19.x +Signed-off-by: Andrew Morton +Signed-off-by: SJ Park +Signed-off-by: Sasha Levin +--- + mm/damon/core.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/mm/damon/core.c b/mm/damon/core.c +index 0a0bb033f28a..dd4eafe8b961 100644 +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -210,12 +210,19 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges, + { + struct damon_region *r, *next; + unsigned int i; ++ unsigned long last_end; + int err; + + for (i = 0; i < nr_ranges; i++) { +- if (ALIGN_DOWN(ranges[i].start, DAMON_MIN_REGION) >= +- ALIGN(ranges[i].end, DAMON_MIN_REGION)) ++ unsigned long start, end; ++ ++ start = ALIGN_DOWN(ranges[i].start, DAMON_MIN_REGION); ++ end = ALIGN(ranges[i].end, DAMON_MIN_REGION); ++ if (start >= end) ++ return -EINVAL; ++ if (i > 0 && last_end > start) + return -EINVAL; ++ last_end = end; + } + + /* Remove regions which are not in the new ranges */ +-- +2.53.0 + diff --git a/staging-6.1/mm-damon-core-validate-ranges-in-damon_set_regions.patch b/staging-6.1/mm-damon-core-validate-ranges-in-damon_set_regions.patch new file mode 100644 index 0000000000..61daaed7d8 --- /dev/null +++ b/staging-6.1/mm-damon-core-validate-ranges-in-damon_set_regions.patch @@ -0,0 +1,66 @@ +From f274de37aa67665a98e14a92c2e88cfaef5fa13f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jul 2026 18:01:51 -0700 +Subject: mm/damon/core: validate ranges in damon_set_regions() + +From: SJ Park + +commit 1292c0ecb1caefb8ca064a3639d5673991e8810c upstream. + +DAMON core logic assumes zero length regions don't exist. However, a few +DAMON API callers including DAMON_SYSFS, DAMON_RECLAIM and DAMON_LRU_SORT +allow users to set empty monitoring target regions. This could result in +WARN_ONCE() on CONFIG_DAMON_DEBUG_SANITY enabled kernel, and +divide-by-zero from damon_merge_two_regions(). + +For example, the WANR_ONCE() can be triggered like below. + + # grep DAMON_DEBUG_SANITY /boot/config-$(uname -r) + # CONFIG_DAMON_DEBUG_SANITY=y + # damo start + # cd /sys/kernel/mm/damon/admin/kdamonds/0 + # echo 0 > contexts/0/targets/0/regions/0/start + # echo 0 > contexts/0/targets/0/regions/0/end + # echo commit > state + # dmesg + [....] + [ 73.705780] ------------[ cut here ]------------ + [ 73.707552] start 0 >= end 0 + [ 73.708452] WARNING: mm/damon/core.c:359 at damon_new_region+0x6e/0x80, CPU#1: kdamond.0/758 + [...] + +All DAMON API callers eventually use damon_set_regions() to setup the +regions. Add the validation logic in the function. + +Link: https://lore.kernel.org/20260630035221.146458-1-sj@kernel.org +Fixes: 43b0536cb471 ("mm/damon: introduce DAMON-based Reclamation (DAMON_RECLAIM)") +Signed-off-by: SJ Park +Cc: Yang yingliang +Cc: # 5.16.x +Signed-off-by: Andrew Morton +Signed-off-by: SJ Park +Signed-off-by: Sasha Levin +--- + mm/damon/core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/mm/damon/core.c b/mm/damon/core.c +index 4b434ebd37c5..0a0bb033f28a 100644 +--- a/mm/damon/core.c ++++ b/mm/damon/core.c +@@ -212,6 +212,12 @@ int damon_set_regions(struct damon_target *t, struct damon_addr_range *ranges, + unsigned int i; + int err; + ++ for (i = 0; i < nr_ranges; i++) { ++ if (ALIGN_DOWN(ranges[i].start, DAMON_MIN_REGION) >= ++ ALIGN(ranges[i].end, DAMON_MIN_REGION)) ++ return -EINVAL; ++ } ++ + /* Remove regions which are not in the new ranges */ + damon_for_each_region_safe(r, next, t) { + for (i = 0; i < nr_ranges; i++) { +-- +2.53.0 + diff --git a/staging-6.1/netfilter-nf_conntrack_expect-restore-helper-propaga.patch b/staging-6.1/netfilter-nf_conntrack_expect-restore-helper-propaga.patch new file mode 100644 index 0000000000..7787ff1fa6 --- /dev/null +++ b/staging-6.1/netfilter-nf_conntrack_expect-restore-helper-propaga.patch @@ -0,0 +1,269 @@ +From d56e298bedc6043cf9d784d7c44e8d38c01fbcaf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 13:00:28 +0200 +Subject: netfilter: nf_conntrack_expect: restore helper propagation via + expectation + +From: Pablo Neira Ayuso + +[ Upstream commit dcb0f9aefdd604d36710fda53c25bd7cf4a3e37a ] + +A recent series to fix expectations broke helper propagation via +expectation, this mechanism is used by the sip and h323 helper. This +also propagates the conntrack helper to expected connections. I changed +semantics of exp->helper which now tells us the actual helper that +created the expectation. + +Add an explicit assign_helper field to expectations for this purpose +and update helpers to use it. + +Restore this feature for userspace conntrack helper via ctnetlink +nfqueue integration so it is again possible to attach a helper to an +expectation, where it makes sense. This is not restored via ctnetlink +expectation creation as there is no client for such feature. Use the +expectation layer 4 protocol number for the helper lookup for +consistency. + +Make sure the expectation using this helper propagation mechanism also +go away when the helper is unregistered. + +Fixes: 9c42bc9db90a ("netfilter: nf_conntrack_expect: honor expectation helper field") +Fixes: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Reported-by: Ilya Maximets +Tested-by: Ilya Maximets +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_expect.h | 5 ++++- + net/netfilter/nf_conntrack_broadcast.c | 1 + + net/netfilter/nf_conntrack_core.c | 7 +++++-- + net/netfilter/nf_conntrack_expect.c | 1 + + net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------ + net/netfilter/nf_conntrack_helper.c | 5 +++++ + net/netfilter/nf_conntrack_netlink.c | 18 ++++++++++++++++-- + net/netfilter/nf_conntrack_sip.c | 2 +- + 8 files changed, 39 insertions(+), 12 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h +index e9a8350e7ccf..80f50fd0f7ad 100644 +--- a/include/net/netfilter/nf_conntrack_expect.h ++++ b/include/net/netfilter/nf_conntrack_expect.h +@@ -45,9 +45,12 @@ struct nf_conntrack_expect { + void (*expectfn)(struct nf_conn *new, + struct nf_conntrack_expect *this); + +- /* Helper to assign to new connection */ ++ /* Helper that created this expectation */ + struct nf_conntrack_helper __rcu *helper; + ++ /* Helper to assign to new connection */ ++ struct nf_conntrack_helper __rcu *assign_helper; ++ + /* The conntrack of the master connection */ + struct nf_conn *master; + +diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c +index d44d9379a8a0..ef8a7ca8c116 100644 +--- a/net/netfilter/nf_conntrack_broadcast.c ++++ b/net/netfilter/nf_conntrack_broadcast.c +@@ -72,6 +72,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->class = NF_CT_EXPECT_CLASS_DEFAULT; + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index f5c466ea1e7d..342627b0d32b 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1800,16 +1800,19 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, + spin_lock_bh(&nf_conntrack_expect_lock); + exp = nf_ct_find_expectation(net, zone, tuple, !tmpl || nf_ct_is_confirmed(tmpl)); + if (exp) { ++ struct nf_conntrack_helper *assign_helper; ++ + pr_debug("expectation arrives ct=%p exp=%p\n", + ct, exp); + /* Welcome, Mr. Bond. We've been expecting you... */ + __set_bit(IPS_EXPECTED_BIT, &ct->status); + /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ + ct->master = exp->master; +- if (exp->helper) { ++ assign_helper = rcu_dereference(exp->assign_helper); ++ if (assign_helper) { + help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); + if (help) +- rcu_assign_pointer(help->helper, exp->helper); ++ rcu_assign_pointer(help->helper, assign_helper); + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index 379711ea5ab6..34324dece89d 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -344,6 +344,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, + helper = rcu_dereference(help->helper); + + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c +index 791aafe9f396..c42547284f35 100644 +--- a/net/netfilter/nf_conntrack_h323_main.c ++++ b/net/netfilter/nf_conntrack_h323_main.c +@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245); ++ rcu_assign_pointer(exp->assign_helper, &nf_conntrack_helper_h245); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3 : NULL, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */ + + nathook = rcu_dereference(nfct_h323_nat_hook); +@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_UDP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect RAS "); +@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index 8e72c3d4db4a..efa080cb1709 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -422,6 +422,11 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data) + + this = rcu_dereference_protected(exp->helper, + lockdep_is_held(&nf_conntrack_expect_lock)); ++ if (this == me) ++ return true; ++ ++ this = rcu_dereference_protected(exp->assign_helper, ++ lockdep_is_held(&nf_conntrack_expect_lock)); + return this == me; + } + +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index a3b18042adec..55bc5626b967 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -2628,6 +2628,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask); + +@@ -2854,6 +2855,7 @@ static int + ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + u32 portid, u32 report) + { ++ struct nf_conntrack_helper *assign_helper = NULL; + struct nlattr *cda[CTA_EXPECT_MAX+1]; + struct nf_conntrack_tuple tuple, mask; + struct nf_conntrack_expect *exp; +@@ -2869,8 +2871,18 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + if (err < 0) + return err; + ++ if (cda[CTA_EXPECT_HELP_NAME]) { ++ const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); ++ ++ assign_helper = __nf_conntrack_helper_find(helpname, ++ nf_ct_l3num(ct), ++ tuple.dst.protonum); ++ if (!assign_helper) ++ return -EOPNOTSUPP; ++ } ++ + exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct, +- &tuple, &mask); ++ assign_helper, &tuple, &mask); + if (IS_ERR(exp)) + return PTR_ERR(exp); + +@@ -3509,6 +3521,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr, + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask) + { +@@ -3562,6 +3575,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, + exp->zone = ct->zone; + #endif + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, assign_helper); + exp->tuple = *tuple; + exp->mask.src.u3 = mask->src.u3; + exp->mask.src.u.all = mask->src.u.all; +@@ -3617,7 +3631,7 @@ ctnetlink_create_expect(struct net *net, + ct = nf_ct_tuplehash_to_ctrack(h); + + rcu_read_lock(); +- exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask); ++ exp = ctnetlink_alloc_expect(cda, ct, NULL, &tuple, &mask); + if (IS_ERR(exp)) { + err = PTR_ERR(exp); + goto err_rcu; +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index ec31611b7a29..0af6ede4b92c 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -1384,7 +1384,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), + saddr, &daddr, proto, NULL, &port); + exp->timeout.expires = sip_timeout * HZ; +- rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, helper); + exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; + + hooks = rcu_dereference(nf_nat_sip_hooks); +-- +2.53.0 + diff --git a/staging-6.1/series b/staging-6.1/series new file mode 100644 index 0000000000..5d3a24c72c --- /dev/null +++ b/staging-6.1/series @@ -0,0 +1,4 @@ +io_uring-rw-fix-missing-erestartsys-conversion-in-re.patch +mm-damon-core-validate-ranges-in-damon_set_regions.patch +mm-damon-core-disallow-overlapping-input-ranges-for-.patch +netfilter-nf_conntrack_expect-restore-helper-propaga.patch diff --git a/staging-6.12/kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch b/staging-6.12/kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch new file mode 100644 index 0000000000..34bb3b5fb8 --- /dev/null +++ b/staging-6.12/kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch @@ -0,0 +1,128 @@ +From c386b26dbc1f2cc87b2743aa63f3070b229d5ccb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:18 -0700 +Subject: kunit: tool: skip stty when stdin is not a tty + +From: Shuvam Pandey + +commit e42c349f4cdfa43cb39a68c8f764f8cafc23a9a9 upstream. + +run_kernel() cleanup and signal_handler() invoke stty unconditionally. +When stdin is not a tty (for example in CI or unit tests), this writes +noise to stderr. + +Call stty only when stdin is a tty. + +Add regression tests for these paths: +- run_kernel() with non-tty stdin +- signal_handler() with non-tty stdin +- signal_handler() with tty stdin + +Signed-off-by: Shuvam Pandey +Reviewed-by: David Gow +Signed-off-by: Shuah Khan +[florian: add missing 'import sys' required by sys.stdin.isatty(); the +module was already present in the mainline tree before this commit but +was absent from the 6.12 base of kunit_kernel.py] +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + tools/testing/kunit/kunit_kernel.py | 11 +++++-- + tools/testing/kunit/kunit_tool_test.py | 42 ++++++++++++++++++++++++++ + 2 files changed, 51 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py +index 3f2979f2f6ea..c09b66ba734b 100644 +--- a/tools/testing/kunit/kunit_kernel.py ++++ b/tools/testing/kunit/kunit_kernel.py +@@ -14,6 +14,7 @@ import os + import shlex + import shutil + import signal ++import sys + import threading + from typing import Iterator, List, Optional, Tuple, Any + from types import FrameType +@@ -333,6 +334,12 @@ class LinuxSourceTree: + return False + return self.validate_config(build_dir) + ++ def _restore_terminal_if_tty(self) -> None: ++ # stty requires a controlling terminal; skip headless runs. ++ if sys.stdin is None or not sys.stdin.isatty(): ++ return ++ subprocess.call(['stty', 'sane']) ++ + def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]: + # Copy to avoid mutating the caller-supplied list. exec_tests() reuses + # the same args across repeated run_kernel() calls (e.g. --run_isolated), +@@ -380,11 +387,11 @@ class LinuxSourceTree: + output.close() + + waiter.join() +- subprocess.call(['stty', 'sane']) ++ self._restore_terminal_if_tty() + + def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None: + logging.error('Build interruption occurred. Cleaning console.') + if self._process: + self._process.terminate() + self._process.wait() +- subprocess.call(['stty', 'sane']) ++ self._restore_terminal_if_tty() +diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py +index 70e5d0abe87f..6e6200d52540 100755 +--- a/tools/testing/kunit/kunit_tool_test.py ++++ b/tools/testing/kunit/kunit_tool_test.py +@@ -503,6 +503,48 @@ class LinuxSourceTreeTest(unittest.TestCase): + self.assertIn('kunit.filter_glob=suite.test1', start_calls[0]) + self.assertIn('kunit.filter_glob=suite.test2', start_calls[1]) + ++ def test_run_kernel_skips_terminal_reset_without_tty(self): ++ def fake_start(unused_args, unused_build_dir): ++ return subprocess.Popen(['printf', 'KTAP version 1\n'], ++ text=True, stdout=subprocess.PIPE) ++ ++ non_tty_stdin = mock.Mock() ++ non_tty_stdin.isatty.return_value = False ++ ++ with tempfile.TemporaryDirectory('') as build_dir: ++ tree = kunit_kernel.LinuxSourceTree(build_dir, kunitconfig_paths=[os.devnull]) ++ with mock.patch.object(tree._ops, 'start', side_effect=fake_start), \ ++ mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ ++ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call: ++ for _ in tree.run_kernel(build_dir=build_dir): ++ pass ++ ++ mock_call.assert_not_called() ++ ++ def test_signal_handler_skips_terminal_reset_without_tty(self): ++ non_tty_stdin = mock.Mock() ++ non_tty_stdin.isatty.return_value = False ++ tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull]) ++ ++ with mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ ++ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ ++ mock.patch.object(kunit_kernel.logging, 'error') as mock_error: ++ tree.signal_handler(signal.SIGINT, None) ++ mock_error.assert_called_once() ++ mock_call.assert_not_called() ++ ++ def test_signal_handler_resets_terminal_with_tty(self): ++ tty_stdin = mock.Mock() ++ tty_stdin.isatty.return_value = True ++ tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull]) ++ ++ with mock.patch.object(kunit_kernel.sys, 'stdin', tty_stdin), \ ++ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ ++ mock.patch.object(kunit_kernel.logging, 'error') as mock_error: ++ tree.signal_handler(signal.SIGINT, None) ++ mock_error.assert_called_once() ++ mock_call.assert_called_once_with(['stty', 'sane']) ++ + def test_build_reconfig_no_config(self): + with tempfile.TemporaryDirectory('') as build_dir: + with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f: +-- +2.53.0 + diff --git a/staging-6.12/kunit-tool-terminate-kernel-under-test-on-sigint.patch b/staging-6.12/kunit-tool-terminate-kernel-under-test-on-sigint.patch new file mode 100644 index 0000000000..66c92c16d2 --- /dev/null +++ b/staging-6.12/kunit-tool-terminate-kernel-under-test-on-sigint.patch @@ -0,0 +1,112 @@ +From 32d59ef004ad145696e0cee42173d5f512e55a5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:17 -0700 +Subject: kunit: tool: Terminate kernel under test on SIGINT + +From: David Gow + +commit 8f260b02eeeffbf2263c2b82b6e3e32fd73cde2b upstream. + +kunit.py will attempt to catch SIGINT / ^C in order to ensure the TTY isn't +messed up, but never actually attempts to terminate the running kernel (be +it UML or QEMU). This can lead to a bit of frustration if the kernel has +crashed or hung. + +Terminate the kernel process in the signal handler, if it's running. This +requires plumbing through the process handle in a few more places (and +having some checks to see if the kernel is still running in places where it +may have already been killed). + +Reported-by: Andy Shevchenko +Closes: https://lore.kernel.org/all/aaFmiAmg9S18EANA@smile.fi.intel.com/ +Signed-off-by: David Gow +Reviewed-by: Andy Shevchenko +Tested-by: Andy Shevchenko +Signed-off-by: Shuah Khan +[florian: resolved conflict in signal_handler(): upstream references +_restore_terminal_if_tty() which is introduced by the following commit; +retained subprocess.call(['stty', 'sane']) until that helper is available] +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + tools/testing/kunit/kunit_kernel.py | 28 +++++++++++++++++++--------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py +index 12b0f2ee5665..3f2979f2f6ea 100644 +--- a/tools/testing/kunit/kunit_kernel.py ++++ b/tools/testing/kunit/kunit_kernel.py +@@ -15,7 +15,7 @@ import shlex + import shutil + import signal + import threading +-from typing import Iterator, List, Optional, Tuple ++from typing import Iterator, List, Optional, Tuple, Any + from types import FrameType + + import kunit_config +@@ -252,6 +252,7 @@ class LinuxSourceTree: + if kconfig_add: + kconfig = kunit_config.parse_from_string('\n'.join(kconfig_add)) + self._kconfig.merge_in_entries(kconfig) ++ self._process : Optional[subprocess.Popen[Any]] = None + + def arch(self) -> str: + return self._arch +@@ -345,36 +346,45 @@ class LinuxSourceTree: + args.append('kunit.filter_action=' + filter_action) + args.append('kunit.enable=1') + +- process = self._ops.start(args, build_dir) +- assert process.stdout is not None # tell mypy it's set ++ self._process = self._ops.start(args, build_dir) ++ assert self._process is not None # tell mypy it's set ++ assert self._process.stdout is not None # tell mypy it's set + + # Enforce the timeout in a background thread. + def _wait_proc() -> None: + try: +- process.wait(timeout=timeout) ++ if self._process: ++ self._process.wait(timeout=timeout) + except Exception as e: + print(e) +- process.terminate() +- process.wait() ++ if self._process: ++ self._process.terminate() ++ self._process.wait() + waiter = threading.Thread(target=_wait_proc) + waiter.start() + + output = open(get_outfile_path(build_dir), 'w') + try: + # Tee the output to the file and to our caller in real time. +- for line in process.stdout: ++ for line in self._process.stdout: + output.write(line) + yield line + # This runs even if our caller doesn't consume every line. + finally: + # Flush any leftover output to the file +- output.write(process.stdout.read()) ++ if self._process: ++ if self._process.stdout: ++ output.write(self._process.stdout.read()) ++ self._process.stdout.close() ++ self._process = None + output.close() +- process.stdout.close() + + waiter.join() + subprocess.call(['stty', 'sane']) + + def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None: + logging.error('Build interruption occurred. Cleaning console.') ++ if self._process: ++ self._process.terminate() ++ self._process.wait() + subprocess.call(['stty', 'sane']) +-- +2.53.0 + diff --git a/staging-6.12/netfilter-nf_conntrack_expect-restore-helper-propaga.patch b/staging-6.12/netfilter-nf_conntrack_expect-restore-helper-propaga.patch new file mode 100644 index 0000000000..fa8ebbbd66 --- /dev/null +++ b/staging-6.12/netfilter-nf_conntrack_expect-restore-helper-propaga.patch @@ -0,0 +1,267 @@ +From ba7135b24bed82b00e13b2c8efa680a78387ced6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 13:00:28 +0200 +Subject: netfilter: nf_conntrack_expect: restore helper propagation via + expectation + +From: Pablo Neira Ayuso + +[ Upstream commit dcb0f9aefdd604d36710fda53c25bd7cf4a3e37a ] + +A recent series to fix expectations broke helper propagation via +expectation, this mechanism is used by the sip and h323 helper. This +also propagates the conntrack helper to expected connections. I changed +semantics of exp->helper which now tells us the actual helper that +created the expectation. + +Add an explicit assign_helper field to expectations for this purpose +and update helpers to use it. + +Restore this feature for userspace conntrack helper via ctnetlink +nfqueue integration so it is again possible to attach a helper to an +expectation, where it makes sense. This is not restored via ctnetlink +expectation creation as there is no client for such feature. Use the +expectation layer 4 protocol number for the helper lookup for +consistency. + +Make sure the expectation using this helper propagation mechanism also +go away when the helper is unregistered. + +Fixes: 9c42bc9db90a ("netfilter: nf_conntrack_expect: honor expectation helper field") +Fixes: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Reported-by: Ilya Maximets +Tested-by: Ilya Maximets +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_expect.h | 5 ++++- + net/netfilter/nf_conntrack_broadcast.c | 1 + + net/netfilter/nf_conntrack_core.c | 7 +++++-- + net/netfilter/nf_conntrack_expect.c | 1 + + net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------ + net/netfilter/nf_conntrack_helper.c | 5 +++++ + net/netfilter/nf_conntrack_netlink.c | 18 ++++++++++++++++-- + net/netfilter/nf_conntrack_sip.c | 2 +- + 8 files changed, 39 insertions(+), 12 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h +index e9a8350e7ccf..80f50fd0f7ad 100644 +--- a/include/net/netfilter/nf_conntrack_expect.h ++++ b/include/net/netfilter/nf_conntrack_expect.h +@@ -45,9 +45,12 @@ struct nf_conntrack_expect { + void (*expectfn)(struct nf_conn *new, + struct nf_conntrack_expect *this); + +- /* Helper to assign to new connection */ ++ /* Helper that created this expectation */ + struct nf_conntrack_helper __rcu *helper; + ++ /* Helper to assign to new connection */ ++ struct nf_conntrack_helper __rcu *assign_helper; ++ + /* The conntrack of the master connection */ + struct nf_conn *master; + +diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c +index f9528d4db0a8..93c501d9d399 100644 +--- a/net/netfilter/nf_conntrack_broadcast.c ++++ b/net/netfilter/nf_conntrack_broadcast.c +@@ -72,6 +72,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->class = NF_CT_EXPECT_CLASS_DEFAULT; + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index 423080cf86a4..0c457e159727 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1773,14 +1773,17 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, + spin_lock_bh(&nf_conntrack_expect_lock); + exp = nf_ct_find_expectation(net, zone, tuple, !tmpl || nf_ct_is_confirmed(tmpl)); + if (exp) { ++ struct nf_conntrack_helper *assign_helper; ++ + /* Welcome, Mr. Bond. We've been expecting you... */ + __set_bit(IPS_EXPECTED_BIT, &ct->status); + /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ + ct->master = exp->master; +- if (exp->helper) { ++ assign_helper = rcu_dereference(exp->assign_helper); ++ if (assign_helper) { + help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); + if (help) +- rcu_assign_pointer(help->helper, exp->helper); ++ rcu_assign_pointer(help->helper, assign_helper); + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index bb8b87f9ee50..a8929885485b 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -344,6 +344,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, + helper = rcu_dereference(help->helper); + + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c +index 791aafe9f396..c42547284f35 100644 +--- a/net/netfilter/nf_conntrack_h323_main.c ++++ b/net/netfilter/nf_conntrack_h323_main.c +@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245); ++ rcu_assign_pointer(exp->assign_helper, &nf_conntrack_helper_h245); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3 : NULL, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */ + + nathook = rcu_dereference(nfct_h323_nat_hook); +@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_UDP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect RAS "); +@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index 9150bcfd7ca8..ea0cdb7ec915 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -419,6 +419,11 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data) + + this = rcu_dereference_protected(exp->helper, + lockdep_is_held(&nf_conntrack_expect_lock)); ++ if (this == me) ++ return true; ++ ++ this = rcu_dereference_protected(exp->assign_helper, ++ lockdep_is_held(&nf_conntrack_expect_lock)); + return this == me; + } + +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index eacbbc342c3f..80fdb875c977 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -2630,6 +2630,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask); + +@@ -2856,6 +2857,7 @@ static int + ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + u32 portid, u32 report) + { ++ struct nf_conntrack_helper *assign_helper = NULL; + struct nlattr *cda[CTA_EXPECT_MAX+1]; + struct nf_conntrack_tuple tuple, mask; + struct nf_conntrack_expect *exp; +@@ -2871,8 +2873,18 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + if (err < 0) + return err; + ++ if (cda[CTA_EXPECT_HELP_NAME]) { ++ const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); ++ ++ assign_helper = __nf_conntrack_helper_find(helpname, ++ nf_ct_l3num(ct), ++ tuple.dst.protonum); ++ if (!assign_helper) ++ return -EOPNOTSUPP; ++ } ++ + exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct, +- &tuple, &mask); ++ assign_helper, &tuple, &mask); + if (IS_ERR(exp)) + return PTR_ERR(exp); + +@@ -3511,6 +3523,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr, + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask) + { +@@ -3564,6 +3577,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, + exp->zone = ct->zone; + #endif + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, assign_helper); + exp->tuple = *tuple; + exp->mask.src.u3 = mask->src.u3; + exp->mask.src.u.all = mask->src.u.all; +@@ -3619,7 +3633,7 @@ ctnetlink_create_expect(struct net *net, + ct = nf_ct_tuplehash_to_ctrack(h); + + rcu_read_lock(); +- exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask); ++ exp = ctnetlink_alloc_expect(cda, ct, NULL, &tuple, &mask); + if (IS_ERR(exp)) { + err = PTR_ERR(exp); + goto err_rcu; +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index bd91b8b47f4b..852c0b74b8a7 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -1386,7 +1386,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), + saddr, &daddr, proto, NULL, &port); + exp->timeout.expires = sip_timeout * HZ; +- rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, helper); + exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; + + hooks = rcu_dereference(nf_nat_sip_hooks); +-- +2.53.0 + diff --git a/staging-6.12/series b/staging-6.12/series new file mode 100644 index 0000000000..8b36f5acf4 --- /dev/null +++ b/staging-6.12/series @@ -0,0 +1,10 @@ +netfilter-nf_conntrack_expect-restore-helper-propaga.patch +um-add-os_set_pdeathsig-helper-function.patch +um-set-parent-death-signal-for-winch-thread-process.patch +um-use-os_set_pdeathsig-helper-in-winch-thread-proce.patch +um-set-parent-death-signal-for-ubd-io-thread-process.patch +um-set-parent-death-signal-for-write_sigio-thread-pr.patch +um-set-parent-death-signal-for-userspace-process.patch +kunit-tool-terminate-kernel-under-test-on-sigint.patch +kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch +um-preserve-errno-within-signal-handler.patch diff --git a/staging-6.12/um-add-os_set_pdeathsig-helper-function.patch b/staging-6.12/um-add-os_set_pdeathsig-helper-function.patch new file mode 100644 index 0000000000..42f184836f --- /dev/null +++ b/staging-6.12/um-add-os_set_pdeathsig-helper-function.patch @@ -0,0 +1,61 @@ +From fc6ea5b0b8cfa038860960f76e22073a5990c799 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:11 -0700 +Subject: um: Add os_set_pdeathsig helper function + +From: Tiwei Bie + +commit 4e5adbe447db382cc76e05613581f96aef4f91d2 upstream. + +This helper can be used to set the parent-death signal of the calling +process to SIGKILL to ensure that the process will be killed if the +UML kernel dies unexpectedly without proper cleanup. This helper will +be used in the follow-up patches. + +Signed-off-by: Tiwei Bie +Link: https://patch.msgid.link/20241024142828.2612828-2-tiwei.btw@antgroup.com +Signed-off-by: Johannes Berg +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/um/include/shared/os.h | 2 ++ + arch/um/os-Linux/process.c | 6 ++++++ + 2 files changed, 8 insertions(+) + +diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h +index 77a8593f219a..2a0843cc2208 100644 +--- a/arch/um/include/shared/os.h ++++ b/arch/um/include/shared/os.h +@@ -219,6 +219,8 @@ extern int os_unmap_memory(void *addr, int len); + extern int os_drop_memory(void *addr, int length); + extern int can_drop_memory(void); + ++void os_set_pdeathsig(void); ++ + /* execvp.c */ + extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); + /* helper.c */ +diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c +index 2686120ab232..4015d3dc3958 100644 +--- a/arch/um/os-Linux/process.c ++++ b/arch/um/os-Linux/process.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -234,3 +235,8 @@ void init_new_thread_signals(void) + set_handler(SIGIO); + signal(SIGWINCH, SIG_IGN); + } ++ ++void os_set_pdeathsig(void) ++{ ++ prctl(PR_SET_PDEATHSIG, SIGKILL); ++} +-- +2.53.0 + diff --git a/staging-6.12/um-preserve-errno-within-signal-handler.patch b/staging-6.12/um-preserve-errno-within-signal-handler.patch new file mode 100644 index 0000000000..255489ab0d --- /dev/null +++ b/staging-6.12/um-preserve-errno-within-signal-handler.patch @@ -0,0 +1,51 @@ +From 100199613d07dfe9a0688b62d46bc64f9f11d9e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:19 -0700 +Subject: um: Preserve errno within signal handler + +From: Tiwei Bie + +commit f68b2d5a907b53eed99cf2efcaaae116df73c298 upstream. + +We rely on errno to determine whether a syscall has failed, so we +need to ensure that accessing errno is async-signal-safe. Currently, +we preserve the errno in sig_handler_common(), but it doesn't cover +every possible case. Let's do it in hard_handler() instead, which +is the signal handler we actually register. + +Signed-off-by: Tiwei Bie +Link: https://patch.msgid.link/20260106001228.1531146-2-tiwei.btw@antgroup.com +Signed-off-by: Johannes Berg +[florian: hard_handler() in 6.12 retains the to_irq_stack/from_irq_stack +loop from before the upstream SMP refactoring; errno save/restore is wrapped +around that loop rather than replacing sig_handler_common's existing save/restore] +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/um/os-Linux/signal.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c +index b11ed66c8bb0..94abc9e3ec7e 100644 +--- a/arch/um/os-Linux/signal.c ++++ b/arch/um/os-Linux/signal.c +@@ -190,6 +190,7 @@ static void hard_handler(int sig, siginfo_t *si, void *p) + { + ucontext_t *uc = p; + mcontext_t *mc = &uc->uc_mcontext; ++ int save_errno = errno; + unsigned long pending = 1UL << sig; + + do { +@@ -227,6 +228,8 @@ static void hard_handler(int sig, siginfo_t *si, void *p) + if (!nested) + pending = from_irq_stack(nested); + } while (pending); ++ ++ errno = save_errno; + } + + void set_handler(int sig) +-- +2.53.0 + diff --git a/staging-6.12/um-set-parent-death-signal-for-ubd-io-thread-process.patch b/staging-6.12/um-set-parent-death-signal-for-ubd-io-thread-process.patch new file mode 100644 index 0000000000..3093a8bf40 --- /dev/null +++ b/staging-6.12/um-set-parent-death-signal-for-ubd-io-thread-process.patch @@ -0,0 +1,37 @@ +From 408699d8e13653a3c67c7b46296aa9769d724203 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:14 -0700 +Subject: um: Set parent-death signal for ubd io thread/process + +From: Tiwei Bie + +commit 9b5e6c0f5a9199c69af81ac5bedc512ee7dc20b3 upstream. + +The ubd io thread is not really a traditional thread. Set the +parent-death signal for it to ensure that it will be killed if +the UML kernel dies unexpectedly without proper cleanup. + +Signed-off-by: Tiwei Bie +Link: https://patch.msgid.link/20241024142828.2612828-3-tiwei.btw@antgroup.com +Signed-off-by: Johannes Berg +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/um/drivers/ubd_kern.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c +index 2bfb17373244..66c1a8835e36 100644 +--- a/arch/um/drivers/ubd_kern.c ++++ b/arch/um/drivers/ubd_kern.c +@@ -1501,6 +1501,7 @@ int io_thread(void *arg) + { + int n, count, written, res; + ++ os_set_pdeathsig(); + os_fix_helper_signals(); + + while(1){ +-- +2.53.0 + diff --git a/staging-6.12/um-set-parent-death-signal-for-userspace-process.patch b/staging-6.12/um-set-parent-death-signal-for-userspace-process.patch new file mode 100644 index 0000000000..fbedd9faad --- /dev/null +++ b/staging-6.12/um-set-parent-death-signal-for-userspace-process.patch @@ -0,0 +1,42 @@ +From 3687234019560dee4029a54a0f6972a363126050 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:16 -0700 +Subject: um: Set parent death signal for userspace process + +From: Benjamin Berg + +commit 801e00d3a1b78b7f71675fae79946ff4aa3ee070 upstream. + +Enable PR_SET_PDEATHSIG so that the UML userspace process will be killed +when the kernel exits unexpectedly. + +Signed-off-by: Benjamin Berg +Link: https://patch.msgid.link/20240919124511.282088-4-benjamin@sipsolutions.net +Signed-off-by: Johannes Berg +[florian: upstream applies os_set_pdeathsig() in stub_exe.c, a file +introduced in v6.13 that does not exist in 6.12; applied instead to +userspace_tramp() in arch/um/os-Linux/skas/process.c, which is the +equivalent entry-point for the userspace process in 6.12] +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/um/os-Linux/skas/process.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c +index b6f656bcffb1..cca016b0b29b 100644 +--- a/arch/um/os-Linux/skas/process.c ++++ b/arch/um/os-Linux/skas/process.c +@@ -214,6 +214,9 @@ static int userspace_tramp(void *stack) + (unsigned long) stub_segv_handler - + (unsigned long) __syscall_stub_start; + ++ /* Make sure this process dies if the kernel dies */ ++ os_set_pdeathsig(); ++ + ptrace(PTRACE_TRACEME, 0, 0, 0); + + signal(SIGTERM, SIG_DFL); +-- +2.53.0 + diff --git a/staging-6.12/um-set-parent-death-signal-for-winch-thread-process.patch b/staging-6.12/um-set-parent-death-signal-for-winch-thread-process.patch new file mode 100644 index 0000000000..5732a818ef --- /dev/null +++ b/staging-6.12/um-set-parent-death-signal-for-winch-thread-process.patch @@ -0,0 +1,46 @@ +From e647349d6a3269915223107e640d0543c6a7fff1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:12 -0700 +Subject: um: Set parent death signal for winch thread/process + +From: Benjamin Berg + +commit fdb2ecd35d327a1fc6bba69b97f85b494e1f4b6b upstream. + +The winch "thread" is really a separate process. Using prctl to set +PR_SET_PDEATHSIG ensures that this separate thread will be killed if the +UML kernel itself dies unexpectedly and does not perform proper cleanup. + +Signed-off-by: Benjamin Berg +Link: https://patch.msgid.link/20240919124511.282088-5-benjamin@sipsolutions.net +Signed-off-by: Johannes Berg +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/um/drivers/chan_user.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c +index a66e556012c4..1434114b2f34 100644 +--- a/arch/um/drivers/chan_user.c ++++ b/arch/um/drivers/chan_user.c +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include "chan_user.h" + #include + #include +@@ -161,6 +162,8 @@ static __noreturn int winch_thread(void *arg) + int count; + char c = 1; + ++ prctl(PR_SET_PDEATHSIG, SIGKILL); ++ + pty_fd = data->pty_fd; + pipe_fd = data->pipe_fd; + count = write(pipe_fd, &c, sizeof(c)); +-- +2.53.0 + diff --git a/staging-6.12/um-set-parent-death-signal-for-write_sigio-thread-pr.patch b/staging-6.12/um-set-parent-death-signal-for-write_sigio-thread-pr.patch new file mode 100644 index 0000000000..4b7b93179f --- /dev/null +++ b/staging-6.12/um-set-parent-death-signal-for-write_sigio-thread-pr.patch @@ -0,0 +1,37 @@ +From 673cc33a4e6f912332ee52995f6e502cbbce237c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:15 -0700 +Subject: um: Set parent-death signal for write_sigio thread/process + +From: Tiwei Bie + +commit c6c4adee65969218b0b7b13f568fd2c6f2333373 upstream. + +The write_sigio thread is not really a traditional thread. Set +the parent-death signal for it to ensure that it will be killed +if the UML kernel dies unexpectedly without proper cleanup. + +Signed-off-by: Tiwei Bie +Link: https://patch.msgid.link/20241024142828.2612828-4-tiwei.btw@antgroup.com +Signed-off-by: Johannes Berg +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/um/os-Linux/sigio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c +index 9e71794839e8..9aac8def4d63 100644 +--- a/arch/um/os-Linux/sigio.c ++++ b/arch/um/os-Linux/sigio.c +@@ -55,6 +55,7 @@ static int write_sigio_thread(void *unused) + int i, n, respond_fd; + char c; + ++ os_set_pdeathsig(); + os_fix_helper_signals(); + fds = ¤t_poll; + while (1) { +-- +2.53.0 + diff --git a/staging-6.12/um-use-os_set_pdeathsig-helper-in-winch-thread-proce.patch b/staging-6.12/um-use-os_set_pdeathsig-helper-in-winch-thread-proce.patch new file mode 100644 index 0000000000..af375f89b3 --- /dev/null +++ b/staging-6.12/um-use-os_set_pdeathsig-helper-in-winch-thread-proce.patch @@ -0,0 +1,45 @@ +From abd611a92fa1292dd99599b737bd2f4d37d28a6e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jul 2026 14:41:13 -0700 +Subject: um: Use os_set_pdeathsig helper in winch thread/process + +From: Tiwei Bie + +commit 42b8b00c8ab1ac18fccde3f29ee589626a561ea7 upstream. + +Since we have a helper now, let's switch to using it. It will make +the code slightly more consistent. + +Signed-off-by: Tiwei Bie +Link: https://patch.msgid.link/20241024142828.2612828-5-tiwei.btw@antgroup.com +Signed-off-by: Johannes Berg +Signed-off-by: Florian Fainelli +Signed-off-by: Sasha Levin +--- + arch/um/drivers/chan_user.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c +index 1434114b2f34..35f9beeb19b3 100644 +--- a/arch/um/drivers/chan_user.c ++++ b/arch/um/drivers/chan_user.c +@@ -10,7 +10,6 @@ + #include + #include + #include +-#include + #include "chan_user.h" + #include + #include +@@ -162,7 +161,7 @@ static __noreturn int winch_thread(void *arg) + int count; + char c = 1; + +- prctl(PR_SET_PDEATHSIG, SIGKILL); ++ os_set_pdeathsig(); + + pty_fd = data->pty_fd; + pipe_fd = data->pipe_fd; +-- +2.53.0 + diff --git a/staging-6.18/kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch b/staging-6.18/kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch new file mode 100644 index 0000000000..5fc6f446c6 --- /dev/null +++ b/staging-6.18/kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch @@ -0,0 +1,113 @@ +From 42f59bd030c2a0b67e6c69933b80cb9cb73b7530 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Feb 2026 18:16:36 +0545 +Subject: kunit: tool: skip stty when stdin is not a tty + +From: Shuvam Pandey + +[ Upstream commit e42c349f4cdfa43cb39a68c8f764f8cafc23a9a9 ] + +run_kernel() cleanup and signal_handler() invoke stty unconditionally. +When stdin is not a tty (for example in CI or unit tests), this writes +noise to stderr. + +Call stty only when stdin is a tty. + +Add regression tests for these paths: +- run_kernel() with non-tty stdin +- signal_handler() with non-tty stdin +- signal_handler() with tty stdin + +Signed-off-by: Shuvam Pandey +Reviewed-by: David Gow +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + tools/testing/kunit/kunit_kernel.py | 10 ++++-- + tools/testing/kunit/kunit_tool_test.py | 42 ++++++++++++++++++++++++++ + 2 files changed, 50 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py +index 2998e1bc088b..b610fcf0715a 100644 +--- a/tools/testing/kunit/kunit_kernel.py ++++ b/tools/testing/kunit/kunit_kernel.py +@@ -345,6 +345,12 @@ class LinuxSourceTree: + return False + return self.validate_config(build_dir) + ++ def _restore_terminal_if_tty(self) -> None: ++ # stty requires a controlling terminal; skip headless runs. ++ if sys.stdin is None or not sys.stdin.isatty(): ++ return ++ subprocess.call(['stty', 'sane']) ++ + def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]: + # Copy to avoid mutating the caller-supplied list. exec_tests() reuses + # the same args across repeated run_kernel() calls (e.g. --run_isolated), +@@ -386,8 +392,8 @@ class LinuxSourceTree: + process.stdout.close() + + waiter.join() +- subprocess.call(['stty', 'sane']) ++ self._restore_terminal_if_tty() + + def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None: + logging.error('Build interruption occurred. Cleaning console.') +- subprocess.call(['stty', 'sane']) ++ self._restore_terminal_if_tty() +diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py +index ed45bac1548d..0eb61de9abd4 100755 +--- a/tools/testing/kunit/kunit_tool_test.py ++++ b/tools/testing/kunit/kunit_tool_test.py +@@ -515,6 +515,48 @@ class LinuxSourceTreeTest(unittest.TestCase): + self.assertIn('kunit.filter_glob=suite.test1', start_calls[0]) + self.assertIn('kunit.filter_glob=suite.test2', start_calls[1]) + ++ def test_run_kernel_skips_terminal_reset_without_tty(self): ++ def fake_start(unused_args, unused_build_dir): ++ return subprocess.Popen(['printf', 'KTAP version 1\n'], ++ text=True, stdout=subprocess.PIPE) ++ ++ non_tty_stdin = mock.Mock() ++ non_tty_stdin.isatty.return_value = False ++ ++ with tempfile.TemporaryDirectory('') as build_dir: ++ tree = kunit_kernel.LinuxSourceTree(build_dir, kunitconfig_paths=[os.devnull]) ++ with mock.patch.object(tree._ops, 'start', side_effect=fake_start), \ ++ mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ ++ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call: ++ for _ in tree.run_kernel(build_dir=build_dir): ++ pass ++ ++ mock_call.assert_not_called() ++ ++ def test_signal_handler_skips_terminal_reset_without_tty(self): ++ non_tty_stdin = mock.Mock() ++ non_tty_stdin.isatty.return_value = False ++ tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull]) ++ ++ with mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ ++ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ ++ mock.patch.object(kunit_kernel.logging, 'error') as mock_error: ++ tree.signal_handler(signal.SIGINT, None) ++ mock_error.assert_called_once() ++ mock_call.assert_not_called() ++ ++ def test_signal_handler_resets_terminal_with_tty(self): ++ tty_stdin = mock.Mock() ++ tty_stdin.isatty.return_value = True ++ tree = kunit_kernel.LinuxSourceTree('', kunitconfig_paths=[os.devnull]) ++ ++ with mock.patch.object(kunit_kernel.sys, 'stdin', tty_stdin), \ ++ mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ ++ mock.patch.object(kunit_kernel.logging, 'error') as mock_error: ++ tree.signal_handler(signal.SIGINT, None) ++ mock_error.assert_called_once() ++ mock_call.assert_called_once_with(['stty', 'sane']) ++ + def test_build_reconfig_no_config(self): + with tempfile.TemporaryDirectory('') as build_dir: + with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f: +-- +2.53.0 + diff --git a/staging-6.18/kunit-tool-terminate-kernel-under-test-on-sigint.patch b/staging-6.18/kunit-tool-terminate-kernel-under-test-on-sigint.patch new file mode 100644 index 0000000000..4bfcb4d77c --- /dev/null +++ b/staging-6.18/kunit-tool-terminate-kernel-under-test-on-sigint.patch @@ -0,0 +1,108 @@ +From eed15c78086d33e928d7c796782883f2b1a3c3c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 28 Feb 2026 18:07:22 +0800 +Subject: kunit: tool: Terminate kernel under test on SIGINT + +From: David Gow + +[ Upstream commit 8f260b02eeeffbf2263c2b82b6e3e32fd73cde2b ] + +kunit.py will attempt to catch SIGINT / ^C in order to ensure the TTY isn't +messed up, but never actually attempts to terminate the running kernel (be +it UML or QEMU). This can lead to a bit of frustration if the kernel has +crashed or hung. + +Terminate the kernel process in the signal handler, if it's running. This +requires plumbing through the process handle in a few more places (and +having some checks to see if the kernel is still running in places where it +may have already been killed). + +Reported-by: Andy Shevchenko +Closes: https://lore.kernel.org/all/aaFmiAmg9S18EANA@smile.fi.intel.com/ +Signed-off-by: David Gow +Reviewed-by: Andy Shevchenko +Tested-by: Andy Shevchenko +Signed-off-by: Shuah Khan +Signed-off-by: Sasha Levin +--- + tools/testing/kunit/kunit_kernel.py | 28 +++++++++++++++++++--------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py +index b610fcf0715a..2869fcb199ff 100644 +--- a/tools/testing/kunit/kunit_kernel.py ++++ b/tools/testing/kunit/kunit_kernel.py +@@ -16,7 +16,7 @@ import shutil + import signal + import sys + import threading +-from typing import Iterator, List, Optional, Tuple ++from typing import Iterator, List, Optional, Tuple, Any + from types import FrameType + + import kunit_config +@@ -265,6 +265,7 @@ class LinuxSourceTree: + if kconfig_add: + kconfig = kunit_config.parse_from_string('\n'.join(kconfig_add)) + self._kconfig.merge_in_entries(kconfig) ++ self._process : Optional[subprocess.Popen[Any]] = None + + def arch(self) -> str: + return self._arch +@@ -364,36 +365,45 @@ class LinuxSourceTree: + args.append('kunit.filter_action=' + filter_action) + args.append('kunit.enable=1') + +- process = self._ops.start(args, build_dir) +- assert process.stdout is not None # tell mypy it's set ++ self._process = self._ops.start(args, build_dir) ++ assert self._process is not None # tell mypy it's set ++ assert self._process.stdout is not None # tell mypy it's set + + # Enforce the timeout in a background thread. + def _wait_proc() -> None: + try: +- process.wait(timeout=timeout) ++ if self._process: ++ self._process.wait(timeout=timeout) + except Exception as e: + print(e) +- process.terminate() +- process.wait() ++ if self._process: ++ self._process.terminate() ++ self._process.wait() + waiter = threading.Thread(target=_wait_proc) + waiter.start() + + output = open(get_outfile_path(build_dir), 'w') + try: + # Tee the output to the file and to our caller in real time. +- for line in process.stdout: ++ for line in self._process.stdout: + output.write(line) + yield line + # This runs even if our caller doesn't consume every line. + finally: + # Flush any leftover output to the file +- output.write(process.stdout.read()) ++ if self._process: ++ if self._process.stdout: ++ output.write(self._process.stdout.read()) ++ self._process.stdout.close() ++ self._process = None + output.close() +- process.stdout.close() + + waiter.join() + self._restore_terminal_if_tty() + + def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameType]) -> None: + logging.error('Build interruption occurred. Cleaning console.') ++ if self._process: ++ self._process.terminate() ++ self._process.wait() + self._restore_terminal_if_tty() +-- +2.53.0 + diff --git a/staging-6.18/netfilter-nf_conntrack_expect-restore-helper-propaga.patch b/staging-6.18/netfilter-nf_conntrack_expect-restore-helper-propaga.patch new file mode 100644 index 0000000000..897b0dc4d9 --- /dev/null +++ b/staging-6.18/netfilter-nf_conntrack_expect-restore-helper-propaga.patch @@ -0,0 +1,267 @@ +From d62208db655c54195997cf6167371005d3b37f05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 13:00:28 +0200 +Subject: netfilter: nf_conntrack_expect: restore helper propagation via + expectation + +From: Pablo Neira Ayuso + +[ Upstream commit dcb0f9aefdd604d36710fda53c25bd7cf4a3e37a ] + +A recent series to fix expectations broke helper propagation via +expectation, this mechanism is used by the sip and h323 helper. This +also propagates the conntrack helper to expected connections. I changed +semantics of exp->helper which now tells us the actual helper that +created the expectation. + +Add an explicit assign_helper field to expectations for this purpose +and update helpers to use it. + +Restore this feature for userspace conntrack helper via ctnetlink +nfqueue integration so it is again possible to attach a helper to an +expectation, where it makes sense. This is not restored via ctnetlink +expectation creation as there is no client for such feature. Use the +expectation layer 4 protocol number for the helper lookup for +consistency. + +Make sure the expectation using this helper propagation mechanism also +go away when the helper is unregistered. + +Fixes: 9c42bc9db90a ("netfilter: nf_conntrack_expect: honor expectation helper field") +Fixes: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Reported-by: Ilya Maximets +Tested-by: Ilya Maximets +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_expect.h | 5 ++++- + net/netfilter/nf_conntrack_broadcast.c | 1 + + net/netfilter/nf_conntrack_core.c | 7 +++++-- + net/netfilter/nf_conntrack_expect.c | 1 + + net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------ + net/netfilter/nf_conntrack_helper.c | 5 +++++ + net/netfilter/nf_conntrack_netlink.c | 18 ++++++++++++++++-- + net/netfilter/nf_conntrack_sip.c | 2 +- + 8 files changed, 39 insertions(+), 12 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h +index e9a8350e7ccf..80f50fd0f7ad 100644 +--- a/include/net/netfilter/nf_conntrack_expect.h ++++ b/include/net/netfilter/nf_conntrack_expect.h +@@ -45,9 +45,12 @@ struct nf_conntrack_expect { + void (*expectfn)(struct nf_conn *new, + struct nf_conntrack_expect *this); + +- /* Helper to assign to new connection */ ++ /* Helper that created this expectation */ + struct nf_conntrack_helper __rcu *helper; + ++ /* Helper to assign to new connection */ ++ struct nf_conntrack_helper __rcu *assign_helper; ++ + /* The conntrack of the master connection */ + struct nf_conn *master; + +diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c +index 4f39bf7c843f..75e53fde6b29 100644 +--- a/net/netfilter/nf_conntrack_broadcast.c ++++ b/net/netfilter/nf_conntrack_broadcast.c +@@ -72,6 +72,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->class = NF_CT_EXPECT_CLASS_DEFAULT; + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index a877f9ad1cf2..44fa3224cc87 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1771,14 +1771,17 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, + spin_lock_bh(&nf_conntrack_expect_lock); + exp = nf_ct_find_expectation(net, zone, tuple, !tmpl || nf_ct_is_confirmed(tmpl)); + if (exp) { ++ struct nf_conntrack_helper *assign_helper; ++ + /* Welcome, Mr. Bond. We've been expecting you... */ + __set_bit(IPS_EXPECTED_BIT, &ct->status); + /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ + ct->master = exp->master; +- if (exp->helper) { ++ assign_helper = rcu_dereference(exp->assign_helper); ++ if (assign_helper) { + help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); + if (help) +- rcu_assign_pointer(help->helper, exp->helper); ++ rcu_assign_pointer(help->helper, assign_helper); + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index 24d0576d84b7..8e943efbdf0a 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -344,6 +344,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, + helper = rcu_dereference(help->helper); + + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c +index bd7e9e13e4f6..a116c6629e2b 100644 +--- a/net/netfilter/nf_conntrack_h323_main.c ++++ b/net/netfilter/nf_conntrack_h323_main.c +@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245); ++ rcu_assign_pointer(exp->assign_helper, &nf_conntrack_helper_h245); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3 : NULL, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */ + + nathook = rcu_dereference(nfct_h323_nat_hook); +@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_UDP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect RAS "); +@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index 9150bcfd7ca8..ea0cdb7ec915 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -419,6 +419,11 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data) + + this = rcu_dereference_protected(exp->helper, + lockdep_is_held(&nf_conntrack_expect_lock)); ++ if (this == me) ++ return true; ++ ++ this = rcu_dereference_protected(exp->assign_helper, ++ lockdep_is_held(&nf_conntrack_expect_lock)); + return this == me; + } + +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index c8fe284b86db..3df7e5fc76c8 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -2635,6 +2635,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask); + +@@ -2861,6 +2862,7 @@ static int + ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + u32 portid, u32 report) + { ++ struct nf_conntrack_helper *assign_helper = NULL; + struct nlattr *cda[CTA_EXPECT_MAX+1]; + struct nf_conntrack_tuple tuple, mask; + struct nf_conntrack_expect *exp; +@@ -2876,8 +2878,18 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + if (err < 0) + return err; + ++ if (cda[CTA_EXPECT_HELP_NAME]) { ++ const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); ++ ++ assign_helper = __nf_conntrack_helper_find(helpname, ++ nf_ct_l3num(ct), ++ tuple.dst.protonum); ++ if (!assign_helper) ++ return -EOPNOTSUPP; ++ } ++ + exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct, +- &tuple, &mask); ++ assign_helper, &tuple, &mask); + if (IS_ERR(exp)) + return PTR_ERR(exp); + +@@ -3516,6 +3528,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr, + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask) + { +@@ -3569,6 +3582,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, + exp->zone = ct->zone; + #endif + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, assign_helper); + exp->tuple = *tuple; + exp->mask.src.u3 = mask->src.u3; + exp->mask.src.u.all = mask->src.u.all; +@@ -3624,7 +3638,7 @@ ctnetlink_create_expect(struct net *net, + ct = nf_ct_tuplehash_to_ctrack(h); + + rcu_read_lock(); +- exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask); ++ exp = ctnetlink_alloc_expect(cda, ct, NULL, &tuple, &mask); + if (IS_ERR(exp)) { + err = PTR_ERR(exp); + goto err_rcu; +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index 147043f19521..4bebf66410ea 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -1386,7 +1386,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), + saddr, &daddr, proto, NULL, &port); + exp->timeout.expires = sip_timeout * HZ; +- rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, helper); + exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; + + hooks = rcu_dereference(nf_nat_sip_hooks); +-- +2.53.0 + diff --git a/staging-6.18/series b/staging-6.18/series new file mode 100644 index 0000000000..e31db453cc --- /dev/null +++ b/staging-6.18/series @@ -0,0 +1,3 @@ +netfilter-nf_conntrack_expect-restore-helper-propaga.patch +kunit-tool-skip-stty-when-stdin-is-not-a-tty.patch +kunit-tool-terminate-kernel-under-test-on-sigint.patch diff --git a/staging-6.6/netfilter-nf_conntrack_expect-restore-helper-propaga.patch b/staging-6.6/netfilter-nf_conntrack_expect-restore-helper-propaga.patch new file mode 100644 index 0000000000..8198a09d8d --- /dev/null +++ b/staging-6.6/netfilter-nf_conntrack_expect-restore-helper-propaga.patch @@ -0,0 +1,267 @@ +From 33f187d9cabd808cf402623dbb83dc37ea899767 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 May 2026 13:00:28 +0200 +Subject: netfilter: nf_conntrack_expect: restore helper propagation via + expectation + +From: Pablo Neira Ayuso + +[ Upstream commit dcb0f9aefdd604d36710fda53c25bd7cf4a3e37a ] + +A recent series to fix expectations broke helper propagation via +expectation, this mechanism is used by the sip and h323 helper. This +also propagates the conntrack helper to expected connections. I changed +semantics of exp->helper which now tells us the actual helper that +created the expectation. + +Add an explicit assign_helper field to expectations for this purpose +and update helpers to use it. + +Restore this feature for userspace conntrack helper via ctnetlink +nfqueue integration so it is again possible to attach a helper to an +expectation, where it makes sense. This is not restored via ctnetlink +expectation creation as there is no client for such feature. Use the +expectation layer 4 protocol number for the helper lookup for +consistency. + +Make sure the expectation using this helper propagation mechanism also +go away when the helper is unregistered. + +Fixes: 9c42bc9db90a ("netfilter: nf_conntrack_expect: honor expectation helper field") +Fixes: 917b61fa2042 ("netfilter: ctnetlink: ignore explicit helper on new expectations") +Reported-by: Ilya Maximets +Tested-by: Ilya Maximets +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Sasha Levin +--- + include/net/netfilter/nf_conntrack_expect.h | 5 ++++- + net/netfilter/nf_conntrack_broadcast.c | 1 + + net/netfilter/nf_conntrack_core.c | 7 +++++-- + net/netfilter/nf_conntrack_expect.c | 1 + + net/netfilter/nf_conntrack_h323_main.c | 12 ++++++------ + net/netfilter/nf_conntrack_helper.c | 5 +++++ + net/netfilter/nf_conntrack_netlink.c | 18 ++++++++++++++++-- + net/netfilter/nf_conntrack_sip.c | 2 +- + 8 files changed, 39 insertions(+), 12 deletions(-) + +diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h +index e9a8350e7ccf..80f50fd0f7ad 100644 +--- a/include/net/netfilter/nf_conntrack_expect.h ++++ b/include/net/netfilter/nf_conntrack_expect.h +@@ -45,9 +45,12 @@ struct nf_conntrack_expect { + void (*expectfn)(struct nf_conn *new, + struct nf_conntrack_expect *this); + +- /* Helper to assign to new connection */ ++ /* Helper that created this expectation */ + struct nf_conntrack_helper __rcu *helper; + ++ /* Helper to assign to new connection */ ++ struct nf_conntrack_helper __rcu *assign_helper; ++ + /* The conntrack of the master connection */ + struct nf_conn *master; + +diff --git a/net/netfilter/nf_conntrack_broadcast.c b/net/netfilter/nf_conntrack_broadcast.c +index d44d9379a8a0..ef8a7ca8c116 100644 +--- a/net/netfilter/nf_conntrack_broadcast.c ++++ b/net/netfilter/nf_conntrack_broadcast.c +@@ -72,6 +72,7 @@ int nf_conntrack_broadcast_help(struct sk_buff *skb, + exp->flags = NF_CT_EXPECT_PERMANENT; + exp->class = NF_CT_EXPECT_CLASS_DEFAULT; + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c +index b086670ec90d..bed9c370fd70 100644 +--- a/net/netfilter/nf_conntrack_core.c ++++ b/net/netfilter/nf_conntrack_core.c +@@ -1729,14 +1729,17 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, + spin_lock_bh(&nf_conntrack_expect_lock); + exp = nf_ct_find_expectation(net, zone, tuple, !tmpl || nf_ct_is_confirmed(tmpl)); + if (exp) { ++ struct nf_conntrack_helper *assign_helper; ++ + /* Welcome, Mr. Bond. We've been expecting you... */ + __set_bit(IPS_EXPECTED_BIT, &ct->status); + /* exp->master safe, refcnt bumped in nf_ct_find_expectation */ + ct->master = exp->master; +- if (exp->helper) { ++ assign_helper = rcu_dereference(exp->assign_helper); ++ if (assign_helper) { + help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); + if (help) +- rcu_assign_pointer(help->helper, exp->helper); ++ rcu_assign_pointer(help->helper, assign_helper); + } + + #ifdef CONFIG_NF_CONNTRACK_MARK +diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c +index 379711ea5ab6..34324dece89d 100644 +--- a/net/netfilter/nf_conntrack_expect.c ++++ b/net/netfilter/nf_conntrack_expect.c +@@ -344,6 +344,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, + helper = rcu_dereference(help->helper); + + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, NULL); + write_pnet(&exp->net, net); + #ifdef CONFIG_NF_CONNTRACK_ZONES + exp->zone = ct->zone; +diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c +index 791aafe9f396..c42547284f35 100644 +--- a/net/netfilter/nf_conntrack_h323_main.c ++++ b/net/netfilter/nf_conntrack_h323_main.c +@@ -642,7 +642,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, &nf_conntrack_helper_h245); ++ rcu_assign_pointer(exp->assign_helper, &nf_conntrack_helper_h245); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -766,7 +766,7 @@ static int expect_callforwarding(struct sk_buff *skb, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + nathook = rcu_dereference(nfct_h323_nat_hook); + if (memcmp(&ct->tuplehash[dir].tuple.src.u3, +@@ -1233,7 +1233,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3 : NULL, + &ct->tuplehash[!dir].tuple.dst.u3, + IPPROTO_TCP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + exp->flags = NF_CT_EXPECT_PERMANENT; /* Accept multiple calls */ + + nathook = rcu_dereference(nfct_h323_nat_hook); +@@ -1305,7 +1305,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_UDP, NULL, &port); +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_ras); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_ras); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect RAS "); +@@ -1522,7 +1522,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +@@ -1576,7 +1576,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, + &ct->tuplehash[!dir].tuple.src.u3, &addr, + IPPROTO_TCP, NULL, &port); + exp->flags = NF_CT_EXPECT_PERMANENT; +- rcu_assign_pointer(exp->helper, nf_conntrack_helper_q931); ++ rcu_assign_pointer(exp->assign_helper, nf_conntrack_helper_q931); + + if (nf_ct_expect_related(exp, 0) == 0) { + pr_debug("nf_ct_ras: expect Q.931 "); +diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c +index 1d449e825dc6..7174369e5aa6 100644 +--- a/net/netfilter/nf_conntrack_helper.c ++++ b/net/netfilter/nf_conntrack_helper.c +@@ -424,6 +424,11 @@ static bool expect_iter_me(struct nf_conntrack_expect *exp, void *data) + + this = rcu_dereference_protected(exp->helper, + lockdep_is_held(&nf_conntrack_expect_lock)); ++ if (this == me) ++ return true; ++ ++ this = rcu_dereference_protected(exp->assign_helper, ++ lockdep_is_held(&nf_conntrack_expect_lock)); + return this == me; + } + +diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c +index 1028ed8ac485..c9bbe25f2d67 100644 +--- a/net/netfilter/nf_conntrack_netlink.c ++++ b/net/netfilter/nf_conntrack_netlink.c +@@ -2624,6 +2624,7 @@ static const struct nla_policy exp_nla_policy[CTA_EXPECT_MAX+1] = { + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr *const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask); + +@@ -2850,6 +2851,7 @@ static int + ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + u32 portid, u32 report) + { ++ struct nf_conntrack_helper *assign_helper = NULL; + struct nlattr *cda[CTA_EXPECT_MAX+1]; + struct nf_conntrack_tuple tuple, mask; + struct nf_conntrack_expect *exp; +@@ -2865,8 +2867,18 @@ ctnetlink_glue_attach_expect(const struct nlattr *attr, struct nf_conn *ct, + if (err < 0) + return err; + ++ if (cda[CTA_EXPECT_HELP_NAME]) { ++ const char *helpname = nla_data(cda[CTA_EXPECT_HELP_NAME]); ++ ++ assign_helper = __nf_conntrack_helper_find(helpname, ++ nf_ct_l3num(ct), ++ tuple.dst.protonum); ++ if (!assign_helper) ++ return -EOPNOTSUPP; ++ } ++ + exp = ctnetlink_alloc_expect((const struct nlattr * const *)cda, ct, +- &tuple, &mask); ++ assign_helper, &tuple, &mask); + if (IS_ERR(exp)) + return PTR_ERR(exp); + +@@ -3505,6 +3517,7 @@ ctnetlink_parse_expect_nat(const struct nlattr *attr, + + static struct nf_conntrack_expect * + ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, ++ const struct nf_conntrack_helper *assign_helper, + struct nf_conntrack_tuple *tuple, + struct nf_conntrack_tuple *mask) + { +@@ -3558,6 +3571,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct, + exp->zone = ct->zone; + #endif + rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, assign_helper); + exp->tuple = *tuple; + exp->mask.src.u3 = mask->src.u3; + exp->mask.src.u.all = mask->src.u.all; +@@ -3613,7 +3627,7 @@ ctnetlink_create_expect(struct net *net, + ct = nf_ct_tuplehash_to_ctrack(h); + + rcu_read_lock(); +- exp = ctnetlink_alloc_expect(cda, ct, &tuple, &mask); ++ exp = ctnetlink_alloc_expect(cda, ct, NULL, &tuple, &mask); + if (IS_ERR(exp)) { + err = PTR_ERR(exp); + goto err_rcu; +diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c +index bd91b8b47f4b..852c0b74b8a7 100644 +--- a/net/netfilter/nf_conntrack_sip.c ++++ b/net/netfilter/nf_conntrack_sip.c +@@ -1386,7 +1386,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff, + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), + saddr, &daddr, proto, NULL, &port); + exp->timeout.expires = sip_timeout * HZ; +- rcu_assign_pointer(exp->helper, helper); ++ rcu_assign_pointer(exp->assign_helper, helper); + exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; + + hooks = rcu_dereference(nf_nat_sip_hooks); +-- +2.53.0 + diff --git a/staging-6.6/series b/staging-6.6/series new file mode 100644 index 0000000000..9de0fac578 --- /dev/null +++ b/staging-6.6/series @@ -0,0 +1 @@ +netfilter-nf_conntrack_expect-restore-helper-propaga.patch