From: Sasha Levin Date: Fri, 17 Jul 2026 01:37:11 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f104c1ab752af5c8f9c53348606c5ec0e34e91c6;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/staging-5.10/crypto-algif_skcipher-force-synchronous-processing-o.patch b/staging-5.10/crypto-algif_skcipher-force-synchronous-processing-o.patch new file mode 100644 index 0000000000..7b81dc9ebc --- /dev/null +++ b/staging-5.10/crypto-algif_skcipher-force-synchronous-processing-o.patch @@ -0,0 +1,116 @@ +From 26a93606e373b23307c5c531668aa7fb43b7a66d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 02:58:37 +0000 +Subject: crypto: algif_skcipher - force synchronous processing on trees + without ctx->state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Muhammet Kaan KILINÇ + +The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv +directly into the skcipher request. After io_submit() the socket lock is +dropped and the request is processed asynchronously, so a concurrent +sendmsg(ALG_SET_IV) can overwrite ctx->iv and make the in-flight request +run under an attacker-controlled IV. For CTR/stream modes this is +IV/keystream reuse and lets an unprivileged user recover the plaintext of +a concurrent operation. + +Snapshotting ctx->iv into per-request storage for the async path is not +sufficient. For ciphers with statesize == 0 - which includes cbc and ctr - +the MSG_MORE inter-chunk IV chaining is carried solely by the in-place +req->iv writeback, which a snapshot redirects into per-request memory that +af_alg_free_resources() releases on completion, silently producing wrong +output. Writing the IV back from the completion callback instead is not +possible either: that would require lock_sock() there, but the callback can +run in softirq/atomic context, so it must not sleep. + +Make the operation synchronous instead, which removes both the IV race and +any writeback race. This is equivalent to the upstream resolution, commit +fcc77d33a34c ("net: Remove support for AIO on sockets"), which removed the +AIO socket path across net/ entirely and so produces the same end state for +this file. This patch deviates from that commit deliberately: rather than +removing AIO socket support tree-wide, which would be far too invasive for +stable, it removes only the AIO branch in crypto/algif_skcipher.c. +io_submit() now completes synchronously; AF_ALG async is rarely used in +practice. + +The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, +and is left alone to keep the fix minimal. + +Tested on 6.6.y: attacker IV injection dropped from 2296/200000 to 0/200000 +after the change; MSG_MORE chunked CTR output bit-identical to single-shot. + +Reported-by: Muhammet Kaan KILINÇ +Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") +Cc: +Signed-off-by: Muhammet Kaan KILINÇ +Signed-off-by: Sasha Levin +--- + crypto/algif_skcipher.c | 49 +++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 31 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index 8b314260929fbb..6a1a71284fe823 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -107,37 +107,24 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, + areq->first_rsgl.sgl.sg, len, ctx->iv); + +- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { +- /* AIO operation */ +- sock_hold(sk); +- areq->iocb = msg->msg_iocb; +- +- /* Remember output size that will be generated. */ +- areq->outlen = len; +- +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP, +- af_alg_async_cb, areq); +- err = ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); +- +- /* AIO operation in progress */ +- if (err == -EINPROGRESS) +- return -EIOCBQUEUED; +- +- sock_put(sk); +- } else { +- /* Synchronous operation */ +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP | +- CRYPTO_TFM_REQ_MAY_BACKLOG, +- crypto_req_done, &ctx->wait); +- err = crypto_wait_req(ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), +- &ctx->wait); +- } ++ /* ++ * Force synchronous processing. The async (AIO) path passed the ++ * socket-wide ctx->iv into the request, which the worker ++ * dereferenced after the socket lock was dropped, letting a ++ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline ++ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove ++ * support for AIO on sockets"); these stable trees lack the ++ * per-request ctx->state used by newer kernels, so the minimal safe ++ * fix is to always complete synchronously. ++ */ ++ skcipher_request_set_callback(&areq->cra_u.skcipher_req, ++ CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &ctx->wait); ++ err = crypto_wait_req(ctx->enc ? ++ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : ++ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), ++ &ctx->wait); + + + free: +-- +2.53.0 + diff --git a/staging-5.10/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch b/staging-5.10/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch new file mode 100644 index 0000000000..148b4f2806 --- /dev/null +++ b/staging-5.10/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch @@ -0,0 +1,50 @@ +From dd3f92d0148dbd6d22628831a99b923cfb77b434 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Oct 2025 06:43:22 +0000 +Subject: sched/fair: Only update stats for allowed CPUs when looking for dst + group + +From: Adam Li + +[ Upstream commit 82d6e01a0699800efd8b048eb584c907ccb47b7a ] + +Load imbalance is observed when the workload frequently forks new threads. +Due to CPU affinity, the workload can run on CPU 0-7 in the first +group, and only on CPU 8-11 in the second group. CPU 12-15 are always idle. + +{ 0 1 2 3 4 5 6 7 } {8 9 10 11 12 13 14 15} + * * * * * * * * * * * * + +When looking for dst group for newly forked threads, in many times +update_sg_wakeup_stats() reports the second group has more idle CPUs +than the first group. The scheduler thinks the second group is less +busy. Then it selects least busy CPUs among CPU 8-11. Therefore CPU 8-11 +can be crowded with newly forked threads, at the same time CPU 0-7 +can be idle. + +A task may not use all the CPUs in a schedule group due to CPU affinity. +Only update schedule group statistics for allowed CPUs. + +Signed-off-by: Adam Li +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index c11d59bea0ea81..fa85b84fdbc533 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -8969,7 +8969,7 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd, + if (sd->flags & SD_ASYM_CPUCAPACITY) + sgs->group_misfit_task_load = 1; + +- for_each_cpu(i, sched_group_span(group)) { ++ for_each_cpu_and(i, sched_group_span(group), p->cpus_ptr) { + struct rq *rq = cpu_rq(i); + unsigned int local; + +-- +2.53.0 + diff --git a/staging-5.10/series b/staging-5.10/series new file mode 100644 index 0000000000..50d9ea5799 --- /dev/null +++ b/staging-5.10/series @@ -0,0 +1,3 @@ +sched-fair-only-update-stats-for-allowed-cpus-when-l.patch +crypto-algif_skcipher-force-synchronous-processing-o.patch +tools-mm-slabinfo-fix-total_objects-attribute-name.patch diff --git a/staging-5.10/tools-mm-slabinfo-fix-total_objects-attribute-name.patch b/staging-5.10/tools-mm-slabinfo-fix-total_objects-attribute-name.patch new file mode 100644 index 0000000000..b77c730843 --- /dev/null +++ b/staging-5.10/tools-mm-slabinfo-fix-total_objects-attribute-name.patch @@ -0,0 +1,51 @@ +From 5d08f3ee9a085c77c2662315abaf96203aa7c852 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 16:05:45 +0800 +Subject: tools/mm/slabinfo: fix total_objects attribute name + +From: Yichong Chen + +[ Upstream commit 892a7864730775c3dbee2a39e9ead4fa8d4256e7 ] + +SLUB exports the total_objects sysfs attribute, but slabinfo tries to read +objects_total. As a result, the lookup fails and the field remains zero. + +Use the correct attribute name and rename the corresponding structure +member to match. + +Fixes: 205ab99dd103 ("slub: Update statistics handling for variable order slabs") +Signed-off-by: Yichong Chen +Cc: +Reviewed-by: SeongJae Park +Link: https://patch.msgid.link/96556748872BB47E+20260612071359.649946-1-chenyichong@uniontech.com +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Sasha Levin +--- + tools/vm/slabinfo.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c +index 3ae985dc24b6d6..5819c4133e0d9c 100644 +--- a/tools/vm/slabinfo.c ++++ b/tools/vm/slabinfo.c +@@ -33,7 +33,7 @@ struct slabinfo { + unsigned int hwcache_align, object_size, objs_per_slab; + unsigned int sanity_checks, slab_size, store_user, trace; + int order, poison, reclaim_account, red_zone; +- unsigned long partial, objects, slabs, objects_partial, objects_total; ++ unsigned long partial, objects, slabs, objects_partial, total_objects; + unsigned long alloc_fastpath, alloc_slowpath; + unsigned long free_fastpath, free_slowpath; + unsigned long free_frozen, free_add_partial, free_remove_partial; +@@ -1232,7 +1232,7 @@ static void read_slab_dir(void) + slab->object_size = get_obj("object_size"); + slab->objects = get_obj("objects"); + slab->objects_partial = get_obj("objects_partial"); +- slab->objects_total = get_obj("objects_total"); ++ slab->total_objects = get_obj("total_objects"); + slab->objs_per_slab = get_obj("objs_per_slab"); + slab->order = get_obj("order"); + slab->partial = get_obj("partial"); +-- +2.53.0 + diff --git a/staging-5.15/crypto-algif_skcipher-force-synchronous-processing-o.patch b/staging-5.15/crypto-algif_skcipher-force-synchronous-processing-o.patch new file mode 100644 index 0000000000..1040377c22 --- /dev/null +++ b/staging-5.15/crypto-algif_skcipher-force-synchronous-processing-o.patch @@ -0,0 +1,116 @@ +From b903d0f50b611d24f32f460f354fb80bd49a1f6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 02:58:37 +0000 +Subject: crypto: algif_skcipher - force synchronous processing on trees + without ctx->state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Muhammet Kaan KILINÇ + +The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv +directly into the skcipher request. After io_submit() the socket lock is +dropped and the request is processed asynchronously, so a concurrent +sendmsg(ALG_SET_IV) can overwrite ctx->iv and make the in-flight request +run under an attacker-controlled IV. For CTR/stream modes this is +IV/keystream reuse and lets an unprivileged user recover the plaintext of +a concurrent operation. + +Snapshotting ctx->iv into per-request storage for the async path is not +sufficient. For ciphers with statesize == 0 - which includes cbc and ctr - +the MSG_MORE inter-chunk IV chaining is carried solely by the in-place +req->iv writeback, which a snapshot redirects into per-request memory that +af_alg_free_resources() releases on completion, silently producing wrong +output. Writing the IV back from the completion callback instead is not +possible either: that would require lock_sock() there, but the callback can +run in softirq/atomic context, so it must not sleep. + +Make the operation synchronous instead, which removes both the IV race and +any writeback race. This is equivalent to the upstream resolution, commit +fcc77d33a34c ("net: Remove support for AIO on sockets"), which removed the +AIO socket path across net/ entirely and so produces the same end state for +this file. This patch deviates from that commit deliberately: rather than +removing AIO socket support tree-wide, which would be far too invasive for +stable, it removes only the AIO branch in crypto/algif_skcipher.c. +io_submit() now completes synchronously; AF_ALG async is rarely used in +practice. + +The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, +and is left alone to keep the fix minimal. + +Tested on 6.6.y: attacker IV injection dropped from 2296/200000 to 0/200000 +after the change; MSG_MORE chunked CTR output bit-identical to single-shot. + +Reported-by: Muhammet Kaan KILINÇ +Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") +Cc: +Signed-off-by: Muhammet Kaan KILINÇ +Signed-off-by: Sasha Levin +--- + crypto/algif_skcipher.c | 49 +++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 31 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index 8b314260929fbb..6a1a71284fe823 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -107,37 +107,24 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, + areq->first_rsgl.sgl.sg, len, ctx->iv); + +- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { +- /* AIO operation */ +- sock_hold(sk); +- areq->iocb = msg->msg_iocb; +- +- /* Remember output size that will be generated. */ +- areq->outlen = len; +- +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP, +- af_alg_async_cb, areq); +- err = ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); +- +- /* AIO operation in progress */ +- if (err == -EINPROGRESS) +- return -EIOCBQUEUED; +- +- sock_put(sk); +- } else { +- /* Synchronous operation */ +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP | +- CRYPTO_TFM_REQ_MAY_BACKLOG, +- crypto_req_done, &ctx->wait); +- err = crypto_wait_req(ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), +- &ctx->wait); +- } ++ /* ++ * Force synchronous processing. The async (AIO) path passed the ++ * socket-wide ctx->iv into the request, which the worker ++ * dereferenced after the socket lock was dropped, letting a ++ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline ++ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove ++ * support for AIO on sockets"); these stable trees lack the ++ * per-request ctx->state used by newer kernels, so the minimal safe ++ * fix is to always complete synchronously. ++ */ ++ skcipher_request_set_callback(&areq->cra_u.skcipher_req, ++ CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &ctx->wait); ++ err = crypto_wait_req(ctx->enc ? ++ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : ++ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), ++ &ctx->wait); + + + free: +-- +2.53.0 + diff --git a/staging-5.15/net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch b/staging-5.15/net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch new file mode 100644 index 0000000000..2674a8a5ff --- /dev/null +++ b/staging-5.15/net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch @@ -0,0 +1,103 @@ +From 58247da1acbee7e96c744639d0b5bb5364797c48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Apr 2023 01:55:57 +0300 +Subject: net: dsa: tag_ksz: do not rely on skb_mac_header() in TX paths + +From: Vladimir Oltean + +[ Upstream commit 499b2491d550677b824b828ff431e4ef4d1d3b9d ] + +skb_mac_header() will no longer be available in the TX path when +reverting commit 6d1ccff62780 ("net: reset mac header in +dev_start_xmit()"). As preparation for that, let's use skb_eth_hdr() to +get to the Ethernet header's MAC DA instead, helper which assumes this +header is located at skb->data (assumption which holds true here). + +Signed-off-by: Vladimir Oltean +Reviewed-by: Eric Dumazet +Reviewed-by: Simon Horman +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +[ sashal: adjusted for missing tail tag PRIO (FIELD_PREP) and PTP tail + tag support in 5.15 ] +Signed-off-by: Sasha Levin +--- + net/dsa/tag_ksz.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c +index 00e4f40716dcbd..7c6c76254874aa 100644 +--- a/net/dsa/tag_ksz.c ++++ b/net/dsa/tag_ksz.c +@@ -51,18 +51,18 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, + static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct ethhdr *hdr; + u8 *tag; +- u8 *addr; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + return NULL; + + /* Tag encoding */ + tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); +- addr = skb_mac_header(skb); ++ hdr = skb_eth_hdr(skb); + + *tag = 1 << dp->index; +- if (is_link_local_ether_addr(addr)) ++ if (is_link_local_ether_addr(hdr->h_dest)) + *tag |= KSZ8795_TAIL_TAG_OVERRIDE; + + return skb; +@@ -119,8 +119,8 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, + struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct ethhdr *hdr; + __be16 *tag; +- u8 *addr; + u16 val; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) +@@ -128,11 +128,11 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, + + /* Tag encoding */ + tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN); +- addr = skb_mac_header(skb); ++ hdr = skb_eth_hdr(skb); + + val = BIT(dp->index); + +- if (is_link_local_ether_addr(addr)) ++ if (is_link_local_ether_addr(hdr->h_dest)) + val |= KSZ9477_TAIL_TAG_OVERRIDE; + + *tag = cpu_to_be16(val); +@@ -178,7 +178,7 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, + struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); +- u8 *addr; ++ struct ethhdr *hdr; + u8 *tag; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) +@@ -186,11 +186,11 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, + + /* Tag encoding */ + tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); +- addr = skb_mac_header(skb); ++ hdr = skb_eth_hdr(skb); + + *tag = BIT(dp->index); + +- if (is_link_local_ether_addr(addr)) ++ if (is_link_local_ether_addr(hdr->h_dest)) + *tag |= KSZ9893_TAIL_TAG_OVERRIDE; + + return skb; +-- +2.53.0 + diff --git a/staging-5.15/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch b/staging-5.15/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch new file mode 100644 index 0000000000..f346d01c2c --- /dev/null +++ b/staging-5.15/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch @@ -0,0 +1,50 @@ +From d02b761826e9c98329427245a38bb3184a4fb558 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Oct 2025 06:43:22 +0000 +Subject: sched/fair: Only update stats for allowed CPUs when looking for dst + group + +From: Adam Li + +[ Upstream commit 82d6e01a0699800efd8b048eb584c907ccb47b7a ] + +Load imbalance is observed when the workload frequently forks new threads. +Due to CPU affinity, the workload can run on CPU 0-7 in the first +group, and only on CPU 8-11 in the second group. CPU 12-15 are always idle. + +{ 0 1 2 3 4 5 6 7 } {8 9 10 11 12 13 14 15} + * * * * * * * * * * * * + +When looking for dst group for newly forked threads, in many times +update_sg_wakeup_stats() reports the second group has more idle CPUs +than the first group. The scheduler thinks the second group is less +busy. Then it selects least busy CPUs among CPU 8-11. Therefore CPU 8-11 +can be crowded with newly forked threads, at the same time CPU 0-7 +can be idle. + +A task may not use all the CPUs in a schedule group due to CPU affinity. +Only update schedule group statistics for allowed CPUs. + +Signed-off-by: Adam Li +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 87f32cf8aa0291..f2a58e54268ea3 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -9209,7 +9209,7 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd, + if (sd->flags & SD_ASYM_CPUCAPACITY) + sgs->group_misfit_task_load = 1; + +- for_each_cpu(i, sched_group_span(group)) { ++ for_each_cpu_and(i, sched_group_span(group), p->cpus_ptr) { + struct rq *rq = cpu_rq(i); + unsigned int local; + +-- +2.53.0 + diff --git a/staging-5.15/series b/staging-5.15/series new file mode 100644 index 0000000000..ebd8a577f1 --- /dev/null +++ b/staging-5.15/series @@ -0,0 +1,4 @@ +sched-fair-only-update-stats-for-allowed-cpus-when-l.patch +crypto-algif_skcipher-force-synchronous-processing-o.patch +tools-mm-slabinfo-fix-total_objects-attribute-name.patch +net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch diff --git a/staging-5.15/tools-mm-slabinfo-fix-total_objects-attribute-name.patch b/staging-5.15/tools-mm-slabinfo-fix-total_objects-attribute-name.patch new file mode 100644 index 0000000000..c080d6f449 --- /dev/null +++ b/staging-5.15/tools-mm-slabinfo-fix-total_objects-attribute-name.patch @@ -0,0 +1,51 @@ +From 2e8e4dfbbb2aed5f9416dd2810c37e2e412a27c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 16:11:50 +0800 +Subject: tools/mm/slabinfo: fix total_objects attribute name + +From: Yichong Chen + +[ Upstream commit 892a7864730775c3dbee2a39e9ead4fa8d4256e7 ] + +SLUB exports the total_objects sysfs attribute, but slabinfo tries to read +objects_total. As a result, the lookup fails and the field remains zero. + +Use the correct attribute name and rename the corresponding structure +member to match. + +Fixes: 205ab99dd103 ("slub: Update statistics handling for variable order slabs") +Signed-off-by: Yichong Chen +Cc: +Reviewed-by: SeongJae Park +Link: https://patch.msgid.link/96556748872BB47E+20260612071359.649946-1-chenyichong@uniontech.com +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Sasha Levin +--- + tools/vm/slabinfo.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c +index 0fffaeedee7672..d26a44e3e68470 100644 +--- a/tools/vm/slabinfo.c ++++ b/tools/vm/slabinfo.c +@@ -33,7 +33,7 @@ struct slabinfo { + unsigned int hwcache_align, object_size, objs_per_slab; + unsigned int sanity_checks, slab_size, store_user, trace; + int order, poison, reclaim_account, red_zone; +- unsigned long partial, objects, slabs, objects_partial, objects_total; ++ unsigned long partial, objects, slabs, objects_partial, total_objects; + unsigned long alloc_fastpath, alloc_slowpath; + unsigned long free_fastpath, free_slowpath; + unsigned long free_frozen, free_add_partial, free_remove_partial; +@@ -1254,7 +1254,7 @@ static void read_slab_dir(void) + slab->object_size = get_obj("object_size"); + slab->objects = get_obj("objects"); + slab->objects_partial = get_obj("objects_partial"); +- slab->objects_total = get_obj("objects_total"); ++ slab->total_objects = get_obj("total_objects"); + slab->objs_per_slab = get_obj("objs_per_slab"); + slab->order = get_obj("order"); + slab->partial = get_obj("partial"); +-- +2.53.0 + diff --git a/staging-6.1/crypto-algif_skcipher-force-synchronous-processing-o.patch b/staging-6.1/crypto-algif_skcipher-force-synchronous-processing-o.patch new file mode 100644 index 0000000000..476890ed27 --- /dev/null +++ b/staging-6.1/crypto-algif_skcipher-force-synchronous-processing-o.patch @@ -0,0 +1,116 @@ +From caaa06086f85652bbc262a8bbce924cd2a55a364 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 02:58:37 +0000 +Subject: crypto: algif_skcipher - force synchronous processing on trees + without ctx->state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Muhammet Kaan KILINÇ + +The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv +directly into the skcipher request. After io_submit() the socket lock is +dropped and the request is processed asynchronously, so a concurrent +sendmsg(ALG_SET_IV) can overwrite ctx->iv and make the in-flight request +run under an attacker-controlled IV. For CTR/stream modes this is +IV/keystream reuse and lets an unprivileged user recover the plaintext of +a concurrent operation. + +Snapshotting ctx->iv into per-request storage for the async path is not +sufficient. For ciphers with statesize == 0 - which includes cbc and ctr - +the MSG_MORE inter-chunk IV chaining is carried solely by the in-place +req->iv writeback, which a snapshot redirects into per-request memory that +af_alg_free_resources() releases on completion, silently producing wrong +output. Writing the IV back from the completion callback instead is not +possible either: that would require lock_sock() there, but the callback can +run in softirq/atomic context, so it must not sleep. + +Make the operation synchronous instead, which removes both the IV race and +any writeback race. This is equivalent to the upstream resolution, commit +fcc77d33a34c ("net: Remove support for AIO on sockets"), which removed the +AIO socket path across net/ entirely and so produces the same end state for +this file. This patch deviates from that commit deliberately: rather than +removing AIO socket support tree-wide, which would be far too invasive for +stable, it removes only the AIO branch in crypto/algif_skcipher.c. +io_submit() now completes synchronously; AF_ALG async is rarely used in +practice. + +The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, +and is left alone to keep the fix minimal. + +Tested on 6.6.y: attacker IV injection dropped from 2296/200000 to 0/200000 +after the change; MSG_MORE chunked CTR output bit-identical to single-shot. + +Reported-by: Muhammet Kaan KILINÇ +Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") +Cc: +Signed-off-by: Muhammet Kaan KILINÇ +Signed-off-by: Sasha Levin +--- + crypto/algif_skcipher.c | 49 +++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 31 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index 8b314260929fbb..6a1a71284fe823 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -107,37 +107,24 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, + areq->first_rsgl.sgl.sg, len, ctx->iv); + +- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { +- /* AIO operation */ +- sock_hold(sk); +- areq->iocb = msg->msg_iocb; +- +- /* Remember output size that will be generated. */ +- areq->outlen = len; +- +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP, +- af_alg_async_cb, areq); +- err = ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); +- +- /* AIO operation in progress */ +- if (err == -EINPROGRESS) +- return -EIOCBQUEUED; +- +- sock_put(sk); +- } else { +- /* Synchronous operation */ +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP | +- CRYPTO_TFM_REQ_MAY_BACKLOG, +- crypto_req_done, &ctx->wait); +- err = crypto_wait_req(ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), +- &ctx->wait); +- } ++ /* ++ * Force synchronous processing. The async (AIO) path passed the ++ * socket-wide ctx->iv into the request, which the worker ++ * dereferenced after the socket lock was dropped, letting a ++ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline ++ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove ++ * support for AIO on sockets"); these stable trees lack the ++ * per-request ctx->state used by newer kernels, so the minimal safe ++ * fix is to always complete synchronously. ++ */ ++ skcipher_request_set_callback(&areq->cra_u.skcipher_req, ++ CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &ctx->wait); ++ err = crypto_wait_req(ctx->enc ? ++ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : ++ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), ++ &ctx->wait); + + + free: +-- +2.53.0 + diff --git a/staging-6.1/fs-quota-create-dedicated-workqueue-for-quota_releas.patch b/staging-6.1/fs-quota-create-dedicated-workqueue-for-quota_releas.patch new file mode 100644 index 0000000000..9ca50db617 --- /dev/null +++ b/staging-6.1/fs-quota-create-dedicated-workqueue-for-quota_releas.patch @@ -0,0 +1,94 @@ +From 28dcce15dc6018b60aa7350cd62b75cd3fd91a8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 18:21:37 +0530 +Subject: fs: quota: create dedicated workqueue for quota_release_work + +From: Shashank A P + +commit 72b7ceca857f38a8ca7c5629feffc63769638974 upstream. + +There is a kernel panic due to WARN_ONCE when panic_on_warn is set. + +This issue occurs when writeback is triggered due to sync call for an +opened file(ie, writeback reason is WB_REASON_SYNC). When f2fs balance +is needed at sync path, flush for quota_release_work is triggered. +By default quota_release_work is queued to "events_unbound" queue which +does not have WQ_MEM_RECLAIM flag. During f2fs balance "writeback" +workqueue tries to flush quota_release_work causing kernel panic due to +MEM_RECLAIM flag mismatch errors. + +This patch creates dedicated workqueue with WQ_MEM_RECLAIM flag +for work quota_release_work. + +------------[ cut here ]------------ +WARNING: CPU: 4 PID: 14867 at kernel/workqueue.c:3721 check_flush_dependency+0x13c/0x148 +Call trace: + check_flush_dependency+0x13c/0x148 + __flush_work+0xd0/0x398 + flush_delayed_work+0x44/0x5c + dquot_writeback_dquots+0x54/0x318 + f2fs_do_quota_sync+0xb8/0x1a8 + f2fs_write_checkpoint+0x3cc/0x99c + f2fs_gc+0x190/0x750 + f2fs_balance_fs+0x110/0x168 + f2fs_write_single_data_page+0x474/0x7dc + f2fs_write_data_pages+0x7d0/0xd0c + do_writepages+0xe0/0x2f4 + __writeback_single_inode+0x44/0x4ac + writeback_sb_inodes+0x30c/0x538 + wb_writeback+0xf4/0x440 + wb_workfn+0x128/0x5d4 + process_scheduled_works+0x1c4/0x45c + worker_thread+0x32c/0x3e8 + kthread+0x11c/0x1b0 + ret_from_fork+0x10/0x20 +Kernel panic - not syncing: kernel: panic_on_warn set ... + +Fixes: ac6f420291b3 ("quota: flush quota_release_work upon quota writeback") +CC: stable@vger.kernel.org +Signed-off-by: Shashank A P +Link: https://patch.msgid.link/20250901092905.2115-1-shashank.ap@samsung.com +Signed-off-by: Jan Kara +Signed-off-by: Sasha Levin +--- + fs/quota/dquot.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c +index 0aa0ed754f2e09..f296872efda9e7 100644 +--- a/fs/quota/dquot.c ++++ b/fs/quota/dquot.c +@@ -163,6 +163,9 @@ static struct quota_module_name module_names[] = INIT_QUOTA_MODULE_NAMES; + /* SLAB cache for dquot structures */ + static struct kmem_cache *dquot_cachep; + ++/* workqueue for work quota_release_work*/ ++static struct workqueue_struct *quota_unbound_wq; ++ + int register_quota_format(struct quota_format_type *fmt) + { + spin_lock(&dq_list_lock); +@@ -916,7 +919,7 @@ void dqput(struct dquot *dquot) + put_releasing_dquots(dquot); + atomic_dec(&dquot->dq_count); + spin_unlock(&dq_list_lock); +- queue_delayed_work(system_unbound_wq, "a_release_work, 1); ++ queue_delayed_work(quota_unbound_wq, "a_release_work, 1); + } + EXPORT_SYMBOL(dqput); + +@@ -3091,6 +3094,11 @@ static int __init dquot_init(void) + if (register_shrinker(&dqcache_shrinker, "dquota-cache")) + panic("Cannot register dquot shrinker"); + ++ quota_unbound_wq = alloc_workqueue("quota_events_unbound", ++ WQ_UNBOUND | WQ_MEM_RECLAIM, WQ_MAX_ACTIVE); ++ if (!quota_unbound_wq) ++ panic("Cannot create quota_unbound_wq\n"); ++ + return 0; + } + fs_initcall(dquot_init); +-- +2.53.0 + diff --git a/staging-6.1/net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch b/staging-6.1/net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch new file mode 100644 index 0000000000..e3b092fa91 --- /dev/null +++ b/staging-6.1/net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch @@ -0,0 +1,103 @@ +From 9b9787a1cb4f3666113a93f63344e4ac9f95245a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Apr 2023 01:55:57 +0300 +Subject: net: dsa: tag_ksz: do not rely on skb_mac_header() in TX paths + +From: Vladimir Oltean + +[ Upstream commit 499b2491d550677b824b828ff431e4ef4d1d3b9d ] + +skb_mac_header() will no longer be available in the TX path when +reverting commit 6d1ccff62780 ("net: reset mac header in +dev_start_xmit()"). As preparation for that, let's use skb_eth_hdr() to +get to the Ethernet header's MAC DA instead, helper which assumes this +header is located at skb->data (assumption which holds true here). + +Signed-off-by: Vladimir Oltean +Reviewed-by: Eric Dumazet +Reviewed-by: Simon Horman +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +[ sashal: adjusted context in ksz9477_xmit() and ksz9893_xmit() for + missing tail tag PRIO support in 6.1 ] +Signed-off-by: Sasha Levin +--- + net/dsa/tag_ksz.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/net/dsa/tag_ksz.c b/net/dsa/tag_ksz.c +index d58bcd16d597d6..459f688cdbf898 100644 +--- a/net/dsa/tag_ksz.c ++++ b/net/dsa/tag_ksz.c +@@ -50,18 +50,18 @@ static struct sk_buff *ksz_common_rcv(struct sk_buff *skb, + static struct sk_buff *ksz8795_xmit(struct sk_buff *skb, struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct ethhdr *hdr; + u8 *tag; +- u8 *addr; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) + return NULL; + + /* Tag encoding */ + tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); +- addr = skb_mac_header(skb); ++ hdr = skb_eth_hdr(skb); + + *tag = 1 << dp->index; +- if (is_link_local_ether_addr(addr)) ++ if (is_link_local_ether_addr(hdr->h_dest)) + *tag |= KSZ8795_TAIL_TAG_OVERRIDE; + + return skb; +@@ -118,8 +118,8 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, + struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); ++ struct ethhdr *hdr; + __be16 *tag; +- u8 *addr; + u16 val; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) +@@ -127,11 +127,11 @@ static struct sk_buff *ksz9477_xmit(struct sk_buff *skb, + + /* Tag encoding */ + tag = skb_put(skb, KSZ9477_INGRESS_TAG_LEN); +- addr = skb_mac_header(skb); ++ hdr = skb_eth_hdr(skb); + + val = BIT(dp->index); + +- if (is_link_local_ether_addr(addr)) ++ if (is_link_local_ether_addr(hdr->h_dest)) + val |= KSZ9477_TAIL_TAG_OVERRIDE; + + *tag = cpu_to_be16(val); +@@ -177,7 +177,7 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, + struct net_device *dev) + { + struct dsa_port *dp = dsa_slave_to_port(dev); +- u8 *addr; ++ struct ethhdr *hdr; + u8 *tag; + + if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) +@@ -185,11 +185,11 @@ static struct sk_buff *ksz9893_xmit(struct sk_buff *skb, + + /* Tag encoding */ + tag = skb_put(skb, KSZ_INGRESS_TAG_LEN); +- addr = skb_mac_header(skb); ++ hdr = skb_eth_hdr(skb); + + *tag = BIT(dp->index); + +- if (is_link_local_ether_addr(addr)) ++ if (is_link_local_ether_addr(hdr->h_dest)) + *tag |= KSZ9893_TAIL_TAG_OVERRIDE; + + return skb; +-- +2.53.0 + diff --git a/staging-6.1/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch b/staging-6.1/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch new file mode 100644 index 0000000000..d53608f4b5 --- /dev/null +++ b/staging-6.1/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch @@ -0,0 +1,50 @@ +From 11948d05a7274637803fdfd8fc840da4431e65de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Oct 2025 06:43:22 +0000 +Subject: sched/fair: Only update stats for allowed CPUs when looking for dst + group + +From: Adam Li + +[ Upstream commit 82d6e01a0699800efd8b048eb584c907ccb47b7a ] + +Load imbalance is observed when the workload frequently forks new threads. +Due to CPU affinity, the workload can run on CPU 0-7 in the first +group, and only on CPU 8-11 in the second group. CPU 12-15 are always idle. + +{ 0 1 2 3 4 5 6 7 } {8 9 10 11 12 13 14 15} + * * * * * * * * * * * * + +When looking for dst group for newly forked threads, in many times +update_sg_wakeup_stats() reports the second group has more idle CPUs +than the first group. The scheduler thinks the second group is less +busy. Then it selects least busy CPUs among CPU 8-11. Therefore CPU 8-11 +can be crowded with newly forked threads, at the same time CPU 0-7 +can be idle. + +A task may not use all the CPUs in a schedule group due to CPU affinity. +Only update schedule group statistics for allowed CPUs. + +Signed-off-by: Adam Li +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index 376d835ca7b45e..23972665264655 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -9550,7 +9550,7 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd, + if (sd->flags & SD_ASYM_CPUCAPACITY) + sgs->group_misfit_task_load = 1; + +- for_each_cpu(i, sched_group_span(group)) { ++ for_each_cpu_and(i, sched_group_span(group), p->cpus_ptr) { + struct rq *rq = cpu_rq(i); + unsigned int local; + +-- +2.53.0 + diff --git a/staging-6.1/series b/staging-6.1/series new file mode 100644 index 0000000000..28f3ef7bba --- /dev/null +++ b/staging-6.1/series @@ -0,0 +1,6 @@ +smb-server-do-not-require-delete-access-for-non-repl.patch +sched-fair-only-update-stats-for-allowed-cpus-when-l.patch +fs-quota-create-dedicated-workqueue-for-quota_releas.patch +crypto-algif_skcipher-force-synchronous-processing-o.patch +tools-mm-slabinfo-fix-total_objects-attribute-name.patch +net-dsa-tag_ksz-do-not-rely-on-skb_mac_header-in-tx-.patch diff --git a/staging-6.1/smb-server-do-not-require-delete-access-for-non-repl.patch b/staging-6.1/smb-server-do-not-require-delete-access-for-non-repl.patch new file mode 100644 index 0000000000..7765a4d99f --- /dev/null +++ b/staging-6.1/smb-server-do-not-require-delete-access-for-non-repl.patch @@ -0,0 +1,61 @@ +From 50b73d46014528bc824a088f849ff19f4bab469f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Jun 2026 07:42:43 +0000 +Subject: smb/server: do not require delete access for non-replacing links + +From: ChenXiaoSong + +[ Upstream commit 851ed9e09639e0daf79a506ce26097b296ed5518 ] + +Reproducer: + + 1. server: systemctl start ksmbd + 2. client: mount -t cifs //${server_ip}/export /mnt + 3. client: touch /mnt/file; ln /mnt/file /mnt/hardlink + 4. client err log: ln: failed to create hard link 'hardlink' => + 'file': Permission denied + 5. server err log: ksmbd: no right to delete : 0x80 + +Fixes: 13f3942f2bf4 ("ksmbd: add per-handle permission check to FILE_LINK_INFORMATION") +Cc: stable@vger.kernel.org +Reported-by: Steve French +Signed-off-by: ChenXiaoSong +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 7bf915e08f909e..09b896739e74cd 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -6060,16 +6060,18 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, + } + case FILE_LINK_INFORMATION: + { +- if (!(fp->daccess & FILE_DELETE_LE)) { +- pr_err("no right to delete : 0x%x\n", fp->daccess); +- return -EACCES; +- } ++ struct smb2_file_link_info *file_info; + + if (buf_len < sizeof(struct smb2_file_link_info)) + return -EINVAL; + +- return smb2_create_link(work, work->tcon->share_conf, +- (struct smb2_file_link_info *)buffer, ++ file_info = (struct smb2_file_link_info *)buffer; ++ if (file_info->ReplaceIfExists && !(fp->daccess & FILE_DELETE_LE)) { ++ pr_err("no right to delete : 0x%x\n", fp->daccess); ++ return -EACCES; ++ } ++ ++ return smb2_create_link(work, work->tcon->share_conf, file_info, + buf_len, fp->filp, + work->conn->local_nls); + } +-- +2.53.0 + diff --git a/staging-6.1/tools-mm-slabinfo-fix-total_objects-attribute-name.patch b/staging-6.1/tools-mm-slabinfo-fix-total_objects-attribute-name.patch new file mode 100644 index 0000000000..b62e6a1a40 --- /dev/null +++ b/staging-6.1/tools-mm-slabinfo-fix-total_objects-attribute-name.patch @@ -0,0 +1,51 @@ +From c3a89d0b8bad9c68d6a057a4680243f60f72bc04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 15:59:17 +0800 +Subject: tools/mm/slabinfo: fix total_objects attribute name + +From: Yichong Chen + +[ Upstream commit 892a7864730775c3dbee2a39e9ead4fa8d4256e7 ] + +SLUB exports the total_objects sysfs attribute, but slabinfo tries to read +objects_total. As a result, the lookup fails and the field remains zero. + +Use the correct attribute name and rename the corresponding structure +member to match. + +Fixes: 205ab99dd103 ("slub: Update statistics handling for variable order slabs") +Signed-off-by: Yichong Chen +Cc: +Reviewed-by: SeongJae Park +Link: https://patch.msgid.link/96556748872BB47E+20260612071359.649946-1-chenyichong@uniontech.com +Signed-off-by: Vlastimil Babka (SUSE) +Signed-off-by: Sasha Levin +--- + tools/vm/slabinfo.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/vm/slabinfo.c b/tools/vm/slabinfo.c +index 0fffaeedee7672..d26a44e3e68470 100644 +--- a/tools/vm/slabinfo.c ++++ b/tools/vm/slabinfo.c +@@ -33,7 +33,7 @@ struct slabinfo { + unsigned int hwcache_align, object_size, objs_per_slab; + unsigned int sanity_checks, slab_size, store_user, trace; + int order, poison, reclaim_account, red_zone; +- unsigned long partial, objects, slabs, objects_partial, objects_total; ++ unsigned long partial, objects, slabs, objects_partial, total_objects; + unsigned long alloc_fastpath, alloc_slowpath; + unsigned long free_fastpath, free_slowpath; + unsigned long free_frozen, free_add_partial, free_remove_partial; +@@ -1254,7 +1254,7 @@ static void read_slab_dir(void) + slab->object_size = get_obj("object_size"); + slab->objects = get_obj("objects"); + slab->objects_partial = get_obj("objects_partial"); +- slab->objects_total = get_obj("objects_total"); ++ slab->total_objects = get_obj("total_objects"); + slab->objs_per_slab = get_obj("objs_per_slab"); + slab->order = get_obj("order"); + slab->partial = get_obj("partial"); +-- +2.53.0 + diff --git a/staging-6.12/bpf-prefer-dirty-packs-for-ebpf-allocations.patch b/staging-6.12/bpf-prefer-dirty-packs-for-ebpf-allocations.patch new file mode 100644 index 0000000000..94370d40a8 --- /dev/null +++ b/staging-6.12/bpf-prefer-dirty-packs-for-ebpf-allocations.patch @@ -0,0 +1,49 @@ +From 6b85987f6d5b51f6443168cbf6f65d14ae033182 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:29:11 -0700 +Subject: bpf: Prefer dirty packs for eBPF allocations + +From: Pawan Gupta + +commit b72e29e0f7ee329d89f86db8700c8ea99b4a370a upstream. + +The pack allocator only flushes predictors when reusing a dirty pack for +cBPF, eBPF allocations never trigger a flush. Currently, eBPF picks the +first free pack, which could be a clean pack. As an optimization, leaving +a clean pack for cBPF can avoid flushes. + +Prefer dirty packs for eBPF and keep clean packs free for cBPF. This +mirrors the existing cBPF preference for clean packs: each program kind +prefers the pack that avoids an extra flush, and falls back to the other +kind only when no preferred pack has room. eBPF reuse of a dirty pack is +harmless since eBPF being privileged does not flush. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 665f8423b76004..d9131b235f7974 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -998,10 +998,10 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool + goto found_free_area; + /* + * cBPF reuse of a dirty pack triggers a flush, so prefer a +- * clean pack for cBPF. eBPF never flushes, so pick the first +- * free pack, dirty or clean. ++ * clean pack for cBPF. eBPF never flushes, so steer it to a ++ * dirty pack and keep clean packs free for cBPF. + */ +- if (!was_classic || !pack->arch_flush_needed) ++ if (was_classic ^ pack->arch_flush_needed) + goto found_free_area; + if (!fallback_pack) { + fallback_pack = pack; +-- +2.53.0 + diff --git a/staging-6.12/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch b/staging-6.12/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch new file mode 100644 index 0000000000..d4032333c0 --- /dev/null +++ b/staging-6.12/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch @@ -0,0 +1,88 @@ +From 80e2b60c3d96b6e053233c63289299add0158931 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:28:55 -0700 +Subject: bpf: Prefer packs that won't trigger an IBPB flush on allocation + +From: Pawan Gupta + +commit a9b1f19a6a673ba06820898d0f1ad02883ea1639 upstream. + +Currently BPF pack allocator picks the chunks from the first available +pack. While this is okay, it naturally leads to more frequent flushes +when there are multiple packs in the system that weren't used since the +last flush. + +As an optimization prefer allocating the new programs from packs that +are unused since last flush. When all packs are dirty, allocation forces +a flush and marks all packs clean. + +Below are some future optimizations ideas: + + 1. Currently, the "dirty" tracking is only done at the pack-level. + Flush frequency can further be reduced with chunk-level tracking. + This requires a new bitmap per-pack to track the dirty state. + 2. IBPB flush is done on all CPUs, even if only a single CPU ran the + BPF program. On a system with hundreds of CPUs this could be a + major bottleneck forcing hundreds of IPIs to deliver the flush. + The solution is to track the CPUs where a BPF program ran, and + issue IBPB only on those CPUs. + 3. Avoid IBPB when flush is already done at other sources (e.g. + context switch). + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 357af07b9ba480..665f8423b76004 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -958,8 +958,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins + void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic) + { + unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size); +- struct bpf_prog_pack *pack; +- unsigned long pos; ++ struct bpf_prog_pack *pack, *fallback_pack = NULL; ++ unsigned long pos, fallback_pos = 0; + void *ptr = NULL; + + mutex_lock(&pack_mutex); +@@ -991,8 +991,29 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool + list_for_each_entry(pack, &pack_list, list) { + pos = bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0, + nbits, 0); +- if (pos < BPF_PROG_CHUNK_COUNT) ++ if (pos >= BPF_PROG_CHUNK_COUNT) ++ continue; ++ /* Flush not enabled, use any pack */ ++ if (!static_branch_unlikely(&bpf_pred_flush_enabled)) + goto found_free_area; ++ /* ++ * cBPF reuse of a dirty pack triggers a flush, so prefer a ++ * clean pack for cBPF. eBPF never flushes, so pick the first ++ * free pack, dirty or clean. ++ */ ++ if (!was_classic || !pack->arch_flush_needed) ++ goto found_free_area; ++ if (!fallback_pack) { ++ fallback_pack = pack; ++ fallback_pos = pos; ++ } ++ } ++ ++ /* No preferred pack found */ ++ if (fallback_pack) { ++ pack = fallback_pack; ++ pos = fallback_pos; ++ goto found_free_area; + } + + pack = alloc_new_pack(bpf_fill_ill_insns); +-- +2.53.0 + diff --git a/staging-6.12/bpf-restrict-jit-predictor-flush-to-cbpf.patch b/staging-6.12/bpf-restrict-jit-predictor-flush-to-cbpf.patch new file mode 100644 index 0000000000..42647c2423 --- /dev/null +++ b/staging-6.12/bpf-restrict-jit-predictor-flush-to-cbpf.patch @@ -0,0 +1,212 @@ +From 00660f978885b384a3f033045632df60867b7b09 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:28:24 -0700 +Subject: bpf: Restrict JIT predictor flush to cBPF + +From: Pawan Gupta + +commit 0bb99f2cfaae6822d734d69722de30af823efdf3 upstream. + +Currently predictor flush on memory reuse is done for all BPF JIT +allocations, but only cBPF programs can be loaded by an unprivileged user. +eBPF is privileged by default, and flushing predictors for all CPUs on +every eBPF reuse penalizes the common case for no security benefit. + +eBPF allocations can be frequent on busy systems, only flush predictors +for cBPF programs. Trampoline and dispatcher allocations also skip the +flush as they are eBPF-only. + + [pawan: backport dropped "was_classic" hunk for arches that do not + support pack allocator] + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 4 ++-- + arch/powerpc/net/bpf_jit_comp.c | 2 +- + arch/riscv/net/bpf_jit_comp64.c | 2 +- + arch/riscv/net/bpf_jit_core.c | 3 ++- + arch/x86/net/bpf_jit_comp.c | 5 +++-- + include/linux/filter.h | 5 +++-- + kernel/bpf/core.c | 13 ++++++++----- + kernel/bpf/dispatcher.c | 2 +- + 8 files changed, 21 insertions(+), 15 deletions(-) + +diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c +index c852749405e0c7..738e56b48f2a21 100644 +--- a/arch/arm64/net/bpf_jit_comp.c ++++ b/arch/arm64/net/bpf_jit_comp.c +@@ -1881,7 +1881,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + image_size = extable_offset + extable_size; + ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, + sizeof(u64), &header, &image_ptr, +- jit_fill_hole); ++ jit_fill_hole, was_classic); + if (!ro_header) { + prog = orig_prog; + goto out_off; +@@ -2413,7 +2413,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + + void *arch_alloc_bpf_trampoline(unsigned int size) + { +- return bpf_prog_pack_alloc(size, jit_fill_hole); ++ return bpf_prog_pack_alloc(size, jit_fill_hole, false); + } + + void arch_free_bpf_trampoline(void *image, unsigned int size) +diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c +index 55c3b64a5f3a40..180175e072adc9 100644 +--- a/arch/powerpc/net/bpf_jit_comp.c ++++ b/arch/powerpc/net/bpf_jit_comp.c +@@ -174,7 +174,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) + alloclen = proglen + FUNCTION_DESCR_SIZE + fixup_len + extable_len; + + fhdr = bpf_jit_binary_pack_alloc(alloclen, &fimage, 4, &hdr, &image, +- bpf_jit_fill_ill_insns); ++ bpf_jit_fill_ill_insns, bpf_prog_was_classic(fp)); + if (!fhdr) { + fp = org_fp; + goto out_addrs; +diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c +index 5895c1b2be203b..43a58e5e123f20 100644 +--- a/arch/riscv/net/bpf_jit_comp64.c ++++ b/arch/riscv/net/bpf_jit_comp64.c +@@ -1113,7 +1113,7 @@ int arch_bpf_trampoline_size(const struct btf_func_model *m, u32 flags, + + void *arch_alloc_bpf_trampoline(unsigned int size) + { +- return bpf_prog_pack_alloc(size, bpf_fill_ill_insns); ++ return bpf_prog_pack_alloc(size, bpf_fill_ill_insns, false); + } + + void arch_free_bpf_trampoline(void *image, unsigned int size) +diff --git a/arch/riscv/net/bpf_jit_core.c b/arch/riscv/net/bpf_jit_core.c +index 6de753c667f42a..2f2af89ab4dfe8 100644 +--- a/arch/riscv/net/bpf_jit_core.c ++++ b/arch/riscv/net/bpf_jit_core.c +@@ -126,7 +126,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + bpf_jit_binary_pack_alloc(prog_size + extable_size, + &jit_data->ro_image, sizeof(u32), + &jit_data->header, &jit_data->image, +- bpf_fill_ill_insns); ++ bpf_fill_ill_insns, ++ bpf_prog_was_classic(prog)); + if (!jit_data->ro_header) { + prog = orig_prog; + goto out_offset; +diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c +index 8cbc26081bdb27..4304596c8fdddd 100644 +--- a/arch/x86/net/bpf_jit_comp.c ++++ b/arch/x86/net/bpf_jit_comp.c +@@ -3206,7 +3206,7 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *rw_im + + void *arch_alloc_bpf_trampoline(unsigned int size) + { +- return bpf_prog_pack_alloc(size, jit_fill_hole); ++ return bpf_prog_pack_alloc(size, jit_fill_hole, false); + } + + void arch_free_bpf_trampoline(void *image, unsigned int size) +@@ -3491,7 +3491,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) + /* allocate module memory for x86 insns and extable */ + header = bpf_jit_binary_pack_alloc(roundup(proglen, align) + extable_size, + &image, align, &rw_header, &rw_image, +- jit_fill_hole); ++ jit_fill_hole, ++ bpf_prog_was_classic(prog)); + if (!header) { + prog = orig_prog; + goto out_addrs; +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 8046cd2a39c6a9..b88a213bcbbe19 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -1262,7 +1262,7 @@ void bpf_jit_free(struct bpf_prog *fp); + struct bpf_binary_header * + bpf_jit_binary_pack_hdr(const struct bpf_prog *fp); + +-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns); ++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic); + void bpf_prog_pack_free(void *ptr, u32 size); + + static inline bool bpf_prog_kallsyms_verify_off(const struct bpf_prog *fp) +@@ -1276,7 +1276,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **ro_image, + unsigned int alignment, + struct bpf_binary_header **rw_hdr, + u8 **rw_image, +- bpf_jit_fill_hole_t bpf_fill_ill_insns); ++ bpf_jit_fill_hole_t bpf_fill_ill_insns, ++ bool was_classic); + int bpf_jit_binary_pack_finalize(struct bpf_binary_header *ro_header, + struct bpf_binary_header *rw_header); + void bpf_jit_binary_pack_free(struct bpf_binary_header *ro_header, +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 5f676320c53beb..29d39092c45778 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -952,7 +952,7 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins + return NULL; + } + +-void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) ++void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool was_classic) + { + unsigned int nbits = BPF_PROG_SIZE_TO_NBITS(size); + struct bpf_prog_pack *pack; +@@ -967,7 +967,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + * safe because cBPF programs (the unprivileged attack surface) + * are bounded well below a pack size. + */ +- if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ if (was_classic && static_branch_unlikely(&bpf_pred_flush_enabled)) + pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n"); + size = round_up(size, PAGE_SIZE); + ptr = bpf_jit_alloc_exec(size); +@@ -999,7 +999,9 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + pos = 0; + + found_free_area: +- static_call_cond(bpf_arch_pred_flush)(); ++ /* Flush only for cBPF as it may contain a crafted gadget */ ++ if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic) ++ static_call_cond(bpf_arch_pred_flush)(); + bitmap_set(pack->bitmap, pos, nbits); + ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT); + +@@ -1159,7 +1161,8 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr, + unsigned int alignment, + struct bpf_binary_header **rw_header, + u8 **rw_image, +- bpf_jit_fill_hole_t bpf_fill_ill_insns) ++ bpf_jit_fill_hole_t bpf_fill_ill_insns, ++ bool was_classic) + { + struct bpf_binary_header *ro_header; + u32 size, hole, start; +@@ -1172,7 +1175,7 @@ bpf_jit_binary_pack_alloc(unsigned int proglen, u8 **image_ptr, + + if (bpf_jit_charge_modmem(size)) + return NULL; +- ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns); ++ ro_header = bpf_prog_pack_alloc(size, bpf_fill_ill_insns, was_classic); + if (!ro_header) { + bpf_jit_uncharge_modmem(size); + return NULL; +diff --git a/kernel/bpf/dispatcher.c b/kernel/bpf/dispatcher.c +index b77db7413f8c70..ea2d60dc1feeb7 100644 +--- a/kernel/bpf/dispatcher.c ++++ b/kernel/bpf/dispatcher.c +@@ -145,7 +145,7 @@ void bpf_dispatcher_change_prog(struct bpf_dispatcher *d, struct bpf_prog *from, + + mutex_lock(&d->mutex); + if (!d->image) { +- d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero); ++ d->image = bpf_prog_pack_alloc(PAGE_SIZE, bpf_jit_fill_hole_with_zero, false); + if (!d->image) + goto out; + d->rw_image = bpf_jit_alloc_exec(PAGE_SIZE); +-- +2.53.0 + diff --git a/staging-6.12/bpf-skip-redundant-ibpb-in-pack-allocator.patch b/staging-6.12/bpf-skip-redundant-ibpb-in-pack-allocator.patch new file mode 100644 index 0000000000..d2b5123ba1 --- /dev/null +++ b/staging-6.12/bpf-skip-redundant-ibpb-in-pack-allocator.patch @@ -0,0 +1,81 @@ +From 356eadd0a01700669bf1a2bb0beb98947c247e76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:28:39 -0700 +Subject: bpf: Skip redundant IBPB in pack allocator + +From: Pawan Gupta + +commit a23c1c5396a91680703360d1ee28a44657c503c4 upstream. + +bpf_prog_pack_alloc() issues IBPB on all CPUs on every cBPF allocation, +even when reusing chunks from an existing pack where no new memory was +touched since the last IBPB. + +Since IBPB on all CPUs is heavy, Dave Hansen suggested to track allocation +since last IBPB, and only issue IBPB at reuse for the chunks that have not +seen an IBPB since they were last freed. + +Track per-pack whether an IBPB is needed via arch_flush_needed. Set it when +allocating a chunk, reset on IBPB flush. On reuse, conditionally issue the +flush. Since IBPB invalidates all BTB entries, clear the flag on all packs +after flushing. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 29d39092c45778..357af07b9ba480 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -885,6 +885,7 @@ int bpf_jit_add_poke_descriptor(struct bpf_prog *prog, + struct bpf_prog_pack { + struct list_head list; + void *ptr; ++ bool arch_flush_needed; + unsigned long bitmap[]; + }; + +@@ -938,6 +939,8 @@ static struct bpf_prog_pack *alloc_new_pack(bpf_jit_fill_hole_t bpf_fill_ill_ins + bpf_fill_ill_insns(pack->ptr, BPF_PROG_PACK_SIZE); + bitmap_zero(pack->bitmap, BPF_PROG_PACK_SIZE / BPF_PROG_CHUNK_SIZE); + ++ if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ pack->arch_flush_needed = true; + set_vm_flush_reset_perms(pack->ptr); + err = set_memory_rox((unsigned long)pack->ptr, + BPF_PROG_PACK_SIZE / PAGE_SIZE); +@@ -1000,8 +1003,15 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns, bool + + found_free_area: + /* Flush only for cBPF as it may contain a crafted gadget */ +- if (static_branch_unlikely(&bpf_pred_flush_enabled) && was_classic) ++ if (static_branch_unlikely(&bpf_pred_flush_enabled) && ++ pack->arch_flush_needed && ++ was_classic) { ++ struct bpf_prog_pack *p; ++ + static_call_cond(bpf_arch_pred_flush)(); ++ list_for_each_entry(p, &pack_list, list) ++ p->arch_flush_needed = false; ++ } + bitmap_set(pack->bitmap, pos, nbits); + ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT); + +@@ -1039,6 +1049,9 @@ void bpf_prog_pack_free(void *ptr, u32 size) + "bpf_prog_pack bug: missing bpf_arch_text_invalidate?\n"); + + bitmap_clear(pack->bitmap, pos, nbits); ++ ++ if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ pack->arch_flush_needed = true; + if (bitmap_find_next_zero_area(pack->bitmap, BPF_PROG_CHUNK_COUNT, 0, + BPF_PROG_CHUNK_COUNT, 0) == 0) { + list_del(&pack->list); +-- +2.53.0 + diff --git a/staging-6.12/bpf-support-for-hardening-against-jit-spraying.patch b/staging-6.12/bpf-support-for-hardening-against-jit-spraying.patch new file mode 100644 index 0000000000..52ce669bb0 --- /dev/null +++ b/staging-6.12/bpf-support-for-hardening-against-jit-spraying.patch @@ -0,0 +1,120 @@ +From 2ba2e0e742c02563c5286e7f5eb8db5c34218027 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:27:54 -0700 +Subject: bpf: Support for hardening against JIT spraying + +From: Pawan Gupta + +commit 96cce16e26dd02a8678f1e87f88a4b5cdb63b995 upstream. + +The BPF JIT allocator packs many small programs into larger executable +allocations and reuses space within those allocations as programs are +loaded and freed. When fresh code is written into space that a previous +program occupied, an indirect jump into the new program can reuse a branch +prediction left behind by the old one. + +Flush the indirect branch predictors before reusing JIT memory so that +indirect jumps into a newly written program don't reuse predictions from an +old program that occupied the same space. + +Introduce bpf_arch_pred_flush_enabled static key and bpf_arch_pred_flush +static call for flushing the branch predictors on JIT memory reuse. +Architectures that need a flush, can update it to a predictor flush +function. By default, its a NOP and does not emit any CALL. + +Allocations larger than a pack are not covered by this flush. That is safe +because cBPF programs (the unprivileged attack surface) are bounded well +below a pack size. Issue a warning if this assumption is ever violated +while the flush is active. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + include/linux/filter.h | 10 ++++++++++ + kernel/bpf/core.c | 19 +++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/include/linux/filter.h b/include/linux/filter.h +index a91f2babf4253d..8046cd2a39c6a9 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -1238,6 +1239,15 @@ extern long bpf_jit_limit_max; + + typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size); + ++/* ++ * Flush the indirect branch predictors before reusing JIT memory, so that ++ * indirect jumps into a newly written program don't reuse predictions left ++ * behind by an old program that occupied the same space. ++ */ ++void bpf_arch_pred_flush(void); ++DECLARE_STATIC_CALL(bpf_arch_pred_flush, bpf_arch_pred_flush); ++DECLARE_STATIC_KEY_FALSE(bpf_pred_flush_enabled); ++ + void bpf_jit_fill_hole_with_zero(void *area, unsigned int size); + + struct bpf_binary_header * +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 517710c89fa505..5f676320c53beb 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -892,6 +893,15 @@ void bpf_jit_fill_hole_with_zero(void *area, unsigned int size) + memset(area, 0, size); + } + ++DEFINE_STATIC_CALL_NULL(bpf_arch_pred_flush, bpf_arch_pred_flush); ++ ++/* ++ * Enabled once bpf_arch_pred_flush points at a real flush routine. Lets the ++ * pack allocator test "is a predictor flush wired up at all" with a cheap ++ * static branch instead of repeatedly querying the static call target. ++ */ ++DEFINE_STATIC_KEY_FALSE(bpf_pred_flush_enabled); ++ + #define BPF_PROG_SIZE_TO_NBITS(size) (round_up(size, BPF_PROG_CHUNK_SIZE) / BPF_PROG_CHUNK_SIZE) + + static DEFINE_MUTEX(pack_mutex); +@@ -951,6 +961,14 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + + mutex_lock(&pack_mutex); + if (size > BPF_PROG_PACK_SIZE) { ++ /* ++ * Allocations larger than a pack get their own pages, and ++ * predictors are not flushed for such allocation. This is only ++ * safe because cBPF programs (the unprivileged attack surface) ++ * are bounded well below a pack size. ++ */ ++ if (static_branch_unlikely(&bpf_pred_flush_enabled)) ++ pr_warn_once("BPF: Predictors not flushed for allocations greater than BPF_PROG_PACK_SIZE\n"); + size = round_up(size, PAGE_SIZE); + ptr = bpf_jit_alloc_exec(size); + if (ptr) { +@@ -981,6 +999,7 @@ void *bpf_prog_pack_alloc(u32 size, bpf_jit_fill_hole_t bpf_fill_ill_insns) + pos = 0; + + found_free_area: ++ static_call_cond(bpf_arch_pred_flush)(); + bitmap_set(pack->bitmap, pos, nbits); + ptr = (void *)(pack->ptr) + (pos << BPF_PROG_CHUNK_SHIFT); + +-- +2.53.0 + diff --git a/staging-6.12/crypto-algif_skcipher-force-synchronous-processing.patch b/staging-6.12/crypto-algif_skcipher-force-synchronous-processing.patch new file mode 100644 index 0000000000..60544b294f --- /dev/null +++ b/staging-6.12/crypto-algif_skcipher-force-synchronous-processing.patch @@ -0,0 +1,159 @@ +From f8fc4098208ede0a7aefd5cf4fbc489da12a2d96 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 02:58:36 +0000 +Subject: crypto: algif_skcipher - force synchronous processing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Muhammet Kaan KILINÇ + +The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv +directly into the skcipher request. After io_submit() the socket lock is +dropped and the request is processed asynchronously by a worker (e.g. +cryptd), which dereferences ctx->iv only later. + +A concurrent sendmsg(ALG_SET_IV) on the same socket can overwrite ctx->iv +inside this window, so the in-flight request runs under an +attacker-controlled IV. For CTR and other stream modes this causes +IV/keystream reuse and allows an unprivileged user to recover the +plaintext of a concurrent operation. + +Snapshotting ctx->iv into per-request storage for the async path is not +sufficient here. For ciphers with statesize == 0 - which includes cbc +and ctr - skcipher_prepare_alg() installs skcipher_noimport()/ +skcipher_noexport(), so ctx->state carries nothing and the MSG_MORE +inter-chunk IV chaining is carried solely by the in-place req->iv +writeback. A snapshot redirects that writeback into per-request memory +that af_alg_free_resources() releases on completion, so AIO + MSG_MORE +with cbc/ctr would silently produce wrong output. Writing the IV back +from the completion callback instead is not possible either: that would +require lock_sock() there, but the callback can run in softirq/atomic +context, so it must not sleep. + +Make the operation synchronous instead. ctx->iv is then only ever +dereferenced under the socket lock held by recvmsg(), which removes the +race, and the req->iv writeback lands in ctx->iv as before, which keeps +MSG_MORE chaining intact for statesize == 0 ciphers. The ctx->state +import/export path is unchanged for ciphers that do have state. + +This is equivalent to the upstream resolution: commit fcc77d33a34c +("net: Remove support for AIO on sockets") removed the AIO socket path +across net/ entirely, producing the same end state for this file - +algif_skcipher never processes an AIO request asynchronously. After this +patch, _skcipher_recvmsg() matches mainline's crypto/algif_skcipher.c as +it stands today, including the same now-dead -EIOCBQUEUED check. This +patch deviates from that commit deliberately: rather than removing AIO +socket support tree-wide, which would be far too invasive for stable, it +removes only the AIO branch in crypto/algif_skcipher.c. io_submit() now +completes synchronously, which is valid for the AIO interface; AF_ALG +async is rarely used in practice. + +The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, +and is left alone to keep the fix minimal. + +Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") +Cc: +Reported-by: Muhammet Kaan KILINÇ +Signed-off-by: Muhammet Kaan KILINÇ +Signed-off-by: Sasha Levin +--- + crypto/algif_skcipher.c | 75 +++++++++++++---------------------------- + 1 file changed, 24 insertions(+), 51 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index ba0a17fd95aca2..35ebc3e0201b04 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -79,20 +79,6 @@ static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req) + return err; + } + +-static void algif_skcipher_done(void *data, int err) +-{ +- struct af_alg_async_req *areq = data; +- struct sock *sk = areq->sk; +- +- if (err) +- goto out; +- +- err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); +- +-out: +- af_alg_async_cb(data, err); +-} +- + static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) + { +@@ -171,43 +157,30 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + cflags |= CRYPTO_SKCIPHER_REQ_CONT; + } + +- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { +- /* AIO operation */ +- sock_hold(sk); +- areq->iocb = msg->msg_iocb; +- +- /* Remember output size that will be generated. */ +- areq->outlen = len; +- +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- cflags | +- CRYPTO_TFM_REQ_MAY_SLEEP, +- algif_skcipher_done, areq); +- err = ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); +- +- /* AIO operation in progress */ +- if (err == -EINPROGRESS) +- return -EIOCBQUEUED; +- +- sock_put(sk); +- } else { +- /* Synchronous operation */ +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- cflags | +- CRYPTO_TFM_REQ_MAY_SLEEP | +- CRYPTO_TFM_REQ_MAY_BACKLOG, +- crypto_req_done, &ctx->wait); +- err = crypto_wait_req(ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), +- &ctx->wait); +- +- if (!err) +- err = algif_skcipher_export( +- sk, &areq->cra_u.skcipher_req); +- } ++ /* ++ * Force synchronous processing. The async (AIO) path passed the ++ * socket-wide ctx->iv into the request, which the worker ++ * dereferenced after the socket lock had been dropped, letting a ++ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline ++ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove ++ * support for AIO on sockets"); the minimal stable fix is to always ++ * complete synchronously, so ctx->iv is only ever dereferenced under ++ * the socket lock. This also keeps the IV chaining intact: for ++ * ciphers with statesize == 0 (e.g. ctr, cbc) the chained IV is ++ * carried by the req->iv writeback into ctx->iv, which is only ++ * consistent on the synchronous path. ++ */ ++ skcipher_request_set_callback(&areq->cra_u.skcipher_req, ++ cflags | ++ CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &ctx->wait); ++ err = crypto_wait_req(ctx->enc ? ++ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : ++ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), ++ &ctx->wait); ++ if (!err) ++ err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); + + free: + af_alg_free_resources(areq); +-- +2.53.0 + diff --git a/staging-6.12/iommu-pass-old-domain-to-set_dev_pasid-op.patch b/staging-6.12/iommu-pass-old-domain-to-set_dev_pasid-op.patch new file mode 100644 index 0000000000..dbcd0e626f --- /dev/null +++ b/staging-6.12/iommu-pass-old-domain-to-set_dev_pasid-op.patch @@ -0,0 +1,164 @@ +From 376d5ee5a20ac6c45f29572a06e1ab48695755c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Nov 2024 10:13:52 +0800 +Subject: iommu: Pass old domain to set_dev_pasid op + +From: Yi Liu + +[ Upstream commit b45a3777ceabbe08ab7a6e97f258191c07cbab8d ] + +To support domain replacement for pasid, the underlying iommu driver needs +to know the old domain hence be able to clean up the existing attachment. +It would be much convenient for iommu layer to pass down the old domain. +Otherwise, iommu drivers would need to track domain for pasids by +themselves, this would duplicate code among the iommu drivers. Or iommu +drivers would rely group->pasid_array to get domain, which may not always +the correct one. + +Suggested-by: Jason Gunthorpe +Reviewed-by: Jason Gunthorpe +Reviewed-by: Kevin Tian +Reviewed-by: Lu Baolu +Reviewed-by: Nicolin Chen +Reviewed-by: Vasant Hegde +Signed-off-by: Yi Liu +Link: https://lore.kernel.org/r/20241107122234.7424-2-yi.l.liu@intel.com +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Stable-dep-of: f46452c3df7a ("iommu/vt-d: Clear Present bit before tearing down scalable-mode context entry") +Signed-off-by: Sasha Levin +--- + drivers/iommu/amd/amd_iommu.h | 3 ++- + drivers/iommu/amd/pasid.c | 3 ++- + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 3 ++- + drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 3 ++- + drivers/iommu/intel/iommu.c | 6 ++++-- + drivers/iommu/intel/svm.c | 3 ++- + drivers/iommu/iommu.c | 3 ++- + include/linux/iommu.h | 2 +- + 8 files changed, 17 insertions(+), 9 deletions(-) + +diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h +index 6fac9ee8dd3ed0..27eedfb47d8b69 100644 +--- a/drivers/iommu/amd/amd_iommu.h ++++ b/drivers/iommu/amd/amd_iommu.h +@@ -52,7 +52,8 @@ struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev, + struct mm_struct *mm); + void amd_iommu_domain_free(struct iommu_domain *dom); + int iommu_sva_set_dev_pasid(struct iommu_domain *domain, +- struct device *dev, ioasid_t pasid); ++ struct device *dev, ioasid_t pasid, ++ struct iommu_domain *old); + void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, + struct iommu_domain *domain); + +diff --git a/drivers/iommu/amd/pasid.c b/drivers/iommu/amd/pasid.c +index 0657b9373be547..d1dfc745f55e3e 100644 +--- a/drivers/iommu/amd/pasid.c ++++ b/drivers/iommu/amd/pasid.c +@@ -100,7 +100,8 @@ static const struct mmu_notifier_ops sva_mn = { + }; + + int iommu_sva_set_dev_pasid(struct iommu_domain *domain, +- struct device *dev, ioasid_t pasid) ++ struct device *dev, ioasid_t pasid, ++ struct iommu_domain *old) + { + struct pdom_dev_data *pdom_dev_data; + struct protection_domain *sva_pdom = to_pdomain(domain); +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +index 32f3e91a7d7f5d..6cb2fbf4303746 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c +@@ -332,7 +332,8 @@ void arm_smmu_sva_notifier_synchronize(void) + } + + static int arm_smmu_sva_set_dev_pasid(struct iommu_domain *domain, +- struct device *dev, ioasid_t id) ++ struct device *dev, ioasid_t id, ++ struct iommu_domain *old) + { + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct arm_smmu_master *master = dev_iommu_priv_get(dev); +diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +index 04e0058daab815..ebc25e5a8f55e6 100644 +--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c ++++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c +@@ -2879,7 +2879,8 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) + } + + static int arm_smmu_s1_set_dev_pasid(struct iommu_domain *domain, +- struct device *dev, ioasid_t id) ++ struct device *dev, ioasid_t id, ++ struct iommu_domain *old) + { + struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); + struct arm_smmu_master *master = dev_iommu_priv_get(dev); +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 18022d17c492b6..3455e75c59c4be 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -4338,7 +4338,8 @@ static void intel_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, + } + + static int intel_iommu_set_dev_pasid(struct iommu_domain *domain, +- struct device *dev, ioasid_t pasid) ++ struct device *dev, ioasid_t pasid, ++ struct iommu_domain *old) + { + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct dmar_domain *dmar_domain = to_dmar_domain(domain); +@@ -4624,7 +4625,8 @@ static int identity_domain_attach_dev(struct iommu_domain *domain, struct device + } + + static int identity_domain_set_dev_pasid(struct iommu_domain *domain, +- struct device *dev, ioasid_t pasid) ++ struct device *dev, ioasid_t pasid, ++ struct iommu_domain *old) + { + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct intel_iommu *iommu = info->iommu; +diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c +index 3cc43a958b4dc7..4a2bd65614ad2d 100644 +--- a/drivers/iommu/intel/svm.c ++++ b/drivers/iommu/intel/svm.c +@@ -111,7 +111,8 @@ static const struct mmu_notifier_ops intel_mmuops = { + }; + + static int intel_svm_set_dev_pasid(struct iommu_domain *domain, +- struct device *dev, ioasid_t pasid) ++ struct device *dev, ioasid_t pasid, ++ struct iommu_domain *old) + { + struct device_domain_info *info = dev_iommu_priv_get(dev); + struct dmar_domain *dmar_domain = to_dmar_domain(domain); +diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c +index 62e1d637250318..fdebfe5380bac2 100644 +--- a/drivers/iommu/iommu.c ++++ b/drivers/iommu/iommu.c +@@ -3342,7 +3342,8 @@ static int __iommu_set_group_pasid(struct iommu_domain *domain, + + for_each_group_device(group, device) { + if (device->dev->iommu->max_pasids > 0) { +- ret = domain->ops->set_dev_pasid(domain, device->dev, pasid); ++ ret = domain->ops->set_dev_pasid(domain, device->dev, ++ pasid, NULL); + if (ret) + goto err_revert; + } +diff --git a/include/linux/iommu.h b/include/linux/iommu.h +index 10f7b1df072361..dc7ceb9406eda7 100644 +--- a/include/linux/iommu.h ++++ b/include/linux/iommu.h +@@ -642,7 +642,7 @@ struct iommu_ops { + struct iommu_domain_ops { + int (*attach_dev)(struct iommu_domain *domain, struct device *dev); + int (*set_dev_pasid)(struct iommu_domain *domain, struct device *dev, +- ioasid_t pasid); ++ ioasid_t pasid, struct iommu_domain *old); + + int (*map_pages)(struct iommu_domain *domain, unsigned long iova, + phys_addr_t paddr, size_t pgsize, size_t pgcount, +-- +2.53.0 + diff --git a/staging-6.12/iommu-vt-d-cleanup-intel_context_flush_present.patch b/staging-6.12/iommu-vt-d-cleanup-intel_context_flush_present.patch new file mode 100644 index 0000000000..c9340b2f10 --- /dev/null +++ b/staging-6.12/iommu-vt-d-cleanup-intel_context_flush_present.patch @@ -0,0 +1,137 @@ +From 4a7f5aee99c7913457dfb9f1673a313c3521ca1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Mar 2025 10:47:49 +0800 +Subject: iommu/vt-d: Cleanup intel_context_flush_present() + +From: Lu Baolu + +[ Upstream commit 4c293add5874038dc82ef579663dd86744d8e872 ] + +The intel_context_flush_present() is called in places where either the +scalable mode is disabled, or scalable mode is enabled but all PASID +entries are known to be non-present. In these cases, the flush_domains +path within intel_context_flush_present() will never execute. This dead +code is therefore removed. + +Signed-off-by: Lu Baolu +Reviewed-by: Kevin Tian +Tested-by: Zhangfei Gao +Link: https://lore.kernel.org/r/20250228092631.3425464-7-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Stable-dep-of: f46452c3df7a ("iommu/vt-d: Clear Present bit before tearing down scalable-mode context entry") +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/iommu.c | 4 ++-- + drivers/iommu/intel/iommu.h | 5 ++--- + drivers/iommu/intel/pasid.c | 41 +++++++------------------------------ + 3 files changed, 11 insertions(+), 39 deletions(-) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index 3455e75c59c4be..a1ec11c90a8b4c 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1917,7 +1917,7 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 + context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); +- intel_context_flush_present(info, context, did, true); ++ intel_context_flush_no_pasid(info, context, did); + context_clear_entry(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + } +@@ -4153,7 +4153,7 @@ static int context_flip_pri(struct device_domain_info *info, bool enable) + + if (!ecap_coherent(iommu->ecap)) + clflush_cache_range(context, sizeof(*context)); +- intel_context_flush_present(info, context, did, true); ++ intel_context_flush_no_pasid(info, context, did); + spin_unlock(&iommu->lock); + + return 0; +diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h +index e46eb1d3fba29d..8a91a8d5661418 100644 +--- a/drivers/iommu/intel/iommu.h ++++ b/drivers/iommu/intel/iommu.h +@@ -1296,9 +1296,8 @@ void cache_tag_flush_all(struct dmar_domain *domain); + void cache_tag_flush_range_np(struct dmar_domain *domain, unsigned long start, + unsigned long end); + +-void intel_context_flush_present(struct device_domain_info *info, +- struct context_entry *context, +- u16 did, bool affect_domains); ++void intel_context_flush_no_pasid(struct device_domain_info *info, ++ struct context_entry *context, u16 did); + + int intel_iommu_enable_prq(struct intel_iommu *iommu); + int intel_iommu_finish_prq(struct intel_iommu *iommu); +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 5e63b5d4577f75..0e0c6cf2d3f4d3 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -717,7 +717,7 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn) + context_clear_entry(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); +- intel_context_flush_present(info, context, did, false); ++ intel_context_flush_no_pasid(info, context, did); + } + + static int pci_pasid_table_teardown(struct pci_dev *pdev, u16 alias, void *data) +@@ -913,17 +913,15 @@ static void __context_flush_dev_iotlb(struct device_domain_info *info) + + /* + * Cache invalidations after change in a context table entry that was present +- * according to the Spec 6.5.3.3 (Guidance to Software for Invalidations). If +- * IOMMU is in scalable mode and all PASID table entries of the device were +- * non-present, set flush_domains to false. Otherwise, true. ++ * according to the Spec 6.5.3.3 (Guidance to Software for Invalidations). ++ * This helper can only be used when IOMMU is working in the legacy mode or ++ * IOMMU is in scalable mode but all PASID table entries of the device are ++ * non-present. + */ +-void intel_context_flush_present(struct device_domain_info *info, +- struct context_entry *context, +- u16 did, bool flush_domains) ++void intel_context_flush_no_pasid(struct device_domain_info *info, ++ struct context_entry *context, u16 did) + { + struct intel_iommu *iommu = info->iommu; +- struct pasid_entry *pte; +- int i; + + /* + * Device-selective context-cache invalidation. The Domain-ID field +@@ -946,30 +944,5 @@ void intel_context_flush_present(struct device_domain_info *info, + return; + } + +- /* +- * For scalable mode: +- * - Domain-selective PASID-cache invalidation to affected domains +- * - Domain-selective IOTLB invalidation to affected domains +- * - Global Device-TLB invalidation to affected functions +- */ +- if (flush_domains) { +- /* +- * If the IOMMU is running in scalable mode and there might +- * be potential PASID translations, the caller should hold +- * the lock to ensure that context changes and cache flushes +- * are atomic. +- */ +- assert_spin_locked(&iommu->lock); +- for (i = 0; i < info->pasid_table->max_pasid; i++) { +- pte = intel_pasid_get_entry(info->dev, i); +- if (!pte || !pasid_pte_is_present(pte)) +- continue; +- +- did = pasid_get_domain_id(pte); +- qi_flush_pasid_cache(iommu, did, QI_PC_ALL_PASIDS, 0); +- iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); +- } +- } +- + __context_flush_dev_iotlb(info); + } +-- +2.53.0 + diff --git a/staging-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch b/staging-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch new file mode 100644 index 0000000000..3083aa639a --- /dev/null +++ b/staging-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-con.patch @@ -0,0 +1,129 @@ +From 3f3d57050d84437f0bc5d160b470169a81485ddb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 01:21:23 +0300 +Subject: iommu/vt-d: Clear Present bit before tearing down context entry +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Lu Baolu + +[ Upstream commit c1e4f1dccbe9d7656d1c6872ebeadb5992d0aaa2 ] + +When tearing down a context entry, the current implementation zeros the +entire 128-bit entry using multiple 64-bit writes. This creates a window +where the hardware can fetch a "torn" entry — where some fields are +already zeroed while the 'Present' bit is still set — leading to +unpredictable behavior or spurious faults. + +While x86 provides strong write ordering, the compiler may reorder writes +to the two 64-bit halves of the context entry. Even without compiler +reordering, the hardware fetch is not guaranteed to be atomic with +respect to multiple CPU writes. + +Align with the "Guidance to Software for Invalidations" in the VT-d spec +(Section 6.5.3.3) by implementing the recommended ownership handshake: + +1. Clear only the 'Present' (P) bit of the context entry first to + signal the transition of ownership from hardware to software. +2. Use dma_wmb() to ensure the cleared bit is visible to the IOMMU. +3. Perform the required cache and context-cache invalidation to ensure + hardware no longer has cached references to the entry. +4. Fully zero out the entry only after the invalidation is complete. + +Also, add a dma_wmb() to context_set_present() to ensure the entry +is fully initialized before the 'Present' bit becomes visible. + +Fixes: ba39592764ed2 ("Intel IOMMU: Intel IOMMU driver") +Reported-by: Dmytro Maluka +Closes: https://lore.kernel.org/all/aTG7gc7I5wExai3S@google.com/ +Signed-off-by: Lu Baolu +Reviewed-by: Dmytro Maluka +Reviewed-by: Samiullah Khawaja +Reviewed-by: Kevin Tian +Link: https://lore.kernel.org/r/20260120061816.2132558-3-baolu.lu@linux.intel.com +Signed-off-by: Joerg Roedel +Signed-off-by: Konstantin Andreev +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/iommu.c | 4 +++- + drivers/iommu/intel/iommu.h | 21 ++++++++++++++++++++- + drivers/iommu/intel/pasid.c | 5 ++++- + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/drivers/iommu/intel/iommu.c b/drivers/iommu/intel/iommu.c +index cce5a19b5d330e..18022d17c492b6 100644 +--- a/drivers/iommu/intel/iommu.c ++++ b/drivers/iommu/intel/iommu.c +@@ -1914,10 +1914,12 @@ static void domain_context_clear_one(struct device_domain_info *info, u8 bus, u8 + } + + did = context_domain_id(context); +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); + intel_context_flush_present(info, context, did, true); ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); + } + + static int domain_setup_first_level(struct intel_iommu *iommu, +diff --git a/drivers/iommu/intel/iommu.h b/drivers/iommu/intel/iommu.h +index b33d8888d7ebd7..e46eb1d3fba29d 100644 +--- a/drivers/iommu/intel/iommu.h ++++ b/drivers/iommu/intel/iommu.h +@@ -958,7 +958,26 @@ static inline unsigned long virt_to_dma_pfn(void *p) + + static inline void context_set_present(struct context_entry *context) + { +- context->lo |= 1; ++ u64 val; ++ ++ dma_wmb(); ++ val = READ_ONCE(context->lo) | 1; ++ WRITE_ONCE(context->lo, val); ++} ++ ++/* ++ * Clear the Present (P) bit (bit 0) of a context table entry. This initiates ++ * the transition of the entry's ownership from hardware to software. The ++ * caller is responsible for fulfilling the invalidation handshake recommended ++ * by the VT-d spec, Section 6.5.3.3 (Guidance to Software for Invalidations). ++ */ ++static inline void context_clear_present(struct context_entry *context) ++{ ++ u64 val; ++ ++ val = READ_ONCE(context->lo) & GENMASK_ULL(63, 1); ++ WRITE_ONCE(context->lo, val); ++ dma_wmb(); + } + + static inline void context_set_fault_enable(struct context_entry *context) +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 74be6b547fc0c2..5e63b5d4577f75 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -804,7 +804,7 @@ static int device_pasid_table_setup(struct device *dev, u8 bus, u8 devfn) + } + + if (context_copied(iommu, bus, devfn)) { +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + + /* +@@ -824,6 +824,9 @@ static int device_pasid_table_setup(struct device *dev, u8 bus, u8 devfn) + iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH); + devtlb_invalidation_with_pasid(iommu, dev, IOMMU_NO_PASID); + ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); ++ + /* + * At this point, the device is supposed to finish reset at + * its driver probe stage, so no in-flight DMA will exist, +-- +2.53.0 + diff --git a/staging-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch b/staging-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch new file mode 100644 index 0000000000..d0583ea7a5 --- /dev/null +++ b/staging-6.12/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch @@ -0,0 +1,65 @@ +From 9803b6151a06be785b1620280a2ac976d26ec347 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:03:07 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down scalable-mode + context entry + +From: Michael Bommarito + +[ Upstream commit f46452c3df7a8d8a5addc0926e76ef19ea7da0a0 ] + +device_pasid_table_teardown() zeroes the 128-bit scalable-mode context +entry with context_clear_entry() while the Present bit is still set. This +creates a window where the hardware can fetch a torn entry, with some +fields already zeroed while Present is still set, leading to unpredictable +behavior or spurious faults. The context-cache invalidation is issued only +after the entry has been zeroed, and intel_pasid_free_table() then frees +the PASID directory pages, so the IOMMU can keep walking a stale Present=1 +entry that points at freed memory. + +While x86 provides strong write ordering, the compiler may reorder the two +64-bit writes to the entry, and the hardware fetch is not guaranteed to be +atomic with respect to multiple CPU writes. + +Commit c1e4f1dccbe9d ("iommu/vt-d: Clear Present bit before tearing down +context entry") fixed this exact pattern in domain_context_clear_one() and +the copied-context path, but device_pasid_table_teardown() was not +converted. + +Align it with the "Guidance to Software for Invalidations" in the VT-d +spec, Section 6.5.3.3, using the same ownership handshake as the sibling +fix: clear only the Present bit, flush it to the IOMMU, perform the +context-cache invalidation, and only then zero the rest of the entry. + +Fixes: 81e921fd32161 ("iommu/vt-d: Fix NULL domain on device release") +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 +Link: https://lore.kernel.org/r/20260528025557.3209367-1-michael.bommarito@gmail.com +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 0e0c6cf2d3f4d3..93e9b9243d5fdb 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -714,10 +714,12 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn) + } + + did = context_domain_id(context); +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); + intel_context_flush_no_pasid(info, context, did); ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); + } + + static int pci_pasid_table_teardown(struct pci_dev *pdev, u16 alias, void *data) +-- +2.53.0 + diff --git a/staging-6.12/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch b/staging-6.12/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch new file mode 100644 index 0000000000..c37d894b4d --- /dev/null +++ b/staging-6.12/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch @@ -0,0 +1,94 @@ +From 076ee954e0a39402ceb8eabe65e7790dfda604e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 14:51:57 +0100 +Subject: KVM: arm64: Bound used_lrs when flushing the pKVM hyp vCPU + +From: Hyunwoo Kim + +commit 8cc8bbbfab14c22c5551d0dd19b208a44b141c76 upstream. + +flush_hyp_vcpu() copies the host vGIC state into the hyp's private vCPU +on every run. The vGIC list register save and restore use used_lrs as +their loop bound and expect it to stay within the number of implemented +list registers. While this is generally the case, flush_hyp_vcpu() +copies vgic_v3 verbatim and does not enforce this, so a value provided +by the host is used at EL2 to index vgic_lr[] and access ICH_LR_EL2 +(host -> EL2). + +Fix by clamping used_lrs to the number of implemented list registers +after the copy, as the trusted path already does in +vgic_flush_lr_state(). The number of implemented list registers is +constant after init, so it is replicated once from +kvm_vgic_global_state.nr_lr into hyp_gicv3_nr_lr rather than read on +every entry. + +Cc: stable@vger.kernel.org +Fixes: be66e67f1750 ("KVM: arm64: Use the pKVM hyp vCPU structure in handle___kvm_vcpu_run()") +Signed-off-by: Hyunwoo Kim +Reviewed-by: Fuad Tabba +Tested-by: Fuad Tabba +Link: https://patch.msgid.link/20260606175614.83273-3-imv4bel@gmail.com +Signed-off-by: Marc Zyngier +[ tabba: adjust context in flush_hyp_vcpu() and kvm_hyp.h ] +Signed-off-by: Fuad Tabba +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kvm_hyp.h | 1 + + arch/arm64/kvm/arm.c | 2 ++ + arch/arm64/kvm/hyp/nvhe/hyp-main.c | 9 +++++++++ + 3 files changed, 12 insertions(+) + +diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h +index c838309e4ec47e..19b8843374d0cf 100644 +--- a/arch/arm64/include/asm/kvm_hyp.h ++++ b/arch/arm64/include/asm/kvm_hyp.h +@@ -144,5 +144,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val); + extern unsigned long kvm_nvhe_sym(__icache_flags); + extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits); + extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl); ++extern unsigned int kvm_nvhe_sym(hyp_gicv3_nr_lr); + + #endif /* __ARM64_KVM_HYP_H__ */ +diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c +index 3753ef782e98e5..a713f32a6545b1 100644 +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -2313,6 +2313,8 @@ static int __init init_subsystems(void) + switch (err) { + case 0: + vgic_present = true; ++ if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) ++ kvm_nvhe_sym(hyp_gicv3_nr_lr) = kvm_vgic_global_state.nr_lr; + break; + case -ENODEV: + case -ENXIO: +diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +index 75f7e386de75bc..5dbc1878428cc2 100644 +--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c ++++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +@@ -22,6 +22,9 @@ + + DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); + ++/* Number of implemented GICv3 LRs. Used by flush_hyp_vcpu(). */ ++unsigned int hyp_gicv3_nr_lr; ++ + void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt); + + static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu) +@@ -116,6 +119,12 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) + hyp_vcpu->vcpu.arch.vsesr_el2 = host_vcpu->arch.vsesr_el2; + + hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3 = host_vcpu->arch.vgic_cpu.vgic_v3; ++ ++ /* Bound used_lrs by the number of implemented list registers. */ ++ hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs = ++ min_t(unsigned int, ++ hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs, ++ hyp_gicv3_nr_lr); + } + + static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) +-- +2.53.0 + diff --git a/staging-6.12/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch b/staging-6.12/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch new file mode 100644 index 0000000000..525ded31f7 --- /dev/null +++ b/staging-6.12/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch @@ -0,0 +1,50 @@ +From c5ab9545bc3b0516913f832b616501c797bb739d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 14:51:25 +0100 +Subject: KVM: arm64: Clear __hyp_running_vcpu when flushing the pKVM hyp vCPU + +From: Hyunwoo Kim + +commit e8042f6e1d7befb2fb6b10a75918642bcd0acf9a upstream. + +flush_hyp_vcpu() copies the host vCPU context into the hyp's private +vCPU on every run. ctxt_to_vcpu() expects a guest context to have a +NULL __hyp_running_vcpu, which is only ever set on the host context, so +that it resolves the vCPU via container_of(). While this is generally +the case, flush_hyp_vcpu() copies the context verbatim and does not +enforce this, so a value provided by the host is dereferenced at EL2 +(host -> EL2). + +Fix by clearing __hyp_running_vcpu after the copy. + +Cc: stable@vger.kernel.org +Fixes: be66e67f1750 ("KVM: arm64: Use the pKVM hyp vCPU structure in handle___kvm_vcpu_run()") +Signed-off-by: Hyunwoo Kim +Reviewed-by: Fuad Tabba +Tested-by: Fuad Tabba +Link: https://patch.msgid.link/20260606175614.83273-2-imv4bel@gmail.com +Signed-off-by: Marc Zyngier +[ tabba: adjust flush_hyp_vcpu() context ] +Signed-off-by: Fuad Tabba +Signed-off-by: Sasha Levin +--- + arch/arm64/kvm/hyp/nvhe/hyp-main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +index 5dbc1878428cc2..72384712377d16 100644 +--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c ++++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +@@ -103,6 +103,9 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) + + hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt; + ++ /* __hyp_running_vcpu must be NULL in a guest context. */ ++ hyp_vcpu->vcpu.arch.ctxt.__hyp_running_vcpu = NULL; ++ + hyp_vcpu->vcpu.arch.sve_state = kern_hyp_va(host_vcpu->arch.sve_state); + /* Limit guest vector length to the maximum supported by the host. */ + hyp_vcpu->vcpu.arch.sve_max_vl = min(host_vcpu->arch.sve_max_vl, kvm_host_sve_max_vl); +-- +2.53.0 + diff --git a/staging-6.12/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch b/staging-6.12/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch new file mode 100644 index 0000000000..3a0fd5d66d --- /dev/null +++ b/staging-6.12/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch @@ -0,0 +1,50 @@ +From 329a10f14b2a1aa66d4d492dc8c42f6decbd319a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Oct 2025 06:43:22 +0000 +Subject: sched/fair: Only update stats for allowed CPUs when looking for dst + group + +From: Adam Li + +[ Upstream commit 82d6e01a0699800efd8b048eb584c907ccb47b7a ] + +Load imbalance is observed when the workload frequently forks new threads. +Due to CPU affinity, the workload can run on CPU 0-7 in the first +group, and only on CPU 8-11 in the second group. CPU 12-15 are always idle. + +{ 0 1 2 3 4 5 6 7 } {8 9 10 11 12 13 14 15} + * * * * * * * * * * * * + +When looking for dst group for newly forked threads, in many times +update_sg_wakeup_stats() reports the second group has more idle CPUs +than the first group. The scheduler thinks the second group is less +busy. Then it selects least busy CPUs among CPU 8-11. Therefore CPU 8-11 +can be crowded with newly forked threads, at the same time CPU 0-7 +can be idle. + +A task may not use all the CPUs in a schedule group due to CPU affinity. +Only update schedule group statistics for allowed CPUs. + +Signed-off-by: Adam Li +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index f36512892adf9d..bd1b30ca184f3c 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -10739,7 +10739,7 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd, + if (sd->flags & SD_ASYM_CPUCAPACITY) + sgs->group_misfit_task_load = 1; + +- for_each_cpu(i, sched_group_span(group)) { ++ for_each_cpu_and(i, sched_group_span(group), p->cpus_ptr) { + struct rq *rq = cpu_rq(i); + unsigned int local; + +-- +2.53.0 + diff --git a/staging-6.12/series b/staging-6.12/series new file mode 100644 index 0000000000..3974357782 --- /dev/null +++ b/staging-6.12/series @@ -0,0 +1,17 @@ +smb-server-do-not-require-delete-access-for-non-repl.patch +iommu-vt-d-clear-present-bit-before-tearing-down-con.patch +tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch +bpf-support-for-hardening-against-jit-spraying.patch +x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch +bpf-restrict-jit-predictor-flush-to-cbpf.patch +bpf-skip-redundant-ibpb-in-pack-allocator.patch +bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch +bpf-prefer-dirty-packs-for-ebpf-allocations.patch +sched-fair-only-update-stats-for-allowed-cpus-when-l.patch +crypto-algif_skcipher-force-synchronous-processing.patch +kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch +kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch +iommu-pass-old-domain-to-set_dev_pasid-op.patch +iommu-vt-d-cleanup-intel_context_flush_present.patch +iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch +timekeeping-register-default-clocksource-before-taki.patch diff --git a/staging-6.12/smb-server-do-not-require-delete-access-for-non-repl.patch b/staging-6.12/smb-server-do-not-require-delete-access-for-non-repl.patch new file mode 100644 index 0000000000..c22a405199 --- /dev/null +++ b/staging-6.12/smb-server-do-not-require-delete-access-for-non-repl.patch @@ -0,0 +1,61 @@ +From 342442e5d1c59fa35d816a0b82f88b60ad1729bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Jun 2026 07:42:43 +0000 +Subject: smb/server: do not require delete access for non-replacing links + +From: ChenXiaoSong + +[ Upstream commit 851ed9e09639e0daf79a506ce26097b296ed5518 ] + +Reproducer: + + 1. server: systemctl start ksmbd + 2. client: mount -t cifs //${server_ip}/export /mnt + 3. client: touch /mnt/file; ln /mnt/file /mnt/hardlink + 4. client err log: ln: failed to create hard link 'hardlink' => + 'file': Permission denied + 5. server err log: ksmbd: no right to delete : 0x80 + +Fixes: 13f3942f2bf4 ("ksmbd: add per-handle permission check to FILE_LINK_INFORMATION") +Cc: stable@vger.kernel.org +Reported-by: Steve French +Signed-off-by: ChenXiaoSong +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 2fd1fb03c01e21..f1cadc029677e8 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -6526,16 +6526,18 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, + } + case FILE_LINK_INFORMATION: + { +- if (!(fp->daccess & FILE_DELETE_LE)) { +- pr_err("no right to delete : 0x%x\n", fp->daccess); +- return -EACCES; +- } ++ struct smb2_file_link_info *file_info; + + if (buf_len < sizeof(struct smb2_file_link_info)) + return -EINVAL; + +- return smb2_create_link(work, work->tcon->share_conf, +- (struct smb2_file_link_info *)buffer, ++ file_info = (struct smb2_file_link_info *)buffer; ++ if (file_info->ReplaceIfExists && !(fp->daccess & FILE_DELETE_LE)) { ++ pr_err("no right to delete : 0x%x\n", fp->daccess); ++ return -EACCES; ++ } ++ ++ return smb2_create_link(work, work->tcon->share_conf, file_info, + buf_len, fp->filp, + work->conn->local_nls); + } +-- +2.53.0 + diff --git a/staging-6.12/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch b/staging-6.12/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch new file mode 100644 index 0000000000..14e499e579 --- /dev/null +++ b/staging-6.12/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch @@ -0,0 +1,124 @@ +From 09f2df28c67f9bbe241cbfded731196f8da63ab1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:07:04 +0200 +Subject: tcp: Add preempt_{disable,enable}_nested() in reqsk_queue_hash_req(). + +From: Kuniyuki Iwashima + +[ Upstream commit e10902df24488ca722303133acfc82490f7d59ad ] + +syzbot reported a weird reqsk->rsk_refcnt underflow in +__inet_csk_reqsk_queue_drop(). + +The captured reqsk_put() in __inet_csk_reqsk_queue_drop() +is called only when it successfully removes reqsk from ehash. + +Moreover, reqsk_timer_handler() calls another reqsk_put() +after that. + +This indicates that the reqsk was missing both refcnts for +ehash and the timer itself. + +Since all the syzbot reports had PREEMPT_RT enabled, the only +possible scenario is that reqsk_queue_hash_req() is preempted +after mod_timer() and before refcount_set(), and then the timer +triggered after 1s aborts the reqsk due to its listener's close(). + +Let's wrap mod_timer() and refcount_set() with +preempt_disable_nested() and preempt_enable_nested(). + +Note that inet_ehash_insert() holds the normal spin_lock() +(mutex in PREEMPT_RT), so it must be called outside of +preempt_disable_nested(), but this is fine. + +The lookup path just ignores 0 sk_refcnt entries in ehash +and tries to create another reqsk, but this will fail at +inet_ehash_insert(). + +[0]: +refcount_t: underflow; use-after-free. +WARNING: lib/refcount.c:28 at refcount_warn_saturate+0xb2/0x110 lib/refcount.c:28, CPU#0: ktimers/0/16 +Modules linked in: +CPU: 0 UID: 0 PID: 16 Comm: ktimers/0 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} +Tainted: [L]=SOFTLOCKUP +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 +RIP: 0010:refcount_warn_saturate+0xb2/0x110 lib/refcount.c:28 +Code: e4 7d d1 0a 67 48 0f b9 3a eb 4a e8 38 3d 23 fd 48 8d 3d e1 7d d1 0a 67 48 0f b9 3a eb 37 e8 25 3d 23 fd 48 8d 3d de 7d d1 0a <67> 48 0f b9 3a eb 24 e8 12 3d 23 fd 48 8d 3d db 7d d1 0a 67 48 0f +RSP: 0000:ffffc90000157948 EFLAGS: 00010246 +RAX: ffffffff84a1301b RBX: 0000000000000003 RCX: ffff88801ca98000 +RDX: 0000000000000100 RSI: 0000000000000000 RDI: ffffffff8f72ae00 +RBP: ffffffff99ae3b01 R08: ffff88801ca98000 R09: 0000000000000005 +R10: 0000000000000100 R11: 0000000000000004 R12: ffff8880425ef568 +R13: ffff8880425ef4f8 R14: ffff8880425ef578 R15: 0000000000000000 +FS: 0000000000000000(0000) GS:ffff888126386000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f7b46710e9c CR3: 000000000dbb6000 CR4: 00000000003526f0 +Call Trace: + + __refcount_sub_and_test include/linux/refcount.h:400 [inline] + __refcount_dec_and_test include/linux/refcount.h:432 [inline] + refcount_dec_and_test include/linux/refcount.h:450 [inline] + reqsk_put include/net/request_sock.h:136 [inline] + __inet_csk_reqsk_queue_drop+0x3ce/0x440 net/ipv4/inet_connection_sock.c:1007 + reqsk_timer_handler+0x651/0xdf0 net/ipv4/inet_connection_sock.c:1137 + call_timer_fn+0x192/0x5e0 kernel/time/timer.c:1748 + expire_timers kernel/time/timer.c:1799 [inline] + __run_timers kernel/time/timer.c:2374 [inline] + __run_timer_base+0x6a3/0x9f0 kernel/time/timer.c:2386 + run_timer_base kernel/time/timer.c:2395 [inline] + run_timer_softirq+0x67/0x170 kernel/time/timer.c:2403 + handle_softirqs+0x1de/0x6d0 kernel/softirq.c:622 + __do_softirq kernel/softirq.c:656 [inline] + run_ktimerd+0x69/0x100 kernel/softirq.c:1151 + smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160 + kthread+0x388/0x470 kernel/kthread.c:436 + ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + + +Fixes: d2d6422f8bd1 ("x86: Allow to enable PREEMPT_RT.") +Reported-by: syzbot+e809069bc15f26300526@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a1a7bcf.0a9e871e.332604.000b.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260601182101.3183993-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +[updated to not require timeout changes from + commit 3ce5dd8161ec ("tcp: Remove timeout arg from reqsk_queue_hash_req()") + DCCP was retired by commit 2a63dd0edf38 ("net: Retire DCCP socket.") after + the release of 6.12, so the shared inet_csk_reqsk_queue_hash_add still + requires the timout argument] +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index dd39cabb39001e..5ff45bc854422b 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1186,6 +1186,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req, + + /* The timer needs to be setup after a successful insertion. */ + timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED); ++ ++ preempt_disable_nested(); ++ + mod_timer(&req->rsk_timer, jiffies + timeout); + + /* before letting lookups find us, make sure all req fields +@@ -1193,6 +1196,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req, + */ + smp_wmb(); + refcount_set(&req->rsk_refcnt, 2 + 1); ++ ++ preempt_enable_nested(); ++ + return true; + } + +-- +2.53.0 + diff --git a/staging-6.12/timekeeping-register-default-clocksource-before-taki.patch b/staging-6.12/timekeeping-register-default-clocksource-before-taki.patch new file mode 100644 index 0000000000..a86ff6c269 --- /dev/null +++ b/staging-6.12/timekeeping-register-default-clocksource-before-taki.patch @@ -0,0 +1,70 @@ +From 411a58cd35fbeea473490223dc3377598739e461 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 16 Jun 2026 12:09:14 +0500 +Subject: timekeeping: Register default clocksource before taking tk_core.lock + +From: Mikhail Gavrilov + +[ Upstream commit 8fa30821180a9a19e78e9f4df1c0ba710252801e ] + +Commit f24df84cbe05 ("time/jiffies: Register jiffies clocksource before +usage") moved the jiffies clocksource registration into +clocksource_default_clock(), so that it is registered lazily on the first +call. __clocksource_register() acquires clocksource_mutex, but the first +caller is timekeeping_init(), which invokes clocksource_default_clock() +while holding tk_core.lock, a raw spinlock. + +Acquiring a sleeping mutex while holding a raw spinlock is invalid. + +The default clocksource only has to be registered before +tk_setup_internals() consumes its mult/shift/maxadj. Neither +clocksource_default_clock(), the ->enable() callback, nor the registration +itself need tk_core.lock, so fetch and enable the clock before acquiring +the lock. This preserves the "register before usage" ordering while +keeping clocksource_mutex out of the raw spinlock section. + +clocksource_default_clock() has a second caller, +clocksource_done_booting(), which invokes it with clocksource_mutex already +held. That path avoids a recursive lock because timekeeping_init() has +already run and set cs_jiffies_registered, so the registration is skipped +there. This change does not alter that; it only fixes the invalid wait +context in timekeeping_init(). + +Fixes: f24df84cbe05 ("time/jiffies: Register jiffies clocksource before usage") +Signed-off-by: Mikhail Gavrilov +Signed-off-by: Thomas Gleixner +Reported-by: Breno Leitao +Reported-by: Oleg Nesterov +Reviewed-by: Breno Leitao +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/20260616070914.65818-1-mikhail.v.gavrilov@gmail.com +Signed-off-by: Sasha Levin +--- + kernel/time/timekeeping.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c +index e3896b2be45321..b99171e71e0ac5 100644 +--- a/kernel/time/timekeeping.c ++++ b/kernel/time/timekeeping.c +@@ -1685,13 +1685,14 @@ void __init timekeeping_init(void) + */ + wall_to_mono = timespec64_sub(boot_offset, wall_time); + ++ clock = clocksource_default_clock(); ++ if (clock->enable) ++ clock->enable(clock); ++ + raw_spin_lock_irqsave(&timekeeper_lock, flags); + write_seqcount_begin(&tk_core.seq); + ntp_init(); + +- clock = clocksource_default_clock(); +- if (clock->enable) +- clock->enable(clock); + tk_setup_internals(tk, clock); + + tk_set_xtime(tk, &wall_time); +-- +2.53.0 + diff --git a/staging-6.12/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch b/staging-6.12/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch new file mode 100644 index 0000000000..5de5280648 --- /dev/null +++ b/staging-6.12/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch @@ -0,0 +1,147 @@ +From 128505f3e1a24a6693dca064abc9970f2c9265c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:28:09 -0700 +Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation + +From: Pawan Gupta + +commit a3af84b0fa00ead01fcd0e28b5d773ff25990a0d upstream. + +Enable hardening against JIT spraying when Spectre-v2 mitigations are in +use. Specifically, issue an IBPB flush on BPF JIT memory reuse. Skip +enabling the IBPB flush if the BPF dispatcher is already using a retpoline +sequence. + +This hardening applies only when BPF-JIT is in use. Guard the enabling +under CONFIG_BPF_JIT so that bugs.c still builds with CONFIG_BPF_JIT=n. + + [ pawan: Use entry_ibpb() instead of write_ibpb(). JIT hardening enable + moved to spectre_v2_select_mitigation() because there is no + spectre_v2_apply_mitigation()] + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Acked-by: Dave Hansen +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/nospec-branch.h | 4 +++ + arch/x86/kernel/cpu/bugs.c | 50 +++++++++++++++++++++++++--- + 2 files changed, 49 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h +index f2cc7754918c0d..2e0812a8ed77af 100644 +--- a/arch/x86/include/asm/nospec-branch.h ++++ b/arch/x86/include/asm/nospec-branch.h +@@ -405,6 +405,10 @@ extern void srso_alias_return_thunk(void); + extern void entry_untrain_ret(void); + extern void entry_ibpb(void); + ++#ifdef CONFIG_BPF_JIT ++extern void bpf_arch_ibpb(void); ++#endif ++ + #ifdef CONFIG_X86_64 + extern void clear_bhb_loop(void); + #endif +diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c +index 939401b5d2ef04..12544fdcadd6af 100644 +--- a/arch/x86/kernel/cpu/bugs.c ++++ b/arch/x86/kernel/cpu/bugs.c +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1360,8 +1361,21 @@ static inline const char *spectre_v2_module_string(void) + { + return spectre_v2_bad_module ? " - vulnerable module loaded" : ""; + } ++ ++/* ++ * The "retpoline sequence" is the "call;mov;ret" sequence that ++ * replaces normal indirect branch instructions. Differentiate ++ * *the* retpoline sequence from the LFENCE-prefixed indirect ++ * branches that simply use the retpoline infrastructure. ++ */ ++static inline bool retpoline_seq_enabled(void) ++{ ++ return boot_cpu_has(X86_FEATURE_RETPOLINE) && !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE); ++} ++ + #else + static inline const char *spectre_v2_module_string(void) { return ""; } ++static inline bool retpoline_seq_enabled(void) { return false; } + #endif + + #define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n" +@@ -1843,8 +1857,7 @@ static void __init bhi_select_mitigation(void) + return; + + /* Retpoline mitigates against BHI unless the CPU has RRSBA behavior */ +- if (boot_cpu_has(X86_FEATURE_RETPOLINE) && +- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE)) { ++ if (retpoline_seq_enabled()) { + spec_ctrl_disable_kernel_rrsba(); + if (rrsba_disabled) + return; +@@ -1868,6 +1881,27 @@ static void __init bhi_select_mitigation(void) + setup_force_cpu_cap(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT); + } + ++#ifdef CONFIG_BPF_JIT ++static void __bpf_arch_ibpb(void *unused) ++{ ++ entry_ibpb(); ++} ++ ++void bpf_arch_ibpb(void) ++{ ++ on_each_cpu(__bpf_arch_ibpb, NULL, 1); ++} ++ ++static bool __init cpu_wants_ibpb_bpf(void) ++{ ++ /* A genuine retpoline already neutralizes ring0 indirect predictions */ ++ if (retpoline_seq_enabled()) ++ return false; ++ ++ return boot_cpu_has(X86_FEATURE_IBPB); ++} ++#endif ++ + static void __init spectre_v2_select_mitigation(void) + { + enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline(); +@@ -2051,6 +2085,14 @@ static void __init spectre_v2_select_mitigation(void) + pr_info("Enabling Restricted Speculation for firmware calls\n"); + } + ++#ifdef CONFIG_BPF_JIT ++ if (cpu_wants_ibpb_bpf()) { ++ static_call_update(bpf_arch_pred_flush, bpf_arch_ibpb); ++ static_branch_enable(&bpf_pred_flush_enabled); ++ pr_info("Enabling IBPB for BPF\n"); ++ } ++#endif ++ + /* Set up IBPB and STIBP depending on the general spectre V2 command */ + spectre_v2_cmd = cmd; + } +@@ -3239,9 +3281,7 @@ static const char *spectre_bhi_state(void) + return "; BHI: BHI_DIS_S"; + else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP)) + return "; BHI: SW loop, KVM: SW loop"; +- else if (boot_cpu_has(X86_FEATURE_RETPOLINE) && +- !boot_cpu_has(X86_FEATURE_RETPOLINE_LFENCE) && +- rrsba_disabled) ++ else if (retpoline_seq_enabled() && rrsba_disabled) + return "; BHI: Retpoline"; + else if (boot_cpu_has(X86_FEATURE_CLEAR_BHB_LOOP_ON_VMEXIT)) + return "; BHI: Vulnerable, KVM: SW loop"; +-- +2.53.0 + diff --git a/staging-6.18/crypto-algif_skcipher-force-synchronous-processing.patch b/staging-6.18/crypto-algif_skcipher-force-synchronous-processing.patch new file mode 100644 index 0000000000..a5149c64f5 --- /dev/null +++ b/staging-6.18/crypto-algif_skcipher-force-synchronous-processing.patch @@ -0,0 +1,159 @@ +From ed7e0af4a748b8f7b1163c5a584b8494d03e1129 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 02:58:36 +0000 +Subject: crypto: algif_skcipher - force synchronous processing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Muhammet Kaan KILINÇ + +The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv +directly into the skcipher request. After io_submit() the socket lock is +dropped and the request is processed asynchronously by a worker (e.g. +cryptd), which dereferences ctx->iv only later. + +A concurrent sendmsg(ALG_SET_IV) on the same socket can overwrite ctx->iv +inside this window, so the in-flight request runs under an +attacker-controlled IV. For CTR and other stream modes this causes +IV/keystream reuse and allows an unprivileged user to recover the +plaintext of a concurrent operation. + +Snapshotting ctx->iv into per-request storage for the async path is not +sufficient here. For ciphers with statesize == 0 - which includes cbc +and ctr - skcipher_prepare_alg() installs skcipher_noimport()/ +skcipher_noexport(), so ctx->state carries nothing and the MSG_MORE +inter-chunk IV chaining is carried solely by the in-place req->iv +writeback. A snapshot redirects that writeback into per-request memory +that af_alg_free_resources() releases on completion, so AIO + MSG_MORE +with cbc/ctr would silently produce wrong output. Writing the IV back +from the completion callback instead is not possible either: that would +require lock_sock() there, but the callback can run in softirq/atomic +context, so it must not sleep. + +Make the operation synchronous instead. ctx->iv is then only ever +dereferenced under the socket lock held by recvmsg(), which removes the +race, and the req->iv writeback lands in ctx->iv as before, which keeps +MSG_MORE chaining intact for statesize == 0 ciphers. The ctx->state +import/export path is unchanged for ciphers that do have state. + +This is equivalent to the upstream resolution: commit fcc77d33a34c +("net: Remove support for AIO on sockets") removed the AIO socket path +across net/ entirely, producing the same end state for this file - +algif_skcipher never processes an AIO request asynchronously. After this +patch, _skcipher_recvmsg() matches mainline's crypto/algif_skcipher.c as +it stands today, including the same now-dead -EIOCBQUEUED check. This +patch deviates from that commit deliberately: rather than removing AIO +socket support tree-wide, which would be far too invasive for stable, it +removes only the AIO branch in crypto/algif_skcipher.c. io_submit() now +completes synchronously, which is valid for the AIO interface; AF_ALG +async is rarely used in practice. + +The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, +and is left alone to keep the fix minimal. + +Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") +Cc: +Reported-by: Muhammet Kaan KILINÇ +Signed-off-by: Muhammet Kaan KILINÇ +Signed-off-by: Sasha Levin +--- + crypto/algif_skcipher.c | 75 +++++++++++++---------------------------- + 1 file changed, 24 insertions(+), 51 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index ba0a17fd95aca2..35ebc3e0201b04 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -79,20 +79,6 @@ static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req) + return err; + } + +-static void algif_skcipher_done(void *data, int err) +-{ +- struct af_alg_async_req *areq = data; +- struct sock *sk = areq->sk; +- +- if (err) +- goto out; +- +- err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); +- +-out: +- af_alg_async_cb(data, err); +-} +- + static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) + { +@@ -171,43 +157,30 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + cflags |= CRYPTO_SKCIPHER_REQ_CONT; + } + +- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { +- /* AIO operation */ +- sock_hold(sk); +- areq->iocb = msg->msg_iocb; +- +- /* Remember output size that will be generated. */ +- areq->outlen = len; +- +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- cflags | +- CRYPTO_TFM_REQ_MAY_SLEEP, +- algif_skcipher_done, areq); +- err = ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); +- +- /* AIO operation in progress */ +- if (err == -EINPROGRESS) +- return -EIOCBQUEUED; +- +- sock_put(sk); +- } else { +- /* Synchronous operation */ +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- cflags | +- CRYPTO_TFM_REQ_MAY_SLEEP | +- CRYPTO_TFM_REQ_MAY_BACKLOG, +- crypto_req_done, &ctx->wait); +- err = crypto_wait_req(ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), +- &ctx->wait); +- +- if (!err) +- err = algif_skcipher_export( +- sk, &areq->cra_u.skcipher_req); +- } ++ /* ++ * Force synchronous processing. The async (AIO) path passed the ++ * socket-wide ctx->iv into the request, which the worker ++ * dereferenced after the socket lock had been dropped, letting a ++ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline ++ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove ++ * support for AIO on sockets"); the minimal stable fix is to always ++ * complete synchronously, so ctx->iv is only ever dereferenced under ++ * the socket lock. This also keeps the IV chaining intact: for ++ * ciphers with statesize == 0 (e.g. ctr, cbc) the chained IV is ++ * carried by the req->iv writeback into ctx->iv, which is only ++ * consistent on the synchronous path. ++ */ ++ skcipher_request_set_callback(&areq->cra_u.skcipher_req, ++ cflags | ++ CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &ctx->wait); ++ err = crypto_wait_req(ctx->enc ? ++ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : ++ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), ++ &ctx->wait); ++ if (!err) ++ err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); + + free: + af_alg_free_resources(areq); +-- +2.53.0 + diff --git a/staging-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch b/staging-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch new file mode 100644 index 0000000000..576b77355a --- /dev/null +++ b/staging-6.18/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch @@ -0,0 +1,65 @@ +From 761b3fae7b763a27f47aaf723ccc32e69ca1ad93 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:03:07 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down scalable-mode + context entry + +From: Michael Bommarito + +[ Upstream commit f46452c3df7a8d8a5addc0926e76ef19ea7da0a0 ] + +device_pasid_table_teardown() zeroes the 128-bit scalable-mode context +entry with context_clear_entry() while the Present bit is still set. This +creates a window where the hardware can fetch a torn entry, with some +fields already zeroed while Present is still set, leading to unpredictable +behavior or spurious faults. The context-cache invalidation is issued only +after the entry has been zeroed, and intel_pasid_free_table() then frees +the PASID directory pages, so the IOMMU can keep walking a stale Present=1 +entry that points at freed memory. + +While x86 provides strong write ordering, the compiler may reorder the two +64-bit writes to the entry, and the hardware fetch is not guaranteed to be +atomic with respect to multiple CPU writes. + +Commit c1e4f1dccbe9d ("iommu/vt-d: Clear Present bit before tearing down +context entry") fixed this exact pattern in domain_context_clear_one() and +the copied-context path, but device_pasid_table_teardown() was not +converted. + +Align it with the "Guidance to Software for Invalidations" in the VT-d +spec, Section 6.5.3.3, using the same ownership handshake as the sibling +fix: clear only the Present bit, flush it to the IOMMU, perform the +context-cache invalidation, and only then zero the rest of the entry. + +Fixes: 81e921fd32161 ("iommu/vt-d: Fix NULL domain on device release") +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 +Link: https://lore.kernel.org/r/20260528025557.3209367-1-michael.bommarito@gmail.com +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 787897e61efa37..85c3116e351c60 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -746,10 +746,12 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn) + } + + did = context_domain_id(context); +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); + intel_context_flush_no_pasid(info, context, did); ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); + } + + static int pci_pasid_table_teardown(struct pci_dev *pdev, u16 alias, void *data) +-- +2.53.0 + diff --git a/staging-6.18/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch b/staging-6.18/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch new file mode 100644 index 0000000000..3fc6da7249 --- /dev/null +++ b/staging-6.18/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch @@ -0,0 +1,94 @@ +From f8e5bda889ad63f9e28829ebb56b5c19e0009f4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 14:24:34 +0100 +Subject: KVM: arm64: Bound used_lrs when flushing the pKVM hyp vCPU + +From: Hyunwoo Kim + +commit 8cc8bbbfab14c22c5551d0dd19b208a44b141c76 upstream. + +flush_hyp_vcpu() copies the host vGIC state into the hyp's private vCPU +on every run. The vGIC list register save and restore use used_lrs as +their loop bound and expect it to stay within the number of implemented +list registers. While this is generally the case, flush_hyp_vcpu() +copies vgic_v3 verbatim and does not enforce this, so a value provided +by the host is used at EL2 to index vgic_lr[] and access ICH_LR_EL2 +(host -> EL2). + +Fix by clamping used_lrs to the number of implemented list registers +after the copy, as the trusted path already does in +vgic_flush_lr_state(). The number of implemented list registers is +constant after init, so it is replicated once from +kvm_vgic_global_state.nr_lr into hyp_gicv3_nr_lr rather than read on +every entry. + +Cc: stable@vger.kernel.org +Fixes: be66e67f1750 ("KVM: arm64: Use the pKVM hyp vCPU structure in handle___kvm_vcpu_run()") +Signed-off-by: Hyunwoo Kim +Reviewed-by: Fuad Tabba +Tested-by: Fuad Tabba +Link: https://patch.msgid.link/20260606175614.83273-3-imv4bel@gmail.com +Signed-off-by: Marc Zyngier +[ tabba: adjust context in flush_hyp_vcpu() and kvm_hyp.h ] +Signed-off-by: Fuad Tabba +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kvm_hyp.h | 1 + + arch/arm64/kvm/arm.c | 2 ++ + arch/arm64/kvm/hyp/nvhe/hyp-main.c | 9 +++++++++ + 3 files changed, 12 insertions(+) + +diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h +index e6be1f5d0967f6..8020e91b536d26 100644 +--- a/arch/arm64/include/asm/kvm_hyp.h ++++ b/arch/arm64/include/asm/kvm_hyp.h +@@ -146,5 +146,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val); + extern unsigned long kvm_nvhe_sym(__icache_flags); + extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits); + extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl); ++extern unsigned int kvm_nvhe_sym(hyp_gicv3_nr_lr); + + #endif /* __ARM64_KVM_HYP_H__ */ +diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c +index e59cb36b5f36f3..10fc6783cd608a 100644 +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -2311,6 +2311,8 @@ static int __init init_subsystems(void) + switch (err) { + case 0: + vgic_present = true; ++ if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) ++ kvm_nvhe_sym(hyp_gicv3_nr_lr) = kvm_vgic_global_state.nr_lr; + break; + case -ENODEV: + case -ENXIO: +diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +index 3dda50391446d9..6e7547b7ca432a 100644 +--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c ++++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +@@ -22,6 +22,9 @@ + + DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); + ++/* Number of implemented GICv3 LRs. Used by flush_hyp_vcpu(). */ ++unsigned int hyp_gicv3_nr_lr; ++ + void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt); + + static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu) +@@ -139,6 +142,12 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) + hyp_vcpu->vcpu.arch.vsesr_el2 = host_vcpu->arch.vsesr_el2; + + hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3 = host_vcpu->arch.vgic_cpu.vgic_v3; ++ ++ /* Bound used_lrs by the number of implemented list registers. */ ++ hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs = ++ min_t(unsigned int, ++ hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs, ++ hyp_gicv3_nr_lr); + } + + static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) +-- +2.53.0 + diff --git a/staging-6.18/nvme-pci-dma-unmap-the-correct-regions-in-nvme_free_.patch b/staging-6.18/nvme-pci-dma-unmap-the-correct-regions-in-nvme_free_.patch new file mode 100644 index 0000000000..621bd0cded --- /dev/null +++ b/staging-6.18/nvme-pci-dma-unmap-the-correct-regions-in-nvme_free_.patch @@ -0,0 +1,49 @@ +From 934f28062e7a9f36286c7baf93e3d3896c04523d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Jul 2026 22:13:42 +0200 +Subject: nvme-pci: DMA unmap the correct regions in nvme_free_sgls +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Roger Pau Monne + +commit a54afbc8a2138f8c2490510cf26cde188d480c43 upstream. + +The call to nvme_free_sgls() in nvme_unmap_data() has the sg_list and sge +parameters swapped. This wasn't noticed by the compiler because both share +the same type. On a Xen PV hardware domain, and possibly any other +architectures that takes that path, this leads to corruption of the NVMe +contents. + +Fixes: f0887e2a52d4 ("nvme-pci: create common sgl unmapping helper") +Reviewed-by: Christoph Hellwig +Signed-off-by: Roger Pau Monné +Signed-off-by: Keith Busch +[nb: drop the attrs parameter added in 6.19 by commit 61d43b1731e0 + ("nvme-pci: migrate to dma_map_phys instead of map_page"), which is + not in 6.18.y] +Signed-off-by: Nicolai Buchwitz +Signed-off-by: Sasha Levin +--- + drivers/nvme/host/pci.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 5e36a5926fe03d..8c66fd23a143c1 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -761,8 +761,8 @@ static void nvme_unmap_data(struct request *req) + + if (!blk_rq_dma_unmap(req, dma_dev, &iod->dma_state, iod->total_len)) { + if (nvme_pci_cmd_use_sgl(&iod->cmd)) +- nvme_free_sgls(req, iod->descriptors[0], +- &iod->cmd.common.dptr.sgl); ++ nvme_free_sgls(req, &iod->cmd.common.dptr.sgl, ++ iod->descriptors[0]); + else + nvme_free_prps(req); + } +-- +2.53.0 + diff --git a/staging-6.18/series b/staging-6.18/series new file mode 100644 index 0000000000..8a5bfe4e39 --- /dev/null +++ b/staging-6.18/series @@ -0,0 +1,6 @@ +nvme-pci-dma-unmap-the-correct-regions-in-nvme_free_.patch +smb-server-do-not-require-delete-access-for-non-repl.patch +tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch +crypto-algif_skcipher-force-synchronous-processing.patch +kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch +iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch diff --git a/staging-6.18/smb-server-do-not-require-delete-access-for-non-repl.patch b/staging-6.18/smb-server-do-not-require-delete-access-for-non-repl.patch new file mode 100644 index 0000000000..c087c6d6f1 --- /dev/null +++ b/staging-6.18/smb-server-do-not-require-delete-access-for-non-repl.patch @@ -0,0 +1,61 @@ +From 1034d817981342a8b7d3b769c5708346f63aa8df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Jun 2026 07:42:43 +0000 +Subject: smb/server: do not require delete access for non-replacing links + +From: ChenXiaoSong + +[ Upstream commit 851ed9e09639e0daf79a506ce26097b296ed5518 ] + +Reproducer: + + 1. server: systemctl start ksmbd + 2. client: mount -t cifs //${server_ip}/export /mnt + 3. client: touch /mnt/file; ln /mnt/file /mnt/hardlink + 4. client err log: ln: failed to create hard link 'hardlink' => + 'file': Permission denied + 5. server err log: ksmbd: no right to delete : 0x80 + +Fixes: 13f3942f2bf4 ("ksmbd: add per-handle permission check to FILE_LINK_INFORMATION") +Cc: stable@vger.kernel.org +Reported-by: Steve French +Signed-off-by: ChenXiaoSong +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 50e36050f9ea3c..44b87196c5afca 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -6572,16 +6572,18 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, + } + case FILE_LINK_INFORMATION: + { +- if (!(fp->daccess & FILE_DELETE_LE)) { +- pr_err("no right to delete : 0x%x\n", fp->daccess); +- return -EACCES; +- } ++ struct smb2_file_link_info *file_info; + + if (buf_len < sizeof(struct smb2_file_link_info)) + return -EINVAL; + +- return smb2_create_link(work, work->tcon->share_conf, +- (struct smb2_file_link_info *)buffer, ++ file_info = (struct smb2_file_link_info *)buffer; ++ if (file_info->ReplaceIfExists && !(fp->daccess & FILE_DELETE_LE)) { ++ pr_err("no right to delete : 0x%x\n", fp->daccess); ++ return -EACCES; ++ } ++ ++ return smb2_create_link(work, work->tcon->share_conf, file_info, + buf_len, fp->filp, + work->conn->local_nls); + } +-- +2.53.0 + diff --git a/staging-6.18/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch b/staging-6.18/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch new file mode 100644 index 0000000000..5685e6ec19 --- /dev/null +++ b/staging-6.18/tcp-add-preempt_-disable-enable-_nested-in-reqsk_que.patch @@ -0,0 +1,124 @@ +From 3c01ce5447cb2c7fdee49c0e16725c545bec767c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Jul 2026 14:07:04 +0200 +Subject: tcp: Add preempt_{disable,enable}_nested() in reqsk_queue_hash_req(). + +From: Kuniyuki Iwashima + +[ Upstream commit e10902df24488ca722303133acfc82490f7d59ad ] + +syzbot reported a weird reqsk->rsk_refcnt underflow in +__inet_csk_reqsk_queue_drop(). + +The captured reqsk_put() in __inet_csk_reqsk_queue_drop() +is called only when it successfully removes reqsk from ehash. + +Moreover, reqsk_timer_handler() calls another reqsk_put() +after that. + +This indicates that the reqsk was missing both refcnts for +ehash and the timer itself. + +Since all the syzbot reports had PREEMPT_RT enabled, the only +possible scenario is that reqsk_queue_hash_req() is preempted +after mod_timer() and before refcount_set(), and then the timer +triggered after 1s aborts the reqsk due to its listener's close(). + +Let's wrap mod_timer() and refcount_set() with +preempt_disable_nested() and preempt_enable_nested(). + +Note that inet_ehash_insert() holds the normal spin_lock() +(mutex in PREEMPT_RT), so it must be called outside of +preempt_disable_nested(), but this is fine. + +The lookup path just ignores 0 sk_refcnt entries in ehash +and tries to create another reqsk, but this will fail at +inet_ehash_insert(). + +[0]: +refcount_t: underflow; use-after-free. +WARNING: lib/refcount.c:28 at refcount_warn_saturate+0xb2/0x110 lib/refcount.c:28, CPU#0: ktimers/0/16 +Modules linked in: +CPU: 0 UID: 0 PID: 16 Comm: ktimers/0 Tainted: G L syzkaller #0 PREEMPT_{RT,(full)} +Tainted: [L]=SOFTLOCKUP +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026 +RIP: 0010:refcount_warn_saturate+0xb2/0x110 lib/refcount.c:28 +Code: e4 7d d1 0a 67 48 0f b9 3a eb 4a e8 38 3d 23 fd 48 8d 3d e1 7d d1 0a 67 48 0f b9 3a eb 37 e8 25 3d 23 fd 48 8d 3d de 7d d1 0a <67> 48 0f b9 3a eb 24 e8 12 3d 23 fd 48 8d 3d db 7d d1 0a 67 48 0f +RSP: 0000:ffffc90000157948 EFLAGS: 00010246 +RAX: ffffffff84a1301b RBX: 0000000000000003 RCX: ffff88801ca98000 +RDX: 0000000000000100 RSI: 0000000000000000 RDI: ffffffff8f72ae00 +RBP: ffffffff99ae3b01 R08: ffff88801ca98000 R09: 0000000000000005 +R10: 0000000000000100 R11: 0000000000000004 R12: ffff8880425ef568 +R13: ffff8880425ef4f8 R14: ffff8880425ef578 R15: 0000000000000000 +FS: 0000000000000000(0000) GS:ffff888126386000(0000) knlGS:0000000000000000 +CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 +CR2: 00007f7b46710e9c CR3: 000000000dbb6000 CR4: 00000000003526f0 +Call Trace: + + __refcount_sub_and_test include/linux/refcount.h:400 [inline] + __refcount_dec_and_test include/linux/refcount.h:432 [inline] + refcount_dec_and_test include/linux/refcount.h:450 [inline] + reqsk_put include/net/request_sock.h:136 [inline] + __inet_csk_reqsk_queue_drop+0x3ce/0x440 net/ipv4/inet_connection_sock.c:1007 + reqsk_timer_handler+0x651/0xdf0 net/ipv4/inet_connection_sock.c:1137 + call_timer_fn+0x192/0x5e0 kernel/time/timer.c:1748 + expire_timers kernel/time/timer.c:1799 [inline] + __run_timers kernel/time/timer.c:2374 [inline] + __run_timer_base+0x6a3/0x9f0 kernel/time/timer.c:2386 + run_timer_base kernel/time/timer.c:2395 [inline] + run_timer_softirq+0x67/0x170 kernel/time/timer.c:2403 + handle_softirqs+0x1de/0x6d0 kernel/softirq.c:622 + __do_softirq kernel/softirq.c:656 [inline] + run_ktimerd+0x69/0x100 kernel/softirq.c:1151 + smpboot_thread_fn+0x541/0xa50 kernel/smpboot.c:160 + kthread+0x388/0x470 kernel/kthread.c:436 + ret_from_fork+0x514/0xb70 arch/x86/kernel/process.c:158 + ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245 + + +Fixes: d2d6422f8bd1 ("x86: Allow to enable PREEMPT_RT.") +Reported-by: syzbot+e809069bc15f26300526@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/all/6a1a7bcf.0a9e871e.332604.000b.GAE@google.com/ +Signed-off-by: Kuniyuki Iwashima +Reviewed-by: Eric Dumazet +Reviewed-by: Sebastian Andrzej Siewior +Link: https://patch.msgid.link/20260601182101.3183993-1-kuniyu@google.com +Signed-off-by: Jakub Kicinski +[updated to not require timeout changes from + commit 3ce5dd8161ec ("tcp: Remove timeout arg from reqsk_queue_hash_req()") + DCCP was retired by commit 2a63dd0edf38 ("net: Retire DCCP socket.") after + the release of 6.12, so the shared inet_csk_reqsk_queue_hash_add still + requires the timout argument] +Signed-off-by: Heiko Stuebner +Signed-off-by: Sasha Levin +--- + net/ipv4/inet_connection_sock.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c +index c777895a720eec..4aa5cdef8e42c4 100644 +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -1163,6 +1163,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req, + + /* The timer needs to be setup after a successful insertion. */ + timer_setup(&req->rsk_timer, reqsk_timer_handler, TIMER_PINNED); ++ ++ preempt_disable_nested(); ++ + mod_timer(&req->rsk_timer, jiffies + timeout); + + /* before letting lookups find us, make sure all req fields +@@ -1170,6 +1173,9 @@ static bool reqsk_queue_hash_req(struct request_sock *req, + */ + smp_wmb(); + refcount_set(&req->rsk_refcnt, 2 + 1); ++ ++ preempt_enable_nested(); ++ + return true; + } + +-- +2.53.0 + diff --git a/staging-6.6/block-skip-sync_blockdev-on-surprise-removal-in-bdev.patch b/staging-6.6/block-skip-sync_blockdev-on-surprise-removal-in-bdev.patch new file mode 100644 index 0000000000..981bd6e803 --- /dev/null +++ b/staging-6.6/block-skip-sync_blockdev-on-surprise-removal-in-bdev.patch @@ -0,0 +1,67 @@ +From fe92b1c1dc089943451aa4be5d372efd5d356af2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 03:34:52 -0400 +Subject: block: skip sync_blockdev() on surprise removal in bdev_mark_dead() + +From: Chao Shi + +commit 49f06cff50a4ccf3b7a1a662ceb892b3b21a527a upstream. + +bdev_mark_dead()'s @surprise == true means the device is already gone. +The filesystem callback fs_bdev_mark_dead() honours this and skips +sync_filesystem(), but the bare block device path (no ->mark_dead op) +lost its !surprise guard when the holder ->mark_dead callback was wired +up (see Fixes), and now calls sync_blockdev() unconditionally, which can +hang forever waiting on writeback that can no longer complete. + +syzkaller hit this via nvme_reset_work()'s "I/O queues lost" path: +nvme_mark_namespaces_dead() -> blk_mark_disk_dead() -> +bdev_mark_dead(bdev, true) -> sync_blockdev() blocks in +folio_wait_writeback(), wedging the reset worker and every task waiting +on it. + +Skip the sync on surprise removal, matching fs_bdev_mark_dead(); +invalidate_bdev() still runs. Orderly removal (surprise == false) is +unchanged. + +Found by FuzzNvme. + +Fixes: d8530de5a6e8 ("block: call into the file system for bdev_mark_dead") +Acked-by: Sungwoo Kim +Acked-by: Dave Tian +Acked-by: Weidong Zhu +Signed-off-by: Chao Shi +Reviewed-by: Christoph Hellwig +Link: https://patch.msgid.link/20260522220025.1770388-1-coshi036@gmail.com +Signed-off-by: Jens Axboe +[ adjusted for 6.6.y: bdev_mark_dead() there still unlocks bd_holder_lock + after the if/else and the else arm is a bare sync_blockdev(), so the + !surprise guard is added as "else if (!surprise)" instead of inside the + mainline else block. ] +Signed-off-by: Chao Shi +Signed-off-by: Sasha Levin +--- + block/bdev.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/block/bdev.c b/block/bdev.c +index 598f94827b941f..a255492ba82654 100644 +--- a/block/bdev.c ++++ b/block/bdev.c +@@ -1024,7 +1024,12 @@ void bdev_mark_dead(struct block_device *bdev, bool surprise) + mutex_lock(&bdev->bd_holder_lock); + if (bdev->bd_holder_ops && bdev->bd_holder_ops->mark_dead) + bdev->bd_holder_ops->mark_dead(bdev, surprise); +- else ++ /* ++ * On surprise removal the device is already gone; syncing is ++ * futile and can hang forever waiting on I/O that will never ++ * complete. Match fs_bdev_mark_dead(), which also skips it. ++ */ ++ else if (!surprise) + sync_blockdev(bdev); + mutex_unlock(&bdev->bd_holder_lock); + +-- +2.53.0 + diff --git a/staging-6.6/crypto-algif_skcipher-force-synchronous-processing-o.patch b/staging-6.6/crypto-algif_skcipher-force-synchronous-processing-o.patch new file mode 100644 index 0000000000..31e6597e2e --- /dev/null +++ b/staging-6.6/crypto-algif_skcipher-force-synchronous-processing-o.patch @@ -0,0 +1,116 @@ +From 2ea7b51316ebdf3311a7c63dd309f51fa0d8b053 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 02:58:37 +0000 +Subject: crypto: algif_skcipher - force synchronous processing on trees + without ctx->state +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Muhammet Kaan KILINÇ + +The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv +directly into the skcipher request. After io_submit() the socket lock is +dropped and the request is processed asynchronously, so a concurrent +sendmsg(ALG_SET_IV) can overwrite ctx->iv and make the in-flight request +run under an attacker-controlled IV. For CTR/stream modes this is +IV/keystream reuse and lets an unprivileged user recover the plaintext of +a concurrent operation. + +Snapshotting ctx->iv into per-request storage for the async path is not +sufficient. For ciphers with statesize == 0 - which includes cbc and ctr - +the MSG_MORE inter-chunk IV chaining is carried solely by the in-place +req->iv writeback, which a snapshot redirects into per-request memory that +af_alg_free_resources() releases on completion, silently producing wrong +output. Writing the IV back from the completion callback instead is not +possible either: that would require lock_sock() there, but the callback can +run in softirq/atomic context, so it must not sleep. + +Make the operation synchronous instead, which removes both the IV race and +any writeback race. This is equivalent to the upstream resolution, commit +fcc77d33a34c ("net: Remove support for AIO on sockets"), which removed the +AIO socket path across net/ entirely and so produces the same end state for +this file. This patch deviates from that commit deliberately: rather than +removing AIO socket support tree-wide, which would be far too invasive for +stable, it removes only the AIO branch in crypto/algif_skcipher.c. +io_submit() now completes synchronously; AF_ALG async is rarely used in +practice. + +The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, +and is left alone to keep the fix minimal. + +Tested on 6.6.y: attacker IV injection dropped from 2296/200000 to 0/200000 +after the change; MSG_MORE chunked CTR output bit-identical to single-shot. + +Reported-by: Muhammet Kaan KILINÇ +Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") +Cc: +Signed-off-by: Muhammet Kaan KILINÇ +Signed-off-by: Sasha Levin +--- + crypto/algif_skcipher.c | 49 +++++++++++++++-------------------------- + 1 file changed, 18 insertions(+), 31 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index e31b1da58dba41..b12df4544d0bbb 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -107,37 +107,24 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + skcipher_request_set_crypt(&areq->cra_u.skcipher_req, areq->tsgl, + areq->first_rsgl.sgl.sgt.sgl, len, ctx->iv); + +- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { +- /* AIO operation */ +- sock_hold(sk); +- areq->iocb = msg->msg_iocb; +- +- /* Remember output size that will be generated. */ +- areq->outlen = len; +- +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP, +- af_alg_async_cb, areq); +- err = ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); +- +- /* AIO operation in progress */ +- if (err == -EINPROGRESS) +- return -EIOCBQUEUED; +- +- sock_put(sk); +- } else { +- /* Synchronous operation */ +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- CRYPTO_TFM_REQ_MAY_SLEEP | +- CRYPTO_TFM_REQ_MAY_BACKLOG, +- crypto_req_done, &ctx->wait); +- err = crypto_wait_req(ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), +- &ctx->wait); +- } ++ /* ++ * Force synchronous processing. The async (AIO) path passed the ++ * socket-wide ctx->iv into the request, which the worker ++ * dereferenced after the socket lock was dropped, letting a ++ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline ++ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove ++ * support for AIO on sockets"); these stable trees lack the ++ * per-request ctx->state used by newer kernels, so the minimal safe ++ * fix is to always complete synchronously. ++ */ ++ skcipher_request_set_callback(&areq->cra_u.skcipher_req, ++ CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &ctx->wait); ++ err = crypto_wait_req(ctx->enc ? ++ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : ++ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), ++ &ctx->wait); + + + free: +-- +2.53.0 + diff --git a/staging-6.6/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch b/staging-6.6/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch new file mode 100644 index 0000000000..bc95c61548 --- /dev/null +++ b/staging-6.6/kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch @@ -0,0 +1,94 @@ +From 5a48125885d2b2ae9bd5215017b9cad010dd2e38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 14:50:36 +0100 +Subject: KVM: arm64: Bound used_lrs when flushing the pKVM hyp vCPU + +From: Hyunwoo Kim + +commit 8cc8bbbfab14c22c5551d0dd19b208a44b141c76 upstream. + +flush_hyp_vcpu() copies the host vGIC state into the hyp's private vCPU +on every run. The vGIC list register save and restore use used_lrs as +their loop bound and expect it to stay within the number of implemented +list registers. While this is generally the case, flush_hyp_vcpu() +copies vgic_v3 verbatim and does not enforce this, so a value provided +by the host is used at EL2 to index vgic_lr[] and access ICH_LR_EL2 +(host -> EL2). + +Fix by clamping used_lrs to the number of implemented list registers +after the copy, as the trusted path already does in +vgic_flush_lr_state(). The number of implemented list registers is +constant after init, so it is replicated once from +kvm_vgic_global_state.nr_lr into hyp_gicv3_nr_lr rather than read on +every entry. + +Cc: stable@vger.kernel.org +Fixes: be66e67f1750 ("KVM: arm64: Use the pKVM hyp vCPU structure in handle___kvm_vcpu_run()") +Signed-off-by: Hyunwoo Kim +Reviewed-by: Fuad Tabba +Tested-by: Fuad Tabba +Link: https://patch.msgid.link/20260606175614.83273-3-imv4bel@gmail.com +Signed-off-by: Marc Zyngier +[ tabba: adjust context in flush_hyp_vcpu() and kvm_hyp.h ] +Signed-off-by: Fuad Tabba +Signed-off-by: Sasha Levin +--- + arch/arm64/include/asm/kvm_hyp.h | 1 + + arch/arm64/kvm/arm.c | 2 ++ + arch/arm64/kvm/hyp/nvhe/hyp-main.c | 9 +++++++++ + 3 files changed, 12 insertions(+) + +diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h +index 51cd106cd840a0..1b209efac97287 100644 +--- a/arch/arm64/include/asm/kvm_hyp.h ++++ b/arch/arm64/include/asm/kvm_hyp.h +@@ -146,5 +146,6 @@ extern u64 kvm_nvhe_sym(id_aa64smfr0_el1_sys_val); + extern unsigned long kvm_nvhe_sym(__icache_flags); + extern unsigned int kvm_nvhe_sym(kvm_arm_vmid_bits); + extern unsigned int kvm_nvhe_sym(kvm_host_sve_max_vl); ++extern unsigned int kvm_nvhe_sym(hyp_gicv3_nr_lr); + + #endif /* __ARM64_KVM_HYP_H__ */ +diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c +index 3ae529e967c7fb..e49ead6d005cc4 100644 +--- a/arch/arm64/kvm/arm.c ++++ b/arch/arm64/kvm/arm.c +@@ -2026,6 +2026,8 @@ static int __init init_subsystems(void) + switch (err) { + case 0: + vgic_present = true; ++ if (static_branch_unlikely(&kvm_vgic_global_state.gicv3_cpuif)) ++ kvm_nvhe_sym(hyp_gicv3_nr_lr) = kvm_vgic_global_state.nr_lr; + break; + case -ENODEV: + case -ENXIO: +diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +index 350d1775a5ce88..aa6c486667e706 100644 +--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c ++++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +@@ -22,6 +22,9 @@ + + DEFINE_PER_CPU(struct kvm_nvhe_init_params, kvm_init_params); + ++/* Number of implemented GICv3 LRs. Used by flush_hyp_vcpu(). */ ++unsigned int hyp_gicv3_nr_lr; ++ + void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt); + + static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) +@@ -46,6 +49,12 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) + hyp_vcpu->vcpu.arch.vsesr_el2 = host_vcpu->arch.vsesr_el2; + + hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3 = host_vcpu->arch.vgic_cpu.vgic_v3; ++ ++ /* Bound used_lrs by the number of implemented list registers. */ ++ hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs = ++ min_t(unsigned int, ++ hyp_vcpu->vcpu.arch.vgic_cpu.vgic_v3.used_lrs, ++ hyp_gicv3_nr_lr); + } + + static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) +-- +2.53.0 + diff --git a/staging-6.6/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch b/staging-6.6/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch new file mode 100644 index 0000000000..c012d64266 --- /dev/null +++ b/staging-6.6/kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch @@ -0,0 +1,50 @@ +From e4aaffe40dfd4714b0ee66ba21637dbffe8dc126 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 14:50:12 +0100 +Subject: KVM: arm64: Clear __hyp_running_vcpu when flushing the pKVM hyp vCPU + +From: Hyunwoo Kim + +commit e8042f6e1d7befb2fb6b10a75918642bcd0acf9a upstream. + +flush_hyp_vcpu() copies the host vCPU context into the hyp's private +vCPU on every run. ctxt_to_vcpu() expects a guest context to have a +NULL __hyp_running_vcpu, which is only ever set on the host context, so +that it resolves the vCPU via container_of(). While this is generally +the case, flush_hyp_vcpu() copies the context verbatim and does not +enforce this, so a value provided by the host is dereferenced at EL2 +(host -> EL2). + +Fix by clearing __hyp_running_vcpu after the copy. + +Cc: stable@vger.kernel.org +Fixes: be66e67f1750 ("KVM: arm64: Use the pKVM hyp vCPU structure in handle___kvm_vcpu_run()") +Signed-off-by: Hyunwoo Kim +Reviewed-by: Fuad Tabba +Tested-by: Fuad Tabba +Link: https://patch.msgid.link/20260606175614.83273-2-imv4bel@gmail.com +Signed-off-by: Marc Zyngier +[ tabba: adjust flush_hyp_vcpu() context ] +Signed-off-by: Fuad Tabba +Signed-off-by: Sasha Levin +--- + arch/arm64/kvm/hyp/nvhe/hyp-main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +index aa6c486667e706..ac0d5a0de01496 100644 +--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c ++++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c +@@ -33,6 +33,9 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu) + + hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt; + ++ /* __hyp_running_vcpu must be NULL in a guest context. */ ++ hyp_vcpu->vcpu.arch.ctxt.__hyp_running_vcpu = NULL; ++ + hyp_vcpu->vcpu.arch.sve_state = kern_hyp_va(host_vcpu->arch.sve_state); + hyp_vcpu->vcpu.arch.sve_max_vl = host_vcpu->arch.sve_max_vl; + +-- +2.53.0 + diff --git a/staging-6.6/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch b/staging-6.6/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch new file mode 100644 index 0000000000..ee70452b53 --- /dev/null +++ b/staging-6.6/sched-fair-only-update-stats-for-allowed-cpus-when-l.patch @@ -0,0 +1,50 @@ +From 7a1916724391731d0bc6d2555dfdfe111c8fb299 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Oct 2025 06:43:22 +0000 +Subject: sched/fair: Only update stats for allowed CPUs when looking for dst + group + +From: Adam Li + +[ Upstream commit 82d6e01a0699800efd8b048eb584c907ccb47b7a ] + +Load imbalance is observed when the workload frequently forks new threads. +Due to CPU affinity, the workload can run on CPU 0-7 in the first +group, and only on CPU 8-11 in the second group. CPU 12-15 are always idle. + +{ 0 1 2 3 4 5 6 7 } {8 9 10 11 12 13 14 15} + * * * * * * * * * * * * + +When looking for dst group for newly forked threads, in many times +update_sg_wakeup_stats() reports the second group has more idle CPUs +than the first group. The scheduler thinks the second group is less +busy. Then it selects least busy CPUs among CPU 8-11. Therefore CPU 8-11 +can be crowded with newly forked threads, at the same time CPU 0-7 +can be idle. + +A task may not use all the CPUs in a schedule group due to CPU affinity. +Only update schedule group statistics for allowed CPUs. + +Signed-off-by: Adam Li +Signed-off-by: Peter Zijlstra (Intel) +Signed-off-by: Sasha Levin +--- + kernel/sched/fair.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c +index cdf49a04fd5820..2fc9fe94d3f1f4 100644 +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -10266,7 +10266,7 @@ static inline void update_sg_wakeup_stats(struct sched_domain *sd, + if (sd->flags & SD_ASYM_CPUCAPACITY) + sgs->group_misfit_task_load = 1; + +- for_each_cpu(i, sched_group_span(group)) { ++ for_each_cpu_and(i, sched_group_span(group), p->cpus_ptr) { + struct rq *rq = cpu_rq(i); + unsigned int local; + +-- +2.53.0 + diff --git a/staging-6.6/series b/staging-6.6/series new file mode 100644 index 0000000000..76fbd3fd31 --- /dev/null +++ b/staging-6.6/series @@ -0,0 +1,6 @@ +smb-server-do-not-require-delete-access-for-non-repl.patch +block-skip-sync_blockdev-on-surprise-removal-in-bdev.patch +sched-fair-only-update-stats-for-allowed-cpus-when-l.patch +crypto-algif_skcipher-force-synchronous-processing-o.patch +kvm-arm64-bound-used_lrs-when-flushing-the-pkvm-hyp-.patch +kvm-arm64-clear-__hyp_running_vcpu-when-flushing-the.patch diff --git a/staging-6.6/smb-server-do-not-require-delete-access-for-non-repl.patch b/staging-6.6/smb-server-do-not-require-delete-access-for-non-repl.patch new file mode 100644 index 0000000000..05e21925c6 --- /dev/null +++ b/staging-6.6/smb-server-do-not-require-delete-access-for-non-repl.patch @@ -0,0 +1,61 @@ +From e445390cf6374aedb297c9ef97a3fc26a4f1b1c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 28 Jun 2026 07:42:43 +0000 +Subject: smb/server: do not require delete access for non-replacing links + +From: ChenXiaoSong + +[ Upstream commit 851ed9e09639e0daf79a506ce26097b296ed5518 ] + +Reproducer: + + 1. server: systemctl start ksmbd + 2. client: mount -t cifs //${server_ip}/export /mnt + 3. client: touch /mnt/file; ln /mnt/file /mnt/hardlink + 4. client err log: ln: failed to create hard link 'hardlink' => + 'file': Permission denied + 5. server err log: ksmbd: no right to delete : 0x80 + +Fixes: 13f3942f2bf4 ("ksmbd: add per-handle permission check to FILE_LINK_INFORMATION") +Cc: stable@vger.kernel.org +Reported-by: Steve French +Signed-off-by: ChenXiaoSong +Acked-by: Namjae Jeon +Signed-off-by: Steve French +Signed-off-by: Sasha Levin +--- + fs/smb/server/smb2pdu.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c +index 968b1b5d858fb7..fafbb4275bba4d 100644 +--- a/fs/smb/server/smb2pdu.c ++++ b/fs/smb/server/smb2pdu.c +@@ -6504,16 +6504,18 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp, + } + case FILE_LINK_INFORMATION: + { +- if (!(fp->daccess & FILE_DELETE_LE)) { +- pr_err("no right to delete : 0x%x\n", fp->daccess); +- return -EACCES; +- } ++ struct smb2_file_link_info *file_info; + + if (buf_len < sizeof(struct smb2_file_link_info)) + return -EINVAL; + +- return smb2_create_link(work, work->tcon->share_conf, +- (struct smb2_file_link_info *)buffer, ++ file_info = (struct smb2_file_link_info *)buffer; ++ if (file_info->ReplaceIfExists && !(fp->daccess & FILE_DELETE_LE)) { ++ pr_err("no right to delete : 0x%x\n", fp->daccess); ++ return -EACCES; ++ } ++ ++ return smb2_create_link(work, work->tcon->share_conf, file_info, + buf_len, fp->filp, + work->conn->local_nls); + } +-- +2.53.0 + diff --git a/staging-7.1/crypto-algif_skcipher-force-synchronous-processing.patch b/staging-7.1/crypto-algif_skcipher-force-synchronous-processing.patch new file mode 100644 index 0000000000..c84cc1454d --- /dev/null +++ b/staging-7.1/crypto-algif_skcipher-force-synchronous-processing.patch @@ -0,0 +1,159 @@ +From 60397482ee75cb912cee1d6ce597921804ab6d57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Jul 2026 02:58:36 +0000 +Subject: crypto: algif_skcipher - force synchronous processing +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Muhammet Kaan KILINÇ + +The AIO/async path in skcipher_recvmsg() passes the socket-wide ctx->iv +directly into the skcipher request. After io_submit() the socket lock is +dropped and the request is processed asynchronously by a worker (e.g. +cryptd), which dereferences ctx->iv only later. + +A concurrent sendmsg(ALG_SET_IV) on the same socket can overwrite ctx->iv +inside this window, so the in-flight request runs under an +attacker-controlled IV. For CTR and other stream modes this causes +IV/keystream reuse and allows an unprivileged user to recover the +plaintext of a concurrent operation. + +Snapshotting ctx->iv into per-request storage for the async path is not +sufficient here. For ciphers with statesize == 0 - which includes cbc +and ctr - skcipher_prepare_alg() installs skcipher_noimport()/ +skcipher_noexport(), so ctx->state carries nothing and the MSG_MORE +inter-chunk IV chaining is carried solely by the in-place req->iv +writeback. A snapshot redirects that writeback into per-request memory +that af_alg_free_resources() releases on completion, so AIO + MSG_MORE +with cbc/ctr would silently produce wrong output. Writing the IV back +from the completion callback instead is not possible either: that would +require lock_sock() there, but the callback can run in softirq/atomic +context, so it must not sleep. + +Make the operation synchronous instead. ctx->iv is then only ever +dereferenced under the socket lock held by recvmsg(), which removes the +race, and the req->iv writeback lands in ctx->iv as before, which keeps +MSG_MORE chaining intact for statesize == 0 ciphers. The ctx->state +import/export path is unchanged for ciphers that do have state. + +This is equivalent to the upstream resolution: commit fcc77d33a34c +("net: Remove support for AIO on sockets") removed the AIO socket path +across net/ entirely, producing the same end state for this file - +algif_skcipher never processes an AIO request asynchronously. After this +patch, _skcipher_recvmsg() matches mainline's crypto/algif_skcipher.c as +it stands today, including the same now-dead -EIOCBQUEUED check. This +patch deviates from that commit deliberately: rather than removing AIO +socket support tree-wide, which would be far too invasive for stable, it +removes only the AIO branch in crypto/algif_skcipher.c. io_submit() now +completes synchronously, which is valid for the AIO interface; AF_ALG +async is rarely used in practice. + +The -EIOCBQUEUED check in skcipher_recvmsg() is now dead but harmless, +and is left alone to keep the fix minimal. + +Fixes: e870456d8e7c ("crypto: algif_skcipher - overhaul memory management") +Cc: +Reported-by: Muhammet Kaan KILINÇ +Signed-off-by: Muhammet Kaan KILINÇ +Signed-off-by: Sasha Levin +--- + crypto/algif_skcipher.c | 75 +++++++++++++---------------------------- + 1 file changed, 24 insertions(+), 51 deletions(-) + +diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c +index ba0a17fd95aca2..35ebc3e0201b04 100644 +--- a/crypto/algif_skcipher.c ++++ b/crypto/algif_skcipher.c +@@ -79,20 +79,6 @@ static int algif_skcipher_export(struct sock *sk, struct skcipher_request *req) + return err; + } + +-static void algif_skcipher_done(void *data, int err) +-{ +- struct af_alg_async_req *areq = data; +- struct sock *sk = areq->sk; +- +- if (err) +- goto out; +- +- err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); +- +-out: +- af_alg_async_cb(data, err); +-} +- + static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + size_t ignored, int flags) + { +@@ -171,43 +157,30 @@ static int _skcipher_recvmsg(struct socket *sock, struct msghdr *msg, + cflags |= CRYPTO_SKCIPHER_REQ_CONT; + } + +- if (msg->msg_iocb && !is_sync_kiocb(msg->msg_iocb)) { +- /* AIO operation */ +- sock_hold(sk); +- areq->iocb = msg->msg_iocb; +- +- /* Remember output size that will be generated. */ +- areq->outlen = len; +- +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- cflags | +- CRYPTO_TFM_REQ_MAY_SLEEP, +- algif_skcipher_done, areq); +- err = ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req); +- +- /* AIO operation in progress */ +- if (err == -EINPROGRESS) +- return -EIOCBQUEUED; +- +- sock_put(sk); +- } else { +- /* Synchronous operation */ +- skcipher_request_set_callback(&areq->cra_u.skcipher_req, +- cflags | +- CRYPTO_TFM_REQ_MAY_SLEEP | +- CRYPTO_TFM_REQ_MAY_BACKLOG, +- crypto_req_done, &ctx->wait); +- err = crypto_wait_req(ctx->enc ? +- crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : +- crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), +- &ctx->wait); +- +- if (!err) +- err = algif_skcipher_export( +- sk, &areq->cra_u.skcipher_req); +- } ++ /* ++ * Force synchronous processing. The async (AIO) path passed the ++ * socket-wide ctx->iv into the request, which the worker ++ * dereferenced after the socket lock had been dropped, letting a ++ * concurrent sendmsg(ALG_SET_IV) inject an attacker IV. Mainline ++ * removed the AIO socket path in commit fcc77d33a34c ("net: Remove ++ * support for AIO on sockets"); the minimal stable fix is to always ++ * complete synchronously, so ctx->iv is only ever dereferenced under ++ * the socket lock. This also keeps the IV chaining intact: for ++ * ciphers with statesize == 0 (e.g. ctr, cbc) the chained IV is ++ * carried by the req->iv writeback into ctx->iv, which is only ++ * consistent on the synchronous path. ++ */ ++ skcipher_request_set_callback(&areq->cra_u.skcipher_req, ++ cflags | ++ CRYPTO_TFM_REQ_MAY_SLEEP | ++ CRYPTO_TFM_REQ_MAY_BACKLOG, ++ crypto_req_done, &ctx->wait); ++ err = crypto_wait_req(ctx->enc ? ++ crypto_skcipher_encrypt(&areq->cra_u.skcipher_req) : ++ crypto_skcipher_decrypt(&areq->cra_u.skcipher_req), ++ &ctx->wait); ++ if (!err) ++ err = algif_skcipher_export(sk, &areq->cra_u.skcipher_req); + + free: + af_alg_free_resources(areq); +-- +2.53.0 + diff --git a/staging-7.1/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch b/staging-7.1/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch new file mode 100644 index 0000000000..829cda45d2 --- /dev/null +++ b/staging-7.1/iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch @@ -0,0 +1,65 @@ +From bb96b190abfa0604a98e79205066f5d9692ed1d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Jun 2026 14:03:07 +0800 +Subject: iommu/vt-d: Clear Present bit before tearing down scalable-mode + context entry + +From: Michael Bommarito + +[ Upstream commit f46452c3df7a8d8a5addc0926e76ef19ea7da0a0 ] + +device_pasid_table_teardown() zeroes the 128-bit scalable-mode context +entry with context_clear_entry() while the Present bit is still set. This +creates a window where the hardware can fetch a torn entry, with some +fields already zeroed while Present is still set, leading to unpredictable +behavior or spurious faults. The context-cache invalidation is issued only +after the entry has been zeroed, and intel_pasid_free_table() then frees +the PASID directory pages, so the IOMMU can keep walking a stale Present=1 +entry that points at freed memory. + +While x86 provides strong write ordering, the compiler may reorder the two +64-bit writes to the entry, and the hardware fetch is not guaranteed to be +atomic with respect to multiple CPU writes. + +Commit c1e4f1dccbe9d ("iommu/vt-d: Clear Present bit before tearing down +context entry") fixed this exact pattern in domain_context_clear_one() and +the copied-context path, but device_pasid_table_teardown() was not +converted. + +Align it with the "Guidance to Software for Invalidations" in the VT-d +spec, Section 6.5.3.3, using the same ownership handshake as the sibling +fix: clear only the Present bit, flush it to the IOMMU, perform the +context-cache invalidation, and only then zero the rest of the entry. + +Fixes: 81e921fd32161 ("iommu/vt-d: Fix NULL domain on device release") +Signed-off-by: Michael Bommarito +Assisted-by: Claude:claude-opus-4-7 +Link: https://lore.kernel.org/r/20260528025557.3209367-1-michael.bommarito@gmail.com +Signed-off-by: Lu Baolu +Signed-off-by: Joerg Roedel +Signed-off-by: Sasha Levin +--- + drivers/iommu/intel/pasid.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c +index 89541b74ab8ca3..40910dc7363b13 100644 +--- a/drivers/iommu/intel/pasid.c ++++ b/drivers/iommu/intel/pasid.c +@@ -748,10 +748,12 @@ static void device_pasid_table_teardown(struct device *dev, u8 bus, u8 devfn) + } + + did = context_domain_id(context); +- context_clear_entry(context); ++ context_clear_present(context); + __iommu_flush_cache(iommu, context, sizeof(*context)); + spin_unlock(&iommu->lock); + intel_context_flush_no_pasid(info, context, did); ++ context_clear_entry(context); ++ __iommu_flush_cache(iommu, context, sizeof(*context)); + } + + static int pci_pasid_table_teardown(struct pci_dev *pdev, u16 alias, void *data) +-- +2.53.0 + diff --git a/staging-7.1/series b/staging-7.1/series new file mode 100644 index 0000000000..60b2d456c8 --- /dev/null +++ b/staging-7.1/series @@ -0,0 +1,2 @@ +crypto-algif_skcipher-force-synchronous-processing.patch +iommu-vt-d-clear-present-bit-before-tearing-down-sca.patch