]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for all trees
authorSasha Levin <sashal@kernel.org>
Fri, 10 Jul 2026 21:02:24 +0000 (17:02 -0400)
committerSasha Levin <sashal@kernel.org>
Fri, 10 Jul 2026 21:02:24 +0000 (17:02 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
41 files changed:
queue-5.15/locking-rtmutex-skip-remove_waiter-when-waiter-is-no.patch [new file with mode: 0644]
queue-5.15/perf-core-detach-event-groups-during-remove_on_exec.patch [new file with mode: 0644]
queue-5.15/rtmutex-use-waiter-task-instead-of-current-in-remove.patch [new file with mode: 0644]
queue-5.15/series
queue-6.1/perf-core-detach-event-groups-during-remove_on_exec.patch [new file with mode: 0644]
queue-6.1/series
queue-6.1/virtio_net-support-dynamic-rss-indirection-table-siz.patch [new file with mode: 0644]
queue-6.12/perf-core-detach-event-groups-during-remove_on_exec.patch [new file with mode: 0644]
queue-6.12/rust-kasan-kasan-rust-requires-clang.patch [new file with mode: 0644]
queue-6.12/series
queue-6.18/fscrypt-fix-key-setup-in-edge-case-with-multiple-dat.patch [new file with mode: 0644]
queue-6.18/fscrypt-replace-mk_users-keyring-with-simple-list.patch [new file with mode: 0644]
queue-6.18/perf-core-detach-event-groups-during-remove_on_exec.patch [new file with mode: 0644]
queue-6.18/rust-kasan-kasan-rust-requires-clang.patch [new file with mode: 0644]
queue-6.18/series
queue-6.6/arm64-fix-early-handling-of-feat_e2h0-not-being-impl.patch [new file with mode: 0644]
queue-6.6/arm64-revamp-hcr_el2.e2h-res1-detection.patch [new file with mode: 0644]
queue-6.6/arm64-sysreg-add-layout-for-id_aa64mmfr4_el1.patch [new file with mode: 0644]
queue-6.6/arm64-sysreg-correct-sign-definitions-for-eiesb-and-.patch [new file with mode: 0644]
queue-6.6/arm64-treat-hcr_el2.e2h-as-res1-when-id_aa64mmfr4_el.patch [new file with mode: 0644]
queue-6.6/crypto-talitos-fix-sec1-32k-ahash-request-limitation.patch [new file with mode: 0644]
queue-6.6/crypto-talitos-rename-first-last-to-first_desc-last_.patch [new file with mode: 0644]
queue-6.6/crypto-talitos-stop-using-crypto_ahash-init.patch [new file with mode: 0644]
queue-6.6/kvm-arm64-initialize-hcr_el2.e2h-early.patch [new file with mode: 0644]
queue-6.6/kvm-arm64-initialize-sctlr_el1-in-__kvm_hyp_init_cpu.patch [new file with mode: 0644]
queue-6.6/loongarch-add-pio-for-early-access-before-acpi-pci-r.patch [new file with mode: 0644]
queue-6.6/net-drop-the-lock-in-skb_may_tx_timestamp.patch [new file with mode: 0644]
queue-6.6/perf-core-detach-event-groups-during-remove_on_exec.patch [new file with mode: 0644]
queue-6.6/revert-crypto-talitos-fix-sec1-32k-ahash-request-lim.patch [new file with mode: 0644]
queue-6.6/revert-crypto-talitos-rename-first-last-to-first_des.patch [new file with mode: 0644]
queue-6.6/revert-loongarch-add-pio-for-early-access-before-acp.patch [new file with mode: 0644]
queue-6.6/series
queue-6.6/virtio_net-support-dynamic-rss-indirection-table-siz.patch [new file with mode: 0644]
queue-7.1/bpf-prefer-dirty-packs-for-ebpf-allocations.patch [new file with mode: 0644]
queue-7.1/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch [new file with mode: 0644]
queue-7.1/bpf-restrict-jit-predictor-flush-to-cbpf.patch [new file with mode: 0644]
queue-7.1/bpf-skip-redundant-ibpb-in-pack-allocator.patch [new file with mode: 0644]
queue-7.1/bpf-support-for-hardening-against-jit-spraying.patch [new file with mode: 0644]
queue-7.1/perf-core-detach-event-groups-during-remove_on_exec.patch [new file with mode: 0644]
queue-7.1/series
queue-7.1/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch [new file with mode: 0644]

diff --git a/queue-5.15/locking-rtmutex-skip-remove_waiter-when-waiter-is-no.patch b/queue-5.15/locking-rtmutex-skip-remove_waiter-when-waiter-is-no.patch
new file mode 100644 (file)
index 0000000..8bee227
--- /dev/null
@@ -0,0 +1,72 @@
+From a84c8d44d6c542c5843abe7b580475f0ea12e8f0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 10:59:49 -0400
+Subject: locking/rtmutex: Skip remove_waiter() when waiter is not enqueued
+
+From: Davidlohr Bueso <dave@stgolabs.net>
+
+[ Upstream commit 40a25d59e85b3c8709ac2424d44f65610467871e ]
+
+syzbot triggered the following splat in remove_waiter() via
+FUTEX_CMP_REQUEUE_PI:
+
+  KASAN: null-ptr-deref in range [0x0000000000000a88-0x0000000000000a8f]
+   class_raw_spinlock_constructor
+   remove_waiter+0x159/0x1200 kernel/locking/rtmutex.c:1561
+   rt_mutex_start_proxy_lock+0x103/0x120
+   futex_requeue+0x10e4/0x20d0
+   __x64_sys_futex+0x34f/0x4d0
+
+task_blocks_on_rt_mutex() does not arm the waiter upon deadlock detection,
+leaving waiter->task nil, where 3bfdc63936dd ("rtmutex: Use waiter::task instead
+of current in remove_waiter()") made this fatal.
+
+Furthermore, rt_mutex_start_proxy_lock() should not be calling into remove_waiter()
+upon a successfully grabbing the rtmutex. 1a1fb985f2e2 ("futex: Handle early deadlock
+return correctly"), moved the remove_waiter() out of __rt_mutex_start_proxy_lock()
+(where 'ret' was only ever 0 or < 0) into the wrapper. Tighten this check to
+account for try_to_take_rt_mutex().
+
+Fixes: 3bfdc63936dd ("rtmutex: Use waiter::task instead of current in remove_waiter()")
+Reported-by: syzbot+78147abe6c524f183ee9@syzkaller.appspotmail.com
+Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
+Signed-off-by: Thomas Gleixner <tglx@kernel.org>
+Cc: stable@vger.kernel.org
+Closes: https://lore.kernel.org/all/69f114ac.050a0220.ac8b.0003.GAE@google.com/
+Link: https://patch.msgid.link/20260507112913.1019537-1-dave@stgolabs.net
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/locking/rtmutex.c     | 3 +++
+ kernel/locking/rtmutex_api.c | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
+index f79c9286c7c0c1..2118f8928eb7cb 100644
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -1513,6 +1513,9 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
+       lockdep_assert_held(&lock->wait_lock);
++      if (!waiter_task) /* never enqueued */
++              return;
++
+       raw_spin_lock(&waiter_task->pi_lock);
+       rt_mutex_dequeue(lock, waiter);
+       waiter_task->pi_blocked_on = NULL;
+diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
+index 56d1938cb52a1f..c4e191340c59b3 100644
+--- a/kernel/locking/rtmutex_api.c
++++ b/kernel/locking/rtmutex_api.c
+@@ -322,7 +322,7 @@ int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,
+       raw_spin_lock_irq(&lock->wait_lock);
+       ret = __rt_mutex_start_proxy_lock(lock, waiter, task);
+-      if (unlikely(ret))
++      if (unlikely(ret < 0))
+               remove_waiter(lock, waiter);
+       raw_spin_unlock_irq(&lock->wait_lock);
+-- 
+2.53.0
+
diff --git a/queue-5.15/perf-core-detach-event-groups-during-remove_on_exec.patch b/queue-5.15/perf-core-detach-event-groups-during-remove_on_exec.patch
new file mode 100644 (file)
index 0000000..b4668fb
--- /dev/null
@@ -0,0 +1,98 @@
+From 3badcf0525a192bdf080670715b14358a443ff6b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:31:45 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context without DETACH_GROUP.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit behavior, while ensuring
+surviving siblings are ungrouped before the removed event leaves the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 156221bd56615c..9b01cfeb3a0663 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4422,7 +4422,8 @@ static void perf_event_enable_on_exec(int ctxn)
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+-                                struct perf_event_context *ctx);
++                                struct perf_event_context *ctx,
++                                unsigned long detach_flags);
+ /*
+  * Removes all events from the current task that have been marked
+@@ -4454,7 +4455,7 @@ static void perf_event_remove_on_exec(int ctxn)
+               modified = true;
+-              perf_event_exit_event(event, ctx);
++              perf_event_exit_event(event, ctx, DETACH_GROUP);
+       }
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13024,10 +13025,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++                    struct perf_event_context *ctx,
++                    unsigned long detach_flags)
+ {
+       struct perf_event *parent_event = event->parent;
+-      unsigned long detach_flags = 0;
+       if (parent_event) {
+               /*
+@@ -13042,7 +13044,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+                * Do destroy all inherited groups, we don't care about those
+                * and being thorough is better.
+                */
+-              detach_flags = DETACH_GROUP | DETACH_CHILD;
++              detach_flags |= DETACH_GROUP | DETACH_CHILD;
+               mutex_lock(&parent_event->child_mutex);
+       }
+@@ -13127,7 +13129,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
+       perf_event_task(child, child_ctx, 0);
+       list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+-              perf_event_exit_event(child_event, child_ctx);
++              perf_event_exit_event(child_event, child_ctx, 0);
+       mutex_unlock(&child_ctx->mutex);
+-- 
+2.53.0
+
diff --git a/queue-5.15/rtmutex-use-waiter-task-instead-of-current-in-remove.patch b/queue-5.15/rtmutex-use-waiter-task-instead-of-current-in-remove.patch
new file mode 100644 (file)
index 0000000..aeac8a8
--- /dev/null
@@ -0,0 +1,87 @@
+From e8757c81615774dbe75e0859f9525dd733240ebd Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 10:59:48 -0400
+Subject: rtmutex: Use waiter::task instead of current in remove_waiter()
+
+From: Keenan Dong <keenanat2000@gmail.com>
+
+[ Upstream commit 3bfdc63936dd4773109b7b8c280c0f3b5ae7d349 ]
+
+remove_waiter() is used by the slowlock paths, but it is also used for
+proxy-lock rollback in rt_mutex_start_proxy_lock() when invoked from
+futex_requeue().
+
+In the latter case waiter::task is not current, but remove_waiter()
+operates on current for the dequeue operation. That results in several
+problems:
+
+  1) the rbtree dequeue happens without waiter::task::pi_lock being held
+
+  2) the waiter task's pi_blocked_on state is not cleared, which leaves a
+     dangling pointer primed for UAF around.
+
+  3) rt_mutex_adjust_prio_chain() operates on the wrong top priority waiter
+     task
+
+Use waiter::task instead of current in all related operations in
+remove_waiter() to cure those problems.
+
+[ tglx: Fixup rt_mutex_adjust_prio_chain(), add a comment and amend the
+       changelog ]
+
+Fixes: 8161239a8bcc ("rtmutex: Simplify PI algorithm and make highest prio task get lock")
+Reported-by: Yuan Tan <yuantan098@gmail.com>
+Reported-by: Yifan Wu <yifanwucs@gmail.com>
+Reported-by: Juefei Pu <tomapufckgml@gmail.com>
+Reported-by: Xin Liu <bird@lzu.edu.cn>
+Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Thomas Gleixner <tglx@kernel.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/locking/rtmutex.c | 11 +++++++----
+ 1 file changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
+index cf72ef77bfe75a..f79c9286c7c0c1 100644
+--- a/kernel/locking/rtmutex.c
++++ b/kernel/locking/rtmutex.c
+@@ -1500,20 +1500,23 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock,
+  *
+  * Must be called with lock->wait_lock held and interrupts disabled. It must
+  * have just failed to try_to_take_rt_mutex().
++ *
++ * When invoked from rt_mutex_start_proxy_lock() waiter::task != current !
+  */
+ static void __sched remove_waiter(struct rt_mutex_base *lock,
+                                 struct rt_mutex_waiter *waiter)
+ {
+       bool is_top_waiter = (waiter == rt_mutex_top_waiter(lock));
+       struct task_struct *owner = rt_mutex_owner(lock);
++      struct task_struct *waiter_task = waiter->task;
+       struct rt_mutex_base *next_lock;
+       lockdep_assert_held(&lock->wait_lock);
+-      raw_spin_lock(&current->pi_lock);
++      raw_spin_lock(&waiter_task->pi_lock);
+       rt_mutex_dequeue(lock, waiter);
+-      current->pi_blocked_on = NULL;
+-      raw_spin_unlock(&current->pi_lock);
++      waiter_task->pi_blocked_on = NULL;
++      raw_spin_unlock(&waiter_task->pi_lock);
+       /*
+        * Only update priority if the waiter was the highest priority
+@@ -1549,7 +1552,7 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
+       raw_spin_unlock_irq(&lock->wait_lock);
+       rt_mutex_adjust_prio_chain(owner, RT_MUTEX_MIN_CHAINWALK, lock,
+-                                 next_lock, NULL, current);
++                                 next_lock, NULL, waiter_task);
+       raw_spin_lock_irq(&lock->wait_lock);
+ }
+-- 
+2.53.0
+
index 13e281e0228ded12b3b983e535a05813decc299d..e5b6c6aac7d64dd21f580b2c0d9dbb99fbc79a46 100644 (file)
@@ -40,3 +40,6 @@ i2c-core-fix-adapter-registration-race.patch
 fbdev-fbcon-fix-out-of-bounds-read-in-err_out-of-fbcon_do_set_font.patch
 nfsv4-flexfiles-reject-zero-filehandle-version-count.patch
 ksmbd-fix-out-of-bounds-read-in-smb_check_perm_dacl.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+rtmutex-use-waiter-task-instead-of-current-in-remove.patch
+locking-rtmutex-skip-remove_waiter-when-waiter-is-no.patch
diff --git a/queue-6.1/perf-core-detach-event-groups-during-remove_on_exec.patch b/queue-6.1/perf-core-detach-event-groups-during-remove_on_exec.patch
new file mode 100644 (file)
index 0000000..0ef1f5d
--- /dev/null
@@ -0,0 +1,99 @@
+From f6f4951c2cf47b7dd924f6539926d68a1b845398 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:30:55 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 146b37e97832a9..1478bad56e40a1 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4334,7 +4334,8 @@ static void perf_event_enable_on_exec(int ctxn)
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+-                                struct perf_event_context *ctx);
++                                struct perf_event_context *ctx,
++                                unsigned long detach_flags);
+ /*
+  * Removes all events from the current task that have been marked
+@@ -4365,7 +4366,7 @@ static void perf_event_remove_on_exec(int ctxn)
+               modified = true;
+-              perf_event_exit_event(event, ctx);
++              perf_event_exit_event(event, ctx, DETACH_GROUP);
+       }
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13055,10 +13056,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++                    struct perf_event_context *ctx,
++                    unsigned long detach_flags)
+ {
+       struct perf_event *parent_event = event->parent;
+-      unsigned long detach_flags = 0;
+       if (parent_event) {
+               /*
+@@ -13073,7 +13075,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+                * Do destroy all inherited groups, we don't care about those
+                * and being thorough is better.
+                */
+-              detach_flags = DETACH_GROUP | DETACH_CHILD;
++              detach_flags |= DETACH_GROUP | DETACH_CHILD;
+               mutex_lock(&parent_event->child_mutex);
+       }
+@@ -13158,7 +13160,7 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
+       perf_event_task(child, child_ctx, 0);
+       list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+-              perf_event_exit_event(child_event, child_ctx);
++              perf_event_exit_event(child_event, child_ctx, 0);
+       mutex_unlock(&child_ctx->mutex);
+-- 
+2.53.0
+
index b384cc251e0c1a1e25d83ccb5c1d67ee3f134556..42fbeb8e3309932f898840eb3cc95b04242f5ee1 100644 (file)
@@ -46,3 +46,5 @@ eventpoll-move-epi_fget-up.patch
 eventpoll-fix-ep_remove-struct-eventpoll-struct-file-uaf.patch
 acpi-cppc-suppress-ubsan-warning-caused-by-field-misuse.patch
 rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+virtio_net-support-dynamic-rss-indirection-table-siz.patch
diff --git a/queue-6.1/virtio_net-support-dynamic-rss-indirection-table-siz.patch b/queue-6.1/virtio_net-support-dynamic-rss-indirection-table-siz.patch
new file mode 100644 (file)
index 0000000..8e48ea2
--- /dev/null
@@ -0,0 +1,154 @@
+From fdae2106a7ec9598da34c7de2f1f528b5d28fbcf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 11:25:21 +0000
+Subject: virtio_net: Support dynamic rss indirection table size
+
+From: Philo Lu <lulie@linux.alibaba.com>
+
+commit 86a48a00efdf61197b6658e52c6140463eb313dc upstream.
+
+When reading/writing virtio_net_ctrl_rss, the indirection table size is
+obtained from vi->rss_indir_table_size, initialized during virtnet_probe().
+However, the indirection_table was statically sized as
+VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
+vi->rss_indir_table_size exceeds this limit.
+
+This patch implements dynamic allocation for the indirection table,
+allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
+and freed in virtnet_remove().
+
+In virtnet_commit_rss_command(), scatter-gather lists for RSS are
+initialized differently based on hash_report presence, so indirection_table
+is unused when !vi->has_rss. Therefore, allocation is unnecessary for
+hash_report-only scenarios.
+
+Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
+Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
+Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Acked-by: Joe Damato <jdamato@fastly.com>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ Hyokyung Kim: 6.1.y predates the refactor that moved the RSS config into
+  struct virtnet_info, so struct virtio_net_ctrl_rss is still embedded in
+  struct control_buf and reached through the heap-allocated vi->ctrl. Every
+  adaptation below follows from that single difference:
+  - the new allocation and all indirection_table accesses use vi->ctrl->rss
+    in place of upstream's vi->rss;
+  - because vi->ctrl is allocated in virtnet_alloc_queues() (via init_vqs())
+    and freed in virtnet_free_queues(), the table is allocated and freed there
+    too, not in virtnet_probe()/virtnet_remove(), so its lifetime tracks
+    vi->ctrl across the probe error-unwind and freeze/restore paths;
+  - since freeing the table now dereferences vi->ctrl, vi->ctrl is set to NULL
+    after each kfree so a re-entered virtnet_free_queues() cannot dereference
+    or free a stale pointer;
+  - the table is allocated with kcalloc() so it is zero-filled when
+    reallocated on the restore path (upstream never reallocates it). ]
+Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/virtio_net.c | 43 +++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 38 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
+index b62b7696313757..2fb00df795d4ab 100644
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -179,15 +179,16 @@ struct receive_queue {
+  * because table sizes may be differ according to the device configuration.
+  */
+ #define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
+-#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
+ struct virtio_net_ctrl_rss {
+       u32 hash_types;
+       u16 indirection_table_mask;
+       u16 unclassified_queue;
+-      u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
++      u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
+       u16 max_tx_vq;
+       u8 hash_key_length;
+       u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
++
++      u16 *indirection_table;
+ };
+ /* Control VQ buffers: protected by the rtnl lock */
+@@ -2488,6 +2489,25 @@ static int virtnet_set_ringparam(struct net_device *dev,
+       return 0;
+ }
++static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size)
++{
++      if (!indir_table_size) {
++              rss->indirection_table = NULL;
++              return 0;
++      }
++
++      rss->indirection_table = kcalloc(indir_table_size, sizeof(u16), GFP_KERNEL);
++      if (!rss->indirection_table)
++              return -ENOMEM;
++
++      return 0;
++}
++
++static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss)
++{
++      kfree(rss->indirection_table);
++}
++
+ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+ {
+       struct net_device *dev = vi->dev;
+@@ -2497,11 +2517,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+       /* prepare sgs */
+       sg_init_table(sgs, 4);
+-      sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
++      sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved);
+       sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
+-      sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
+-      sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++      if (vi->has_rss) {
++              sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
++              sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++      } else {
++              sg_set_buf(&sgs[1], &vi->ctrl->rss.hash_cfg_reserved, sizeof(uint16_t));
++      }
+       sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
+                       - offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
+@@ -3415,7 +3439,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+       kfree(vi->rq);
+       kfree(vi->sq);
++      if (vi->ctrl)
++              rss_indirection_table_free(&vi->ctrl->rss);
+       kfree(vi->ctrl);
++      vi->ctrl = NULL;
+ }
+ static void _free_receive_bufs(struct virtnet_info *vi)
+@@ -3610,6 +3637,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+               vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
+               if (!vi->ctrl)
+                       goto err_ctrl;
++              if ((vi->has_rss || vi->has_rss_hash_report) &&
++                  rss_indirection_table_alloc(&vi->ctrl->rss, vi->rss_indir_table_size))
++                      goto err_sq;
+       } else {
+               vi->ctrl = NULL;
+       }
+@@ -3642,7 +3672,10 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+ err_rq:
+       kfree(vi->sq);
+ err_sq:
++      if (vi->ctrl)
++              rss_indirection_table_free(&vi->ctrl->rss);
+       kfree(vi->ctrl);
++      vi->ctrl = NULL;
+ err_ctrl:
+       return -ENOMEM;
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.12/perf-core-detach-event-groups-during-remove_on_exec.patch b/queue-6.12/perf-core-detach-event-groups-during-remove_on_exec.patch
new file mode 100644 (file)
index 0000000..1fe7732
--- /dev/null
@@ -0,0 +1,99 @@
+From 57e54b3034f105c415058add64a0f5b462f83737 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:29:08 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 8fa3ee209a5be6..da77f856e1c83b 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4536,7 +4536,8 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+-                                struct perf_event_context *ctx);
++                                struct perf_event_context *ctx,
++                                unsigned long detach_flags);
+ /*
+  * Removes all events from the current task that have been marked
+@@ -4563,7 +4564,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+               modified = true;
+-              perf_event_exit_event(event, ctx);
++              perf_event_exit_event(event, ctx, DETACH_GROUP);
+       }
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13477,10 +13478,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++                    struct perf_event_context *ctx,
++                    unsigned long detach_flags)
+ {
+       struct perf_event *parent_event = event->parent;
+-      unsigned long detach_flags = 0;
+       if (parent_event) {
+               /*
+@@ -13495,7 +13497,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+                * Do destroy all inherited groups, we don't care about those
+                * and being thorough is better.
+                */
+-              detach_flags = DETACH_GROUP | DETACH_CHILD;
++              detach_flags |= DETACH_GROUP | DETACH_CHILD;
+               mutex_lock(&parent_event->child_mutex);
+       }
+@@ -13574,7 +13576,7 @@ static void perf_event_exit_task_context(struct task_struct *child)
+       perf_event_task(child, child_ctx, 0);
+       list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+-              perf_event_exit_event(child_event, child_ctx);
++              perf_event_exit_event(child_event, child_ctx, 0);
+       mutex_unlock(&child_ctx->mutex);
+-- 
+2.53.0
+
diff --git a/queue-6.12/rust-kasan-kasan-rust-requires-clang.patch b/queue-6.12/rust-kasan-kasan-rust-requires-clang.patch
new file mode 100644 (file)
index 0000000..b81855e
--- /dev/null
@@ -0,0 +1,40 @@
+From 3001d0c22e2f93bf90c6fe056e96630b6d5a10d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 20:03:59 +0200
+Subject: rust: kasan: KASAN+RUST requires clang
+
+From: Alice Ryhl <aliceryhl@google.com>
+
+[ Upstream commit 5b271543d0f08e9733d4732721e960e285f6448f ]
+
+Kernel KASAN involves passing various llvm/gcc specific arguments to
+the C and Rust compiler. Since these arguments differ between llvm and
+gcc, it's not safe to mix an llvm-based rustc with a gcc build when
+kasan is enabled.
+
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Reviewed-by: Gary Guo <gary@garyguo.net>
+Cc: stable@vger.kernel.org
+Fixes: e3117404b411 ("kbuild: rust: Enable KASAN support")
+Link: https://patch.msgid.link/20260408-kasan-rust-sw-tags-v3-1-e07964d14363@google.com
+Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ init/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index f4b91b1857bf86..53eba5cd88ff51 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -1974,6 +1974,7 @@ config RUST
+       depends on !CFI_CLANG || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
+       select CFI_ICALL_NORMALIZE_INTEGERS if CFI_CLANG
+       depends on !CALL_PADDING || RUSTC_VERSION >= 108100
++      depends on !KASAN || CC_IS_CLANG
+       depends on !KASAN_SW_TAGS
+       depends on !(MITIGATION_RETHUNK && KASAN) || RUSTC_VERSION >= 108300
+       help
+-- 
+2.53.0
+
index 24bf8cec1505375dcfce3f22d513b4d8b8ed2c5a..5fc35e486895ef53231dd52fcf86393fd80088a6 100644 (file)
@@ -36,3 +36,5 @@ acpi-nfit-core-fix-possible-null-pointer-dereference.patch
 platform-x86-intel-hid-protect-acpi-notify-handler-against-recursion.patch
 loongarch-add-pio-for-early-access-before-acpi-pci-root-register.patch
 rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+rust-kasan-kasan-rust-requires-clang.patch
diff --git a/queue-6.18/fscrypt-fix-key-setup-in-edge-case-with-multiple-dat.patch b/queue-6.18/fscrypt-fix-key-setup-in-edge-case-with-multiple-dat.patch
new file mode 100644 (file)
index 0000000..6f871a2
--- /dev/null
@@ -0,0 +1,429 @@
+From 0f01cb9f5084015014a40f1541853d3081857f69 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jun 2026 11:06:51 -0700
+Subject: fscrypt: Fix key setup in edge case with multiple data unit sizes
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+[ Upstream commit dd015b566d505d698386103e9c80b739c7336eb8 ]
+
+The addition of support for customizable data unit sizes introduced an
+edge case where a file's contents can be en/decrypted with the wrong
+data unit size.  It occurs when there are multiple v2 policies that:
+
+- Have *different* data unit sizes, via the log2_data_unit_size field
+
+- Share the same master_key_identifier, contents_encryption_mode, and
+  either FSCRYPT_POLICY_FLAG_DIRECT_KEY,
+  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32, or
+  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64
+
+- Are being used on the same filesystem, which also must be mounted with
+  the "inlinecrypt" mount option.
+
+Fortunately this edge case doesn't actually occur in practice.  I just
+found it via code review.  But it needs to be fixed regardless.
+
+The bug is caused by the data unit size not being fully considered when
+blk_crypto_keys are cached in mk_direct_keys, mk_iv_ino_lblk_32_keys,
+and mk_iv_ino_lblk_64_keys.  They're differentiated only by master key,
+encryption mode, and flag.  However, each one actually has a data unit
+size too.  Only the first data unit size that is cached is used.
+
+To fix this, start using the data unit size to differentiate the cached
+keys.  For several reasons, including avoiding increasing the size of
+struct fscrypt_master_key, just replace all three arrays with a single
+linked list instead of changing them into two-dimensional arrays.  This
+works well when considering that in practice at most 2 entries are used
+across all three arrays, so it was already mostly wasted space.
+
+For simplicity, make the list also take over the publish/subscribe of
+the prepared key itself.  That is, create separate list nodes for
+blk_crypto_keys vs crypto_skciphers, and add nodes to the list only when
+their key is actually prepared.  (Note that the legacy
+fscrypt_direct_keys table in fs/crypto/keysetup_v1.c already works this
+way.)  This eliminates the need for the additional memory barriers when
+reading and writing the fields of struct fscrypt_prepared_key.
+
+Note that I technically should have included the data unit size in the
+HKDF info string as well.  But it's too late to change that.
+
+Fixes: 5b1188847180 ("fscrypt: support crypto data unit size less than filesystem block size")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618180652.52742-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h |  52 +++++++++-------
+ fs/crypto/inline_crypt.c    |   8 +--
+ fs/crypto/keyring.c         |  23 ++++---
+ fs/crypto/keysetup.c        | 118 ++++++++++++++++++++++--------------
+ 4 files changed, 120 insertions(+), 81 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 4e8e82a9ccf9a3..3bcde4b59efb0e 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -236,7 +236,7 @@ struct fscrypt_symlink_data {
+  * @tfm: crypto API transform object
+  * @blk_key: key for blk-crypto
+  *
+- * Normally only one of the fields will be non-NULL.
++ * Only one of the fields is non-NULL.
+  */
+ struct fscrypt_prepared_key {
+       struct crypto_sync_skcipher *tfm;
+@@ -245,6 +245,15 @@ struct fscrypt_prepared_key {
+ #endif
+ };
++/* An entry in the linked list ->mk_mode_keys */
++struct fscrypt_mode_key {
++      struct fscrypt_prepared_key key;
++      struct list_head link;
++      u8 hkdf_context;
++      u8 mode_num;
++      u8 data_unit_bits;
++};
++
+ /*
+  * fscrypt_inode_info - the "encryption key" for an inode
+  *
+@@ -433,20 +442,12 @@ int fscrypt_derive_sw_secret(struct super_block *sb,
+  * @prep_key, depending on which encryption implementation the file will use.
+  */
+ static inline bool
+-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
++fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+                       const struct fscrypt_inode_info *ci)
+ {
+-      /*
+-       * The two smp_load_acquire()'s here pair with the smp_store_release()'s
+-       * in fscrypt_prepare_inline_crypt_key() and fscrypt_prepare_key().
+-       * I.e., in some cases (namely, if this prep_key is a per-mode
+-       * encryption key) another task can publish blk_key or tfm concurrently,
+-       * executing a RELEASE barrier.  We need to use smp_load_acquire() here
+-       * to safely ACQUIRE the memory the other task published.
+-       */
+       if (fscrypt_using_inline_encryption(ci))
+-              return smp_load_acquire(&prep_key->blk_key) != NULL;
+-      return smp_load_acquire(&prep_key->tfm) != NULL;
++              return prep_key->blk_key != NULL;
++      return prep_key->tfm != NULL;
+ }
+ #else /* CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
+@@ -489,10 +490,10 @@ fscrypt_derive_sw_secret(struct super_block *sb,
+ }
+ static inline bool
+-fscrypt_is_key_prepared(struct fscrypt_prepared_key *prep_key,
++fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+                       const struct fscrypt_inode_info *ci)
+ {
+-      return smp_load_acquire(&prep_key->tfm) != NULL;
++      return prep_key->tfm != NULL;
+ }
+ #endif /* !CONFIG_FS_ENCRYPTION_INLINE_CRYPT */
+@@ -580,8 +581,8 @@ struct fscrypt_master_key {
+       /*
+        * Active and structural reference counts.  An active ref guarantees
+        * that the struct continues to exist, continues to be in the keyring
+-       * ->s_master_keys, and that any embedded subkeys (e.g.
+-       * ->mk_direct_keys) that have been prepared continue to exist.
++       * ->s_master_keys, and that any non-file-scoped subkeys (e.g.
++       * ->mk_mode_keys) that have been prepared continue to exist.
+        * A structural ref only guarantees that the struct continues to exist.
+        *
+        * There is one active ref associated with ->mk_present being true, and
+@@ -635,12 +636,21 @@ struct fscrypt_master_key {
+       spinlock_t              mk_decrypted_inodes_lock;
+       /*
+-       * Per-mode encryption keys for the various types of encryption policies
+-       * that use them.  Allocated and derived on-demand.
++       * A list of 'struct fscrypt_mode_key' for the (hkdf_context, mode_num,
++       * data_unit_bits, inlinecrypt) combinations that are in use for this
++       * master key, for hkdf_context in [HKDF_CONTEXT_DIRECT_KEY,
++       * HKDF_CONTEXT_IV_INO_LBLK_32_KEY, HKDF_CONTEXT_IV_INO_LBLK_64_KEY].
++       *
++       * This is a linked list and not a hash table because in practice
++       * there's just a single encryption policy per master key, using
++       * _at most_ 2 nodes in this list.  Per-file keys don't use this at all.
++       *
++       * This list is append-only until the master key is fully removed, at
++       * which time the list is cleared.  Before then,
++       * fscrypt_mode_key_setup_mutex synchronizes appends, and searches use
++       * the RCU read lock together with ->mk_sem held for read.
+        */
+-      struct fscrypt_prepared_key mk_direct_keys[FSCRYPT_MODE_MAX + 1];
+-      struct fscrypt_prepared_key mk_iv_ino_lblk_64_keys[FSCRYPT_MODE_MAX + 1];
+-      struct fscrypt_prepared_key mk_iv_ino_lblk_32_keys[FSCRYPT_MODE_MAX + 1];
++      struct list_head        mk_mode_keys;
+       /* Hash key for inode numbers.  Initialized only when needed. */
+       siphash_key_t           mk_ino_hash_key;
+diff --git a/fs/crypto/inline_crypt.c b/fs/crypto/inline_crypt.c
+index ed6e926226b51d..645cc493607294 100644
+--- a/fs/crypto/inline_crypt.c
++++ b/fs/crypto/inline_crypt.c
+@@ -198,13 +198,7 @@ int fscrypt_prepare_inline_crypt_key(struct fscrypt_prepared_key *prep_key,
+               goto fail;
+       }
+-      /*
+-       * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
+-       * I.e., here we publish ->blk_key with a RELEASE barrier so that
+-       * concurrent tasks can ACQUIRE it.  Note that this concurrency is only
+-       * possible for per-mode keys, not for per-file keys.
+-       */
+-      smp_store_release(&prep_key->blk_key, blk_key);
++      prep_key->blk_key = blk_key;
+       return 0;
+ fail:
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 3adbd7167055a9..29bea5f3c98234 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -87,14 +87,14 @@ void fscrypt_put_master_key(struct fscrypt_master_key *mk)
+ void fscrypt_put_master_key_activeref(struct super_block *sb,
+                                     struct fscrypt_master_key *mk)
+ {
+-      size_t i;
++      struct fscrypt_mode_key *node, *tmp;
+       if (!refcount_dec_and_test(&mk->mk_active_refs))
+               return;
+       /*
+        * No active references left, so complete the full removal of this
+        * fscrypt_master_key struct by removing it from the keyring and
+-       * destroying any subkeys embedded in it.
++       * destroying any non-file-scoped subkeys.
+        */
+       if (WARN_ON_ONCE(!sb->s_master_keys))
+@@ -110,13 +110,16 @@ void fscrypt_put_master_key_activeref(struct super_block *sb,
+       WARN_ON_ONCE(mk->mk_present);
+       WARN_ON_ONCE(!list_empty(&mk->mk_decrypted_inodes));
+-      for (i = 0; i <= FSCRYPT_MODE_MAX; i++) {
+-              fscrypt_destroy_prepared_key(
+-                              sb, &mk->mk_direct_keys[i]);
+-              fscrypt_destroy_prepared_key(
+-                              sb, &mk->mk_iv_ino_lblk_64_keys[i]);
+-              fscrypt_destroy_prepared_key(
+-                              sb, &mk->mk_iv_ino_lblk_32_keys[i]);
++      /*
++       * Destroy any non-file-scoped subkeys.  Since ->mk_active_refs == 0,
++       * they're no longer referenced by any inodes.  Nor can key setup run
++       * and use them again.  So they're no longer needed.  (This implies no
++       * concurrent readers, so we don't need list_del_rcu() for example.)
++       */
++      list_for_each_entry_safe(node, tmp, &mk->mk_mode_keys, link) {
++              fscrypt_destroy_prepared_key(sb, &node->key);
++              list_del(&node->link);
++              kfree(node);
+       }
+       memzero_explicit(&mk->mk_ino_hash_key,
+                        sizeof(mk->mk_ino_hash_key));
+@@ -445,6 +448,8 @@ static int add_new_master_key(struct super_block *sb,
+       INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
+       spin_lock_init(&mk->mk_decrypted_inodes_lock);
++      INIT_LIST_HEAD(&mk->mk_mode_keys);
++
+       if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
+               err = allocate_master_key_users_keyring(mk);
+               if (err)
+diff --git a/fs/crypto/keysetup.c b/fs/crypto/keysetup.c
+index 4bd3918f50e3fa..f27997ef9a08c5 100644
+--- a/fs/crypto/keysetup.c
++++ b/fs/crypto/keysetup.c
+@@ -163,13 +163,7 @@ int fscrypt_prepare_key(struct fscrypt_prepared_key *prep_key,
+       tfm = fscrypt_allocate_skcipher(ci->ci_mode, raw_key, ci->ci_inode);
+       if (IS_ERR(tfm))
+               return PTR_ERR(tfm);
+-      /*
+-       * Pairs with the smp_load_acquire() in fscrypt_is_key_prepared().
+-       * I.e., here we publish ->tfm with a RELEASE barrier so that
+-       * concurrent tasks can ACQUIRE it.  Note that this concurrency is only
+-       * possible for per-mode keys, not for per-file keys.
+-       */
+-      smp_store_release(&prep_key->tfm, tfm);
++      prep_key->tfm = tfm;
+       return 0;
+ }
+@@ -190,9 +184,37 @@ int fscrypt_set_per_file_enc_key(struct fscrypt_inode_info *ci,
+       return fscrypt_prepare_key(&ci->ci_enc_key, raw_key, ci);
+ }
++/*
++ * Find the fscrypt_prepared_key (if any) for a particular (mk, hkdf_context,
++ * mode_num, data_unit_bits, inlinecrypt) combination.
++ *
++ * The caller must hold ->mk_sem for reading and ->mk_present must be true,
++ * ensuring that ->mk_mode_keys is still append-only.
++ */
++static struct fscrypt_prepared_key *
++fscrypt_find_mode_key(struct fscrypt_master_key *mk, u8 hkdf_context,
++                    u8 mode_num, const struct fscrypt_inode_info *ci)
++{
++      struct fscrypt_mode_key *node;
++
++      /*
++       * The RCU read lock here is used only to synchronize with concurrent
++       * list_add_tail_rcu().  Concurrent deletions are impossible here, so
++       * returning a pointer to a node without taking any refcount is safe.
++       */
++      guard(rcu)();
++      list_for_each_entry_rcu(node, &mk->mk_mode_keys, link) {
++              if (node->hkdf_context == hkdf_context &&
++                  node->mode_num == mode_num &&
++                  node->data_unit_bits == ci->ci_data_unit_bits &&
++                  fscrypt_is_key_prepared(&node->key, ci))
++                      return &node->key;
++      }
++      return NULL;
++}
++
+ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
+                                 struct fscrypt_master_key *mk,
+-                                struct fscrypt_prepared_key *keys,
+                                 u8 hkdf_context, bool include_fs_uuid)
+ {
+       const struct inode *inode = ci->ci_inode;
+@@ -200,7 +222,8 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
+       struct fscrypt_mode *mode = ci->ci_mode;
+       const u8 mode_num = mode - fscrypt_modes;
+       struct fscrypt_prepared_key *prep_key;
+-      u8 mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
++      struct fscrypt_mode_key *new_node;
++      u8 raw_mode_key[FSCRYPT_MAX_RAW_KEY_SIZE];
+       u8 hkdf_info[sizeof(mode_num) + sizeof(sb->s_uuid)];
+       unsigned int hkdf_infolen = 0;
+       bool use_hw_wrapped_key = false;
+@@ -223,48 +246,56 @@ static int setup_per_mode_enc_key(struct fscrypt_inode_info *ci,
+               use_hw_wrapped_key = true;
+       }
+-      prep_key = &keys[mode_num];
+-      if (fscrypt_is_key_prepared(prep_key, ci)) {
++      prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
++      if (prep_key) {
+               ci->ci_enc_key = *prep_key;
+               return 0;
+       }
+-      mutex_lock(&fscrypt_mode_key_setup_mutex);
++      guard(mutex)(&fscrypt_mode_key_setup_mutex);
+-      if (fscrypt_is_key_prepared(prep_key, ci))
+-              goto done_unlock;
++      prep_key = fscrypt_find_mode_key(mk, hkdf_context, mode_num, ci);
++      if (prep_key) {
++              ci->ci_enc_key = *prep_key;
++              return 0;
++      }
++
++      new_node = kzalloc_obj(*new_node);
++      if (!new_node)
++              return -ENOMEM;
++      new_node->hkdf_context = hkdf_context;
++      new_node->mode_num = mode_num;
++      new_node->data_unit_bits = ci->ci_data_unit_bits;
++      prep_key = &new_node->key;
+       if (use_hw_wrapped_key) {
+               err = fscrypt_prepare_inline_crypt_key(prep_key,
+                                                      mk->mk_secret.bytes,
+                                                      mk->mk_secret.size, true,
+                                                      ci);
+-              if (err)
+-                      goto out_unlock;
+-              goto done_unlock;
++      } else {
++              static_assert(sizeof(mode_num) == 1);
++              static_assert(sizeof(sb->s_uuid) == 16);
++              static_assert(sizeof(hkdf_info) == 17);
++              hkdf_info[hkdf_infolen++] = mode_num;
++              if (include_fs_uuid) {
++                      memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
++                             sizeof(sb->s_uuid));
++                      hkdf_infolen += sizeof(sb->s_uuid);
++              }
++              fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context,
++                                  hkdf_info, hkdf_infolen, raw_mode_key,
++                                  mode->keysize);
++              err = fscrypt_prepare_key(prep_key, raw_mode_key, ci);
++              memzero_explicit(raw_mode_key, mode->keysize);
+       }
+-
+-      BUILD_BUG_ON(sizeof(mode_num) != 1);
+-      BUILD_BUG_ON(sizeof(sb->s_uuid) != 16);
+-      BUILD_BUG_ON(sizeof(hkdf_info) != 17);
+-      hkdf_info[hkdf_infolen++] = mode_num;
+-      if (include_fs_uuid) {
+-              memcpy(&hkdf_info[hkdf_infolen], &sb->s_uuid,
+-                     sizeof(sb->s_uuid));
+-              hkdf_infolen += sizeof(sb->s_uuid);
++      if (err) {
++              kfree(new_node);
++              return err;
+       }
+-      fscrypt_hkdf_expand(&mk->mk_secret.hkdf, hkdf_context, hkdf_info,
+-                          hkdf_infolen, mode_key, mode->keysize);
+-      err = fscrypt_prepare_key(prep_key, mode_key, ci);
+-      memzero_explicit(mode_key, mode->keysize);
+-      if (err)
+-              goto out_unlock;
+-done_unlock:
++      list_add_tail_rcu(&new_node->link, &mk->mk_mode_keys);
+       ci->ci_enc_key = *prep_key;
+-      err = 0;
+-out_unlock:
+-      mutex_unlock(&fscrypt_mode_key_setup_mutex);
+-      return err;
++      return 0;
+ }
+ /*
+@@ -311,8 +342,8 @@ static int fscrypt_setup_iv_ino_lblk_32_key(struct fscrypt_inode_info *ci,
+ {
+       int err;
+-      err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_32_keys,
+-                                   HKDF_CONTEXT_IV_INO_LBLK_32_KEY, true);
++      err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_IV_INO_LBLK_32_KEY,
++                                   true);
+       if (err)
+               return err;
+@@ -364,8 +395,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
+                * encryption key.  This ensures that the master key is
+                * consistently used only for HKDF, avoiding key reuse issues.
+                */
+-              err = setup_per_mode_enc_key(ci, mk, mk->mk_direct_keys,
+-                                           HKDF_CONTEXT_DIRECT_KEY, false);
++              err = setup_per_mode_enc_key(ci, mk, HKDF_CONTEXT_DIRECT_KEY,
++                                           false);
+       } else if (ci->ci_policy.v2.flags &
+                  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64) {
+               /*
+@@ -374,9 +405,8 @@ static int fscrypt_setup_v2_file_key(struct fscrypt_inode_info *ci,
+                * the IVs.  This format is optimized for use with inline
+                * encryption hardware compliant with the UFS standard.
+                */
+-              err = setup_per_mode_enc_key(ci, mk, mk->mk_iv_ino_lblk_64_keys,
+-                                           HKDF_CONTEXT_IV_INO_LBLK_64_KEY,
+-                                           true);
++              err = setup_per_mode_enc_key(
++                      ci, mk, HKDF_CONTEXT_IV_INO_LBLK_64_KEY, true);
+       } else if (ci->ci_policy.v2.flags &
+                  FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) {
+               err = fscrypt_setup_iv_ino_lblk_32_key(ci, mk);
+-- 
+2.53.0
+
diff --git a/queue-6.18/fscrypt-replace-mk_users-keyring-with-simple-list.patch b/queue-6.18/fscrypt-replace-mk_users-keyring-with-simple-list.patch
new file mode 100644 (file)
index 0000000..97231b6
--- /dev/null
@@ -0,0 +1,454 @@
+From 8572b924e77f5d7c92c3270def5f810131ee2856 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 18 Jun 2026 15:19:21 -0700
+Subject: fscrypt: Replace mk_users keyring with simple list
+
+From: Eric Biggers <ebiggers@kernel.org>
+
+[ Upstream commit 696c030e1e3438955aba443b308ee8b6faa3983e ]
+
+Change mk_users (the set of user claims to an fscrypt master key) from a
+'struct key' keyring to a simple linked list.
+
+It's still a collection of 'struct key' for quota tracking.  It was
+originally thought to be natural that a collection of 'struct key'
+should be held in a 'struct key' keyring.  In reality, it's just been
+causing problems, similar to how using 'struct key' for the filesystem
+keyring caused problems and was removed in commit d7e7b9af104c
+("fscrypt: stop using keyrings subsystem for fscrypt_master_key").
+
+Commit d3a7bd420076 ("fscrypt: clear keyring before calling key_put()")
+fixed mk_users cleanup to be synchronous.  But that apparently wasn't
+enough: the keyring subsystem's redundant locking is still generating
+lockdep false positives due to the interaction with filesystem reclaim.
+
+With the simple list, the redundant locking and lockdep issue goes away.
+
+Of course, searching a linked list is linear-time whereas the
+'struct key' keyring used a fancy constant-time associative array.  But
+that's fine here, since in practice there's just one entry in the list.
+In fact the new code is much faster in practice, since it's much smaller
+and doesn't have to convert the kuid_t into a string to search for it.
+
+Reported-by: syzbot+f55b043dacf43776b50c@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=f55b043dacf43776b50c
+Reported-by: Mohammed EL Kadiri <med08elkadiri@gmail.com>
+Closes: https://lore.kernel.org/keyrings/20260614150041.21172-1-med08elkadiri@gmail.com/
+Fixes: 23c688b54016 ("fscrypt: allow unprivileged users to add/remove keys for v2 policies")
+Cc: stable@vger.kernel.org
+Link: https://patch.msgid.link/20260618221921.87896-1-ebiggers@kernel.org
+Signed-off-by: Eric Biggers <ebiggers@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/crypto/fscrypt_private.h |  32 ++++--
+ fs/crypto/keyring.c         | 216 +++++++++++++++---------------------
+ 2 files changed, 113 insertions(+), 135 deletions(-)
+
+diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
+index 3bcde4b59efb0e..886ea39e924df0 100644
+--- a/fs/crypto/fscrypt_private.h
++++ b/fs/crypto/fscrypt_private.h
+@@ -499,6 +499,19 @@ fscrypt_is_key_prepared(const struct fscrypt_prepared_key *prep_key,
+ /* keyring.c */
++/*
++ * fscrypt_master_key_user - a user's claim to a master key
++ */
++struct fscrypt_master_key_user {
++      struct list_head link;
++      kuid_t uid;
++      /*
++       * This 'struct key' contains no secret.  It exists solely to charge the
++       * appropriate user's key quota.
++       */
++      struct key *quota_key;
++};
++
+ /*
+  * fscrypt_master_key_secret - secret key material of an in-use master key
+  */
+@@ -614,19 +627,18 @@ struct fscrypt_master_key {
+       struct fscrypt_key_specifier            mk_spec;
+       /*
+-       * Keyring which contains a key of type 'key_type_fscrypt_user' for each
+-       * user who has added this key.  Normally each key will be added by just
+-       * one user, but it's possible that multiple users share a key, and in
+-       * that case we need to keep track of those users so that one user can't
+-       * remove the key before the others want it removed too.
++       * List of user claims to this key (struct fscrypt_master_key_user).
++       * Normally each key will be added by just one user, but it's possible
++       * that multiple users share a key, and in that case we need to keep
++       * track of those users so that one user can't remove the key before the
++       * others want it removed too.
+        *
+-       * This is NULL for v1 policy keys; those can only be added by root.
++       * Used only for v2 policy keys.  v1 policy keys can be added only by
++       * root, so user tracking doesn't apply to them.
+        *
+-       * Locking: protected by ->mk_sem.  (We don't just rely on the keyrings
+-       * subsystem semaphore ->mk_users->sem, as we need support for atomic
+-       * search+insert along with proper synchronization with other fields.)
++       * Locking: protected by ->mk_sem.
+        */
+-      struct key              *mk_users;
++      struct list_head        mk_users;
+       /*
+        * List of inodes that were unlocked using this key.  This allows the
+diff --git a/fs/crypto/keyring.c b/fs/crypto/keyring.c
+index 29bea5f3c98234..4ea4ee5cfc64b5 100644
+--- a/fs/crypto/keyring.c
++++ b/fs/crypto/keyring.c
+@@ -65,22 +65,19 @@ static void fscrypt_free_master_key(struct rcu_head *head)
+       kfree_sensitive(mk);
+ }
++static void clear_mk_users(struct fscrypt_master_key *mk);
++
+ void fscrypt_put_master_key(struct fscrypt_master_key *mk)
+ {
+       if (!refcount_dec_and_test(&mk->mk_struct_refs))
+               return;
+       /*
+-       * No structural references left, so free ->mk_users, and also free the
++       * No structural references left, so clear ->mk_users, and also free the
+        * fscrypt_master_key struct itself after an RCU grace period ensures
+        * that concurrent keyring lookups can no longer find it.
+        */
+       WARN_ON_ONCE(refcount_read(&mk->mk_active_refs) != 0);
+-      if (mk->mk_users) {
+-              /* Clear the keyring so the quota gets released right away. */
+-              keyring_clear(mk->mk_users);
+-              key_put(mk->mk_users);
+-              mk->mk_users = NULL;
+-      }
++      clear_mk_users(mk);
+       call_rcu(&mk->mk_rcu_head, fscrypt_free_master_key);
+ }
+@@ -165,8 +162,8 @@ static void fscrypt_user_key_describe(const struct key *key, struct seq_file *m)
+ }
+ /*
+- * Type of key in ->mk_users.  Each key of this type represents a particular
+- * user who has added a particular master key.
++ * Type of fscrypt_master_key_user::quota_key.  This contains no secret; it
++ * exists solely to charge a user's key quota.
+  *
+  * Note that the name of this key type really should be something like
+  * ".fscrypt-user" instead of simply ".fscrypt".  But the shorter name is chosen
+@@ -180,30 +177,9 @@ static struct key_type key_type_fscrypt_user = {
+       .describe               = fscrypt_user_key_describe,
+ };
+-#define FSCRYPT_MK_USERS_DESCRIPTION_SIZE     \
+-      (CONST_STRLEN("fscrypt-") + 2 * FSCRYPT_KEY_IDENTIFIER_SIZE + \
+-       CONST_STRLEN("-users") + 1)
+-
+ #define FSCRYPT_MK_USER_DESCRIPTION_SIZE      \
+       (2 * FSCRYPT_KEY_IDENTIFIER_SIZE + CONST_STRLEN(".uid.") + 10 + 1)
+-static void format_mk_users_keyring_description(
+-                      char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE],
+-                      const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+-{
+-      sprintf(description, "fscrypt-%*phN-users",
+-              FSCRYPT_KEY_IDENTIFIER_SIZE, mk_identifier);
+-}
+-
+-static void format_mk_user_description(
+-                      char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE],
+-                      const u8 mk_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE])
+-{
+-
+-      sprintf(description, "%*phN.uid.%u", FSCRYPT_KEY_IDENTIFIER_SIZE,
+-              mk_identifier, __kuid_val(current_fsuid()));
+-}
+-
+ /* Create ->s_master_keys if needed.  Synchronized by fscrypt_add_key_mutex. */
+ static int allocate_filesystem_keyring(struct super_block *sb)
+ {
+@@ -338,91 +314,94 @@ fscrypt_find_master_key(struct super_block *sb,
+       return mk;
+ }
+-static int allocate_master_key_users_keyring(struct fscrypt_master_key *mk)
+-{
+-      char description[FSCRYPT_MK_USERS_DESCRIPTION_SIZE];
+-      struct key *keyring;
+-
+-      format_mk_users_keyring_description(description,
+-                                          mk->mk_spec.u.identifier);
+-      keyring = keyring_alloc(description, GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+-                              current_cred(), KEY_POS_SEARCH |
+-                                KEY_USR_SEARCH | KEY_USR_READ | KEY_USR_VIEW,
+-                              KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
+-      if (IS_ERR(keyring))
+-              return PTR_ERR(keyring);
+-
+-      mk->mk_users = keyring;
+-      return 0;
+-}
+-
+-/*
+- * Find the current user's "key" in the master key's ->mk_users.
+- * Returns ERR_PTR(-ENOKEY) if not found.
+- */
+-static struct key *find_master_key_user(struct fscrypt_master_key *mk)
++/* Find the current user's claim in ->mk_users.  ->mk_sem must be held. */
++static struct fscrypt_master_key_user *
++find_master_key_user(struct fscrypt_master_key *mk)
+ {
+-      char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
+-      key_ref_t keyref;
++      struct fscrypt_master_key_user *mk_user;
++      kuid_t uid = current_fsuid();
+-      format_mk_user_description(description, mk->mk_spec.u.identifier);
+-
+-      /*
+-       * We need to mark the keyring reference as "possessed" so that we
+-       * acquire permission to search it, via the KEY_POS_SEARCH permission.
+-       */
+-      keyref = keyring_search(make_key_ref(mk->mk_users, true /*possessed*/),
+-                              &key_type_fscrypt_user, description, false);
+-      if (IS_ERR(keyref)) {
+-              if (PTR_ERR(keyref) == -EAGAIN || /* not found */
+-                  PTR_ERR(keyref) == -EKEYREVOKED) /* recently invalidated */
+-                      keyref = ERR_PTR(-ENOKEY);
+-              return ERR_CAST(keyref);
++      list_for_each_entry(mk_user, &mk->mk_users, link) {
++              if (uid_eq(mk_user->uid, uid))
++                      return mk_user;
+       }
+-      return key_ref_to_ptr(keyref);
++      return NULL;
+ }
+ /*
+- * Give the current user a "key" in ->mk_users.  This charges the user's quota
++ * Give the current user a claim in ->mk_users.  This charges the user's quota
+  * and marks the master key as added by the current user, so that it cannot be
+  * removed by another user with the key.  Either ->mk_sem must be held for
+  * write, or the master key must be still undergoing initialization.
+  */
+ static int add_master_key_user(struct fscrypt_master_key *mk)
+ {
++      kuid_t uid = current_fsuid();
+       char description[FSCRYPT_MK_USER_DESCRIPTION_SIZE];
+-      struct key *mk_user;
++      struct key *quota_key;
++      struct fscrypt_master_key_user *mk_user;
+       int err;
+-      format_mk_user_description(description, mk->mk_spec.u.identifier);
+-      mk_user = key_alloc(&key_type_fscrypt_user, description,
+-                          current_fsuid(), current_gid(), current_cred(),
+-                          KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
+-      if (IS_ERR(mk_user))
+-              return PTR_ERR(mk_user);
++      snprintf(description, sizeof(description), "%*phN.uid.%u",
++               FSCRYPT_KEY_IDENTIFIER_SIZE, mk->mk_spec.u.identifier,
++               __kuid_val(uid));
++      quota_key = key_alloc(&key_type_fscrypt_user, description, uid,
++                            current_gid(), current_cred(),
++                            KEY_POS_SEARCH | KEY_USR_VIEW, 0, NULL);
++      if (IS_ERR(quota_key))
++              return PTR_ERR(quota_key);
++
++      err = key_instantiate_and_link(quota_key, NULL, 0, NULL, NULL);
++      if (err) {
++              key_put(quota_key);
++              return err;
++      }
+-      err = key_instantiate_and_link(mk_user, NULL, 0, mk->mk_users, NULL);
+-      key_put(mk_user);
+-      return err;
++      mk_user = kzalloc_obj(*mk_user);
++      if (!mk_user) {
++              key_put(quota_key);
++              return -ENOMEM;
++      }
++      mk_user->uid = uid;
++      mk_user->quota_key = quota_key;
++      list_add(&mk_user->link, &mk->mk_users);
++      return 0;
++}
++
++static void unlink_and_free_mk_user(struct fscrypt_master_key_user *mk_user)
++{
++      list_del(&mk_user->link);
++      key_put(mk_user->quota_key);
++      kfree(mk_user);
+ }
+ /*
+- * Remove the current user's "key" from ->mk_users.
++ * Remove the current user's claim from ->mk_users.
+  * ->mk_sem must be held for write.
+  *
+- * Returns 0 if removed, -ENOKEY if not found, or another -errno code.
++ * Returns 0 if removed or -ENOKEY if not found.
+  */
+ static int remove_master_key_user(struct fscrypt_master_key *mk)
+ {
+-      struct key *mk_user;
+-      int err;
++      struct fscrypt_master_key_user *mk_user;
+       mk_user = find_master_key_user(mk);
+-      if (IS_ERR(mk_user))
+-              return PTR_ERR(mk_user);
+-      err = key_unlink(mk->mk_users, mk_user);
+-      key_put(mk_user);
+-      return err;
++      if (!mk_user)
++              return -ENOKEY;
++      unlink_and_free_mk_user(mk_user);
++      return 0;
++}
++
++/*
++ * Clear ->mk_users.  Either ->mk_sem must be held for write, or 'mk' must have
++ * no structural references left.
++ */
++static void clear_mk_users(struct fscrypt_master_key *mk)
++{
++      struct fscrypt_master_key_user *mk_user, *tmp;
++
++      list_for_each_entry_safe(mk_user, tmp, &mk->mk_users, link)
++              unlink_and_free_mk_user(mk_user);
+ }
+ /*
+@@ -445,15 +424,14 @@ static int add_new_master_key(struct super_block *sb,
+       refcount_set(&mk->mk_struct_refs, 1);
+       mk->mk_spec = *mk_spec;
++      INIT_LIST_HEAD(&mk->mk_users);
++
+       INIT_LIST_HEAD(&mk->mk_decrypted_inodes);
+       spin_lock_init(&mk->mk_decrypted_inodes_lock);
+       INIT_LIST_HEAD(&mk->mk_mode_keys);
+       if (mk_spec->type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
+-              err = allocate_master_key_users_keyring(mk);
+-              if (err)
+-                      goto out_put;
+               err = add_master_key_user(mk);
+               if (err)
+                       goto out_put;
+@@ -482,19 +460,13 @@ static int add_existing_master_key(struct fscrypt_master_key *mk,
+       int err;
+       /*
+-       * If the current user is already in ->mk_users, then there's nothing to
+-       * do.  Otherwise, we need to add the user to ->mk_users.  (Neither is
+-       * applicable for v1 policy keys, which have NULL ->mk_users.)
++       * For v2 policy keys (FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER): If the current
++       * user is already in ->mk_users, then there's nothing to do.
++       * Otherwise, add the user to ->mk_users.
+        */
+-      if (mk->mk_users) {
+-              struct key *mk_user = find_master_key_user(mk);
+-
+-              if (mk_user != ERR_PTR(-ENOKEY)) {
+-                      if (IS_ERR(mk_user))
+-                              return PTR_ERR(mk_user);
+-                      key_put(mk_user);
++      if (mk->mk_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) {
++              if (find_master_key_user(mk) != NULL)
+                       return 0;
+-              }
+               err = add_master_key_user(mk);
+               if (err)
+                       return err;
+@@ -893,7 +865,6 @@ int fscrypt_verify_key_added(struct super_block *sb,
+ {
+       struct fscrypt_key_specifier mk_spec;
+       struct fscrypt_master_key *mk;
+-      struct key *mk_user;
+       int err;
+       mk_spec.type = FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER;
+@@ -905,13 +876,10 @@ int fscrypt_verify_key_added(struct super_block *sb,
+               goto out;
+       }
+       down_read(&mk->mk_sem);
+-      mk_user = find_master_key_user(mk);
+-      if (IS_ERR(mk_user)) {
+-              err = PTR_ERR(mk_user);
+-      } else {
+-              key_put(mk_user);
++      if (find_master_key_user(mk) != NULL)
+               err = 0;
+-      }
++      else
++              err = -ENOKEY;
+       up_read(&mk->mk_sem);
+       fscrypt_put_master_key(mk);
+ out:
+@@ -1103,16 +1071,18 @@ static int do_remove_key(struct file *filp, void __user *_uarg, bool all_users)
+       down_write(&mk->mk_sem);
+       /* If relevant, remove current user's (or all users) claim to the key */
+-      if (mk->mk_users && mk->mk_users->keys.nr_leaves_on_tree != 0) {
+-              if (all_users)
+-                      err = keyring_clear(mk->mk_users);
+-              else
++      if (!list_empty(&mk->mk_users)) {
++              if (all_users) {
++                      clear_mk_users(mk);
++                      err = 0;
++              } else {
+                       err = remove_master_key_user(mk);
++              }
+               if (err) {
+                       up_write(&mk->mk_sem);
+                       goto out_put_key;
+               }
+-              if (mk->mk_users->keys.nr_leaves_on_tree != 0) {
++              if (!list_empty(&mk->mk_users)) {
+                       /*
+                        * Other users have still added the key too.  We removed
+                        * the current user's claim to the key, but we still
+@@ -1198,6 +1168,8 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       struct super_block *sb = file_inode(filp)->i_sb;
+       struct fscrypt_get_key_status_arg arg;
+       struct fscrypt_master_key *mk;
++      kuid_t uid;
++      const struct fscrypt_master_key_user *mk_user;
+       int err;
+       if (copy_from_user(&arg, uarg, sizeof(arg)))
+@@ -1230,19 +1202,13 @@ int fscrypt_ioctl_get_key_status(struct file *filp, void __user *uarg)
+       }
+       arg.status = FSCRYPT_KEY_STATUS_PRESENT;
+-      if (mk->mk_users) {
+-              struct key *mk_user;
+-              arg.user_count = mk->mk_users->keys.nr_leaves_on_tree;
+-              mk_user = find_master_key_user(mk);
+-              if (!IS_ERR(mk_user)) {
++      uid = current_fsuid();
++      list_for_each_entry(mk_user, &mk->mk_users, link) {
++              arg.user_count++;
++              if (uid_eq(mk_user->uid, uid))
+                       arg.status_flags |=
+                               FSCRYPT_KEY_STATUS_FLAG_ADDED_BY_SELF;
+-                      key_put(mk_user);
+-              } else if (mk_user != ERR_PTR(-ENOKEY)) {
+-                      err = PTR_ERR(mk_user);
+-                      goto out_release_key;
+-              }
+       }
+       err = 0;
+ out_release_key:
+-- 
+2.53.0
+
diff --git a/queue-6.18/perf-core-detach-event-groups-during-remove_on_exec.patch b/queue-6.18/perf-core-detach-event-groups-during-remove_on_exec.patch
new file mode 100644 (file)
index 0000000..d37cf3b
--- /dev/null
@@ -0,0 +1,111 @@
+From 0459843e2962de0309deca8d97f06c75479adba5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Jun 2026 23:22:18 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 6b6fea8d33e044..449550b3bb286a 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4586,7 +4586,7 @@ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+                                 struct perf_event_context *ctx,
+                                 struct task_struct *task,
+-                                bool revoke);
++                                unsigned long detach_flags);
+ /*
+  * Removes all events from the current task that have been marked
+@@ -4613,7 +4613,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+               modified = true;
+-              perf_event_exit_event(event, ctx, ctx->task, false);
++              perf_event_exit_event(event, ctx, ctx->task, DETACH_GROUP);
+       }
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -12511,7 +12511,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event,
+       /*
+        * De-schedule the event and mark it REVOKED.
+        */
+-      perf_event_exit_event(event, ctx, ctx->task, true);
++      perf_event_exit_event(event, ctx, ctx->task, DETACH_REVOKE);
+       /*
+        * All _free_event() bits that rely on event->pmu:
+@@ -14095,12 +14095,13 @@ static void
+ perf_event_exit_event(struct perf_event *event,
+                     struct perf_event_context *ctx,
+                     struct task_struct *task,
+-                    bool revoke)
++                    unsigned long detach_flags)
+ {
+       struct perf_event *parent_event = event->parent;
+-      unsigned long detach_flags = DETACH_EXIT;
+       unsigned int attach_state;
++      detach_flags |= DETACH_EXIT;
++
+       if (parent_event) {
+               /*
+                * Do not destroy the 'original' grouping; because of the
+@@ -14123,8 +14124,8 @@ perf_event_exit_event(struct perf_event *event,
+                       sync_child_event(event, task);
+       }
+-      if (revoke)
+-              detach_flags |= DETACH_GROUP | DETACH_REVOKE;
++      if (detach_flags & DETACH_REVOKE)
++              detach_flags |= DETACH_GROUP;
+       perf_remove_from_context(event, detach_flags);
+       /*
+@@ -14212,7 +14213,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
+               perf_event_task(task, ctx, 0);
+       list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry)
+-              perf_event_exit_event(child_event, ctx, exit ? task : NULL, false);
++              perf_event_exit_event(child_event, ctx, exit ? task : NULL, 0);
+       mutex_unlock(&ctx->mutex);
+-- 
+2.53.0
+
diff --git a/queue-6.18/rust-kasan-kasan-rust-requires-clang.patch b/queue-6.18/rust-kasan-kasan-rust-requires-clang.patch
new file mode 100644 (file)
index 0000000..63ff733
--- /dev/null
@@ -0,0 +1,40 @@
+From 43f26212403918d90b27dfae878f9e0c7f8158e9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 19:59:43 +0200
+Subject: rust: kasan: KASAN+RUST requires clang
+
+From: Alice Ryhl <aliceryhl@google.com>
+
+[ Upstream commit 5b271543d0f08e9733d4732721e960e285f6448f ]
+
+Kernel KASAN involves passing various llvm/gcc specific arguments to
+the C and Rust compiler. Since these arguments differ between llvm and
+gcc, it's not safe to mix an llvm-based rustc with a gcc build when
+kasan is enabled.
+
+Signed-off-by: Alice Ryhl <aliceryhl@google.com>
+Reviewed-by: Gary Guo <gary@garyguo.net>
+Cc: stable@vger.kernel.org
+Fixes: e3117404b411 ("kbuild: rust: Enable KASAN support")
+Link: https://patch.msgid.link/20260408-kasan-rust-sw-tags-v3-1-e07964d14363@google.com
+Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ init/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/init/Kconfig b/init/Kconfig
+index cab3ad28ca49e7..0c25e78e10f47e 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -2096,6 +2096,7 @@ config RUST
+       depends on !CFI || HAVE_CFI_ICALL_NORMALIZE_INTEGERS_RUSTC
+       select CFI_ICALL_NORMALIZE_INTEGERS if CFI
+       depends on !CALL_PADDING || RUSTC_VERSION >= 108100
++      depends on !KASAN || CC_IS_CLANG
+       depends on !KASAN_SW_TAGS
+       depends on !(MITIGATION_RETHUNK && KASAN) || RUSTC_VERSION >= 108300
+       help
+-- 
+2.53.0
+
index e307ec6abd330e576db53d32d68a44e28fd2ab0a..9efc790bf66952b7474a55268a12474553246e3d 100644 (file)
@@ -39,3 +39,7 @@ rust-block-fix-gendisk-cleanup-paths.patch
 rust-doctest-fix-incorrect-pattern-in-replacement.patch
 rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
 futex-requeue-revert-prevent-null-pointer-dereference-in-remove_waiter-on-self-deadlock.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+rust-kasan-kasan-rust-requires-clang.patch
+fscrypt-fix-key-setup-in-edge-case-with-multiple-dat.patch
+fscrypt-replace-mk_users-keyring-with-simple-list.patch
diff --git a/queue-6.6/arm64-fix-early-handling-of-feat_e2h0-not-being-impl.patch b/queue-6.6/arm64-fix-early-handling-of-feat_e2h0-not-being-impl.patch
new file mode 100644 (file)
index 0000000..2f6efdc
--- /dev/null
@@ -0,0 +1,92 @@
+From 2342107063f0bbeb4272bc4ad5f4a359b9b09068 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:00 +0000
+Subject: arm64: Fix early handling of FEAT_E2H0 not being implemented
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit b3320142f3db9b3f2a23460abd3e22292e1530a5 ]
+
+Commit 3944382fa6f2 introduced checks for the FEAT_E2H0 not being
+implemented. However, the check is absolutely wrong and makes a
+point it testing a bit that is guaranteed to be zero.
+
+On top of that, the detection happens way too late, after the
+init_el2_state has done its job.
+
+This went undetected because the HW this was tested on has E2H being
+RAO/WI, and not RES1. However, the bug shows up when run as a nested
+guest, where HCR_EL2.E2H is not necessarily set to 1. As a result,
+booting the kernel in hVHE mode fails with timer accesses being
+cought in a trap loop (which was fun to debug).
+
+Fix the check for ID_AA64MMFR4_EL1.E2H0, and set the HCR_EL2.E2H bit
+early so that it can be checked by the rest of the init sequence.
+
+With this, hVHE works again in a NV environment that doesn't have
+FEAT_E2H0.
+
+Fixes: 3944382fa6f2 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Link: https://lore.kernel.org/r/20240321115414.3169115-1-maz@kernel.org
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/head.S | 29 ++++++++++++++++-------------
+ 1 file changed, 16 insertions(+), 13 deletions(-)
+
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index e32c8dd0b17a77..e0e710b36da378 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -576,6 +576,21 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+       isb
+ 0:
+       mov_q   x0, HCR_HOST_NVHE_FLAGS
++
++      /*
++       * Compliant CPUs advertise their VHE-onlyness with
++       * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
++       * RES1 in that case. Publish the E2H bit early so that
++       * it can be picked up by the init_el2_state macro.
++       *
++       * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
++       * don't advertise it (they predate this relaxation).
++       */
++      mrs_s   x1, SYS_ID_AA64MMFR4_EL1
++      tbz     x1, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
++
++      orr     x0, x0, #HCR_E2H
++1:
+       msr     hcr_el2, x0
+       isb
+@@ -588,22 +603,10 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+       mov_q   x1, INIT_SCTLR_EL1_MMU_OFF
+-      /*
+-       * Compliant CPUs advertise their VHE-onlyness with
+-       * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
+-       * RES1 in that case.
+-       *
+-       * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but
+-       * don't advertise it (they predate this relaxation).
+-       */
+-      mrs_s   x0, SYS_ID_AA64MMFR4_EL1
+-      ubfx    x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
+-      tbnz    x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
+-
+       mrs     x0, hcr_el2
+       and     x0, x0, #HCR_E2H
+       cbz     x0, 2f
+-1:
++
+       /* Set a sane SCTLR_EL1, the VHE way */
+       pre_disable_mmu_workaround
+       msr_s   SYS_SCTLR_EL12, x1
+-- 
+2.53.0
+
diff --git a/queue-6.6/arm64-revamp-hcr_el2.e2h-res1-detection.patch b/queue-6.6/arm64-revamp-hcr_el2.e2h-res1-detection.patch
new file mode 100644 (file)
index 0000000..4055b95
--- /dev/null
@@ -0,0 +1,113 @@
+From 820ad08c8680c42de17c2470541a1d68b6937375 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:03 +0000
+Subject: arm64: Revamp HCR_EL2.E2H RES1 detection
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit ca88ecdce5f51874a7c151809bd2c936ee0d3805 ]
+
+We currently have two ways to identify CPUs that only implement FEAT_VHE
+and not FEAT_E2H0:
+
+- either they advertise it via ID_AA64MMFR4_EL1.E2H0,
+- or the HCR_EL2.E2H bit is RAO/WI
+
+However, there is a third category of "cpus" that fall between these
+two cases: on CPUs that do not implement FEAT_FGT, it is IMPDEF whether
+an access to ID_AA64MMFR4_EL1 can trap to EL2 when the register value
+is zero.
+
+A consequence of this is that on systems such as Neoverse V2, a NV
+guest cannot reliably detect that it is in a VHE-only configuration
+(E2H is writable, and ID_AA64MMFR0_EL1 is 0), despite the hypervisor's
+best effort to repaint the id register.
+
+Replace the RAO/WI test by a sequence that makes use of the VHE
+register remnapping between EL1 and EL2 to detect this situation,
+and work out whether we get the VHE behaviour even after having
+set HCR_EL2.E2H to 0.
+
+This solves the NV problem, and provides a more reliable acid test
+for CPUs that do not completely follow the letter of the architecture
+while providing a RES1 behaviour for HCR_EL2.E2H.
+
+Suggested-by: Mark Rutland <mark.rutland@arm.com>
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Acked-by: Catalin Marinas <catalin.marinas@arm.com>
+Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
+Tested-by: Jan Kotas <jank@cadence.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Link: https://lore.kernel.org/r/15A85F2B-1A0C-4FA7-9FE4-EEC2203CC09E@global.cadence.com
+
+[ Backport: Resolved conflict in arch/arm64/include/asm/el2_setup.h
+  by replacing msr_hcr_el2 macro usages with raw msr hcr_el2 (since
+  the macro is missing in 6.6.y). ]
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/el2_setup.h | 38 +++++++++++++++++++++++++-----
+ 1 file changed, 32 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
+index 76b0d50d286d59..4c7467b382b608 100644
+--- a/arch/arm64/include/asm/el2_setup.h
++++ b/arch/arm64/include/asm/el2_setup.h
+@@ -24,22 +24,48 @@
+        * ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
+        * can reset into an UNKNOWN state and might not read as 1 until it has
+        * been initialized explicitly.
+-       *
+-       * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
+-       * don't advertise it (they predate this relaxation).
+-       *
+        * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
+        * indicating whether the CPU is running in E2H mode.
+        */
+       mrs_s   x1, SYS_ID_AA64MMFR4_EL1
+       sbfx    x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
+       cmp     x1, #0
+-      b.ge    .LnVHE_\@
++      b.lt    .LnE2H0_\@
++      /*
++       * Unfortunately, HCR_EL2.E2H can be RES1 even if not advertised
++       * as such via ID_AA64MMFR4_EL1.E2H0:
++       *
++       * - Fruity CPUs predate the !FEAT_E2H0 relaxation, and seem to
++       *   have HCR_EL2.E2H implemented as RAO/WI.
++       *
++       * - On CPUs that lack FEAT_FGT, a hypervisor can't trap guest
++       *   reads of ID_AA64MMFR4_EL1 to advertise !FEAT_E2H0. NV
++       *   guests on these hosts can write to HCR_EL2.E2H without
++       *   trapping to the hypervisor, but these writes have no
++       *   functional effect.
++       *
++       * Handle both cases by checking for an essential VHE property
++       * (system register remapping) to decide whether we're
++       * effectively VHE-only or not.
++       */
++      msr     hcr_el2, x0             // Setup HCR_EL2 as nVHE
++      isb
++      mov     x1, #1          // Write something to FAR_EL1
++      msr     far_el1, x1
++      isb
++      mov     x1, #2          // Try to overwrite it via FAR_EL2
++      msr     far_el2, x1
++      isb
++      mrs     x1, far_el1     // If we see the latest write in FAR_EL1,
++      cmp     x1, #2          // we can safely assume we are VHE only.
++      b.ne    .LnVHE_\@       // Otherwise, we know that nVHE works.
++
++.LnE2H0_\@:
+       orr     x0, x0, #HCR_E2H
+-.LnVHE_\@:
+       msr     hcr_el2, x0
+       isb
++.LnVHE_\@:
+ .endm
+ .macro __init_el2_sctlr
+-- 
+2.53.0
+
diff --git a/queue-6.6/arm64-sysreg-add-layout-for-id_aa64mmfr4_el1.patch b/queue-6.6/arm64-sysreg-add-layout-for-id_aa64mmfr4_el1.patch
new file mode 100644 (file)
index 0000000..249a4f8
--- /dev/null
@@ -0,0 +1,78 @@
+From eae585cefd26bee9a9c7bf93127f942fe74fecf2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:35:58 +0000
+Subject: arm64: sysreg: Add layout for ID_AA64MMFR4_EL1
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit cfc680bb04c54e61faa51a34d8383a0aa25b583f ]
+
+ARMv9.5 has infroduced ID_AA64MMFR4_EL1 with a bunch of new features.
+Add the corresponding layout.
+
+This is extracted from the public ARM SysReg_xml_A_profile-2023-09
+delivery, timestamped d55f5af8e09052abe92a02adf820deea2eaed717.
+
+Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Reviewed-by: Miguel Luis <miguel.luis@oracle.com>
+Link: https://lore.kernel.org/r/20240122181344.258974-5-maz@kernel.org
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/tools/sysreg | 37 +++++++++++++++++++++++++++++++++++++
+ 1 file changed, 37 insertions(+)
+
+diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
+index 76ce150e7347e5..f7180d391f829f 100644
+--- a/arch/arm64/tools/sysreg
++++ b/arch/arm64/tools/sysreg
+@@ -1669,6 +1669,43 @@ UnsignedEnum    3:0     TCRX
+ EndEnum
+ EndSysreg
++Sysreg        ID_AA64MMFR4_EL1        3       0       0       7       4
++Res0  63:40
++UnsignedEnum  39:36   E3DSE
++      0b0000  NI
++      0b0001  IMP
++EndEnum
++Res0  35:28
++SignedEnum    27:24   E2H0
++      0b0000  IMP
++      0b1110  NI_NV1
++      0b1111  NI
++EndEnum
++UnsignedEnum  23:20   NV_frac
++      0b0000  NV_NV2
++      0b0001  NV2_ONLY
++EndEnum
++UnsignedEnum  19:16   FGWTE3
++      0b0000  NI
++      0b0001  IMP
++EndEnum
++UnsignedEnum  15:12   HACDBS
++      0b0000  NI
++      0b0001  IMP
++EndEnum
++UnsignedEnum  11:8    ASID2
++      0b0000  NI
++      0b0001  IMP
++EndEnum
++SignedEnum    7:4     EIESB
++      0b0000  NI
++      0b0001  ToEL3
++      0b0010  ToELx
++      0b1111  ANY
++EndEnum
++Res0  3:0
++EndSysreg
++
+ Sysreg        SCTLR_EL1       3       0       1       0       0
+ Field 63      TIDCP
+ Field 62      SPINTMASK
+-- 
+2.53.0
+
diff --git a/queue-6.6/arm64-sysreg-correct-sign-definitions-for-eiesb-and-.patch b/queue-6.6/arm64-sysreg-correct-sign-definitions-for-eiesb-and-.patch
new file mode 100644 (file)
index 0000000..e1a1518
--- /dev/null
@@ -0,0 +1,53 @@
+From 4d28c6b03345d42076b2cd50522ac3ff5de150e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 29 Aug 2025 10:51:42 +0100
+Subject: arm64: sysreg: Correct sign definitions for EIESB and DoubleLock
+
+From: Fuad Tabba <tabba@google.com>
+
+[ Upstream commit f4d4ebc84995178273740f3e601e97fdefc561d2 ]
+
+The `ID_AA64MMFR4_EL1.EIESB` field, is an unsigned enumeration, but was
+incorrectly defined as a `SignedEnum` when introduced in commit
+cfc680bb04c5 ("arm64: sysreg: Add layout for ID_AA64MMFR4_EL1"). This is
+corrected to `UnsignedEnum`.
+
+Conversely, the `ID_AA64DFR0_EL1.DoubleLock` field, is a signed
+enumeration, but was incorrectly defined as an `UnsignedEnum`. This is
+corrected to `SignedEnum`, which wasn't correctly set when annotated as
+such in commit ad16d4cf0b4f ("arm64/sysreg: Initial unsigned annotations
+for ID registers").
+
+Signed-off-by: Fuad Tabba <tabba@google.com>
+Acked-by: Mark Rutland <mark.rutland@arm.com>
+Signed-off-by: Will Deacon <will@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/tools/sysreg | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm64/tools/sysreg b/arch/arm64/tools/sysreg
+index f7180d391f829f..43089787196bad 100644
+--- a/arch/arm64/tools/sysreg
++++ b/arch/arm64/tools/sysreg
+@@ -1130,7 +1130,7 @@ UnsignedEnum     43:40   TraceFilt
+       0b0000  NI
+       0b0001  IMP
+ EndEnum
+-UnsignedEnum  39:36   DoubleLock
++SignedEnum    39:36   DoubleLock
+       0b0000  IMP
+       0b1111  NI
+ EndEnum
+@@ -1697,7 +1697,7 @@ UnsignedEnum     11:8    ASID2
+       0b0000  NI
+       0b0001  IMP
+ EndEnum
+-SignedEnum    7:4     EIESB
++UnsignedEnum  7:4     EIESB
+       0b0000  NI
+       0b0001  ToEL3
+       0b0010  ToELx
+-- 
+2.53.0
+
diff --git a/queue-6.6/arm64-treat-hcr_el2.e2h-as-res1-when-id_aa64mmfr4_el.patch b/queue-6.6/arm64-treat-hcr_el2.e2h-as-res1-when-id_aa64mmfr4_el.patch
new file mode 100644 (file)
index 0000000..9376353
--- /dev/null
@@ -0,0 +1,75 @@
+From f1de5423d12f895e07cc6891613229f018e70a6c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:35:59 +0000
+Subject: arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is
+ negative
+
+From: Marc Zyngier <maz@kernel.org>
+
+[ Upstream commit 3944382fa6f22b54fd399632b1af92c28123979b ]
+
+For CPUs that have ID_AA64MMFR4_EL1.E2H0 as negative, it is important
+to avoid the boot path that sets HCR_EL2.E2H=0. Fortunately, we
+already have this path to cope with fruity CPUs.
+
+Tweak init_el2 to look at ID_AA64MMFR4_EL1.E2H0 first.
+
+Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
+Link: https://lore.kernel.org/r/20240122181344.258974-8-maz@kernel.org
+Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/kernel/head.S | 23 +++++++++++++++--------
+ 1 file changed, 15 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index 6517bf2644a08b..e32c8dd0b17a77 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -589,25 +589,32 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+       mov_q   x1, INIT_SCTLR_EL1_MMU_OFF
+       /*
+-       * Fruity CPUs seem to have HCR_EL2.E2H set to RES1,
+-       * making it impossible to start in nVHE mode. Is that
+-       * compliant with the architecture? Absolutely not!
++       * Compliant CPUs advertise their VHE-onlyness with
++       * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
++       * RES1 in that case.
++       *
++       * Fruity CPUs seem to have HCR_EL2.E2H set to RES1, but
++       * don't advertise it (they predate this relaxation).
+        */
++      mrs_s   x0, SYS_ID_AA64MMFR4_EL1
++      ubfx    x0, x0, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
++      tbnz    x0, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
++
+       mrs     x0, hcr_el2
+       and     x0, x0, #HCR_E2H
+-      cbz     x0, 1f
+-
++      cbz     x0, 2f
++1:
+       /* Set a sane SCTLR_EL1, the VHE way */
+       pre_disable_mmu_workaround
+       msr_s   SYS_SCTLR_EL12, x1
+       mov     x2, #BOOT_CPU_FLAG_E2H
+-      b       2f
++      b       3f
+-1:
++2:
+       pre_disable_mmu_workaround
+       msr     sctlr_el1, x1
+       mov     x2, xzr
+-2:
++3:
+       __init_el2_nvhe_prepare_eret
+       mov     w0, #BOOT_CPU_MODE_EL2
+-- 
+2.53.0
+
diff --git a/queue-6.6/crypto-talitos-fix-sec1-32k-ahash-request-limitation.patch b/queue-6.6/crypto-talitos-fix-sec1-32k-ahash-request-limitation.patch
new file mode 100644 (file)
index 0000000..de6602a
--- /dev/null
@@ -0,0 +1,362 @@
+From 8b29c044e1ae8a35b483b0978e6fbb4c0976ea30 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:55 +0200
+Subject: crypto: talitos - fix SEC1 32k ahash request limitation
+
+From: Paul Louvel <paul.louvel@bootlin.com>
+
+commit 655ef638a2bc3cd0a9eff99a02f83cab94a3a917 upstream.
+
+Since commit c662b043cdca ("crypto: af_alg/hash: Support
+MSG_SPLICE_PAGES"), the crypto core may pass large scatterlists spanning
+multiple pages to drivers supporting ahash operations. As a result, a
+driver can now receive large ahash requests.
+
+The SEC1 engine has a limitation where a single descriptor cannot
+process more than 32k of data. The current implementation attempts to
+handle the entire request within a single descriptor, which leads to
+failures raised by the driver:
+
+  "length exceeds h/w max limit"
+
+Address this limitation by splitting large ahash requests into multiple
+descriptors, each respecting the 32k hardware limit. This allows
+processing arbitrarily large requests.
+
+Cc: stable@vger.kernel.org
+Fixes: c662b043cdca ("crypto: af_alg/hash: Support MSG_SPLICE_PAGES")
+Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 216 ++++++++++++++++++++++++++-------------
+ 1 file changed, 147 insertions(+), 69 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index a941ec08817eb4..ea6ae72c71ad62 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -12,6 +12,7 @@
+  * All rights reserved.
+  */
++#include <linux/workqueue.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+@@ -870,10 +871,18 @@ struct talitos_ahash_req_ctx {
+       unsigned int swinit;
+       unsigned int first;
+       unsigned int last;
++      unsigned int last_request;
+       unsigned int to_hash_later;
+       unsigned int nbuf;
+       struct scatterlist bufsl[2];
+       struct scatterlist *psrc;
++
++      struct scatterlist request_bufsl[2];
++      struct ahash_request *areq;
++      struct scatterlist *request_sl;
++      unsigned int remaining_ahash_request_bytes;
++      unsigned int current_ahash_request_bytes;
++      struct work_struct sec1_ahash_process_remaining;
+ };
+ struct talitos_export_state {
+@@ -1759,7 +1768,20 @@ static void ahash_done(struct device *dev,
+       kfree(edesc);
+-      ahash_request_complete(areq, err);
++      if (err) {
++              ahash_request_complete(areq, err);
++              return;
++      }
++
++      req_ctx->remaining_ahash_request_bytes -=
++              req_ctx->current_ahash_request_bytes;
++
++      if (!req_ctx->remaining_ahash_request_bytes) {
++              ahash_request_complete(areq, 0);
++              return;
++      }
++
++      schedule_work(&req_ctx->sec1_ahash_process_remaining);
+ }
+ /*
+@@ -1925,60 +1947,7 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
+                                  nbytes, 0, 0, 0, areq->base.flags, false);
+ }
+-static int ahash_init(struct ahash_request *areq)
+-{
+-      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+-      struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+-      struct device *dev = ctx->dev;
+-      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      unsigned int size;
+-      dma_addr_t dma;
+-
+-      /* Initialize the context */
+-      req_ctx->buf_idx = 0;
+-      req_ctx->nbuf = 0;
+-      req_ctx->first = 1; /* first indicates h/w must init its context */
+-      req_ctx->swinit = 0; /* assume h/w init of context */
+-      size =  (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+-                      ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+-                      : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+-      req_ctx->hw_context_size = size;
+-
+-      dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+-                           DMA_TO_DEVICE);
+-      dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
+-
+-      return 0;
+-}
+-
+-/*
+- * on h/w without explicit sha224 support, we initialize h/w context
+- * manually with sha224 constants, and tell it to run sha256.
+- */
+-static int ahash_init_sha224_swinit(struct ahash_request *areq)
+-{
+-      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-
+-      req_ctx->hw_context[0] = SHA224_H0;
+-      req_ctx->hw_context[1] = SHA224_H1;
+-      req_ctx->hw_context[2] = SHA224_H2;
+-      req_ctx->hw_context[3] = SHA224_H3;
+-      req_ctx->hw_context[4] = SHA224_H4;
+-      req_ctx->hw_context[5] = SHA224_H5;
+-      req_ctx->hw_context[6] = SHA224_H6;
+-      req_ctx->hw_context[7] = SHA224_H7;
+-
+-      /* init 64-bit count */
+-      req_ctx->hw_context[8] = 0;
+-      req_ctx->hw_context[9] = 0;
+-
+-      ahash_init(areq);
+-      req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
+-
+-      return 0;
+-}
+-
+-static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
++static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes)
+ {
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+@@ -1997,12 +1966,12 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+       if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+               /* Buffer up to one whole block */
+-              nents = sg_nents_for_len(areq->src, nbytes);
++              nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+               if (nents < 0) {
+                       dev_err(dev, "Invalid number of src SG.\n");
+                       return nents;
+               }
+-              sg_copy_to_buffer(areq->src, nents,
++              sg_copy_to_buffer(req_ctx->request_sl, nents,
+                                 ctx_buf + req_ctx->nbuf, nbytes);
+               req_ctx->nbuf += nbytes;
+               return 0;
+@@ -2029,7 +1998,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+               sg_init_table(req_ctx->bufsl, nsg);
+               sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
+               if (nsg > 1)
+-                      sg_chain(req_ctx->bufsl, 2, areq->src);
++                      sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl);
+               req_ctx->psrc = req_ctx->bufsl;
+       } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
+               int offset;
+@@ -2038,26 +2007,26 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+                       offset = blocksize - req_ctx->nbuf;
+               else
+                       offset = nbytes_to_hash - req_ctx->nbuf;
+-              nents = sg_nents_for_len(areq->src, offset);
++              nents = sg_nents_for_len(req_ctx->request_sl, offset);
+               if (nents < 0) {
+                       dev_err(dev, "Invalid number of src SG.\n");
+                       return nents;
+               }
+-              sg_copy_to_buffer(areq->src, nents,
++              sg_copy_to_buffer(req_ctx->request_sl, nents,
+                                 ctx_buf + req_ctx->nbuf, offset);
+               req_ctx->nbuf += offset;
+-              req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src,
++              req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, req_ctx->request_sl,
+                                                offset);
+       } else
+-              req_ctx->psrc = areq->src;
++              req_ctx->psrc = req_ctx->request_sl;
+       if (to_hash_later) {
+-              nents = sg_nents_for_len(areq->src, nbytes);
++              nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+               if (nents < 0) {
+                       dev_err(dev, "Invalid number of src SG.\n");
+                       return nents;
+               }
+-              sg_pcopy_to_buffer(areq->src, nents,
++              sg_pcopy_to_buffer(req_ctx->request_sl, nents,
+                                  req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
+                                     to_hash_later,
+                                     nbytes - to_hash_later);
+@@ -2065,7 +2034,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+       req_ctx->to_hash_later = to_hash_later;
+       /* Allocate extended descriptor */
+-      edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
++      edesc = ahash_edesc_alloc(req_ctx->areq, nbytes_to_hash);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+@@ -2087,14 +2056,123 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+       if (ctx->keylen && (req_ctx->first || req_ctx->last))
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+-      return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done);
++      return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+ }
+-static int ahash_update(struct ahash_request *areq)
++static void sec1_ahash_process_remaining(struct work_struct *work)
++{
++      struct talitos_ahash_req_ctx *req_ctx =
++              container_of(work, struct talitos_ahash_req_ctx,
++                           sec1_ahash_process_remaining);
++      int err = 0;
++
++      req_ctx->request_sl = scatterwalk_ffwd(req_ctx->request_bufsl,
++                                             req_ctx->request_sl, TALITOS1_MAX_DATA_LEN);
++
++      if (req_ctx->remaining_ahash_request_bytes > TALITOS1_MAX_DATA_LEN)
++              req_ctx->current_ahash_request_bytes = TALITOS1_MAX_DATA_LEN;
++      else {
++              req_ctx->current_ahash_request_bytes =
++                      req_ctx->remaining_ahash_request_bytes;
++
++              if (req_ctx->last_request)
++                      req_ctx->last = 1;
++      }
++
++      err = ahash_process_req_one(req_ctx->areq,
++                                  req_ctx->current_ahash_request_bytes);
++
++      if (err != -EINPROGRESS)
++              ahash_request_complete(req_ctx->areq, err);
++}
++
++static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct device *dev = ctx->dev;
++      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++      struct talitos_private *priv = dev_get_drvdata(dev);
++      bool is_sec1 = has_ftr_sec1(priv);
++
++      req_ctx->areq = areq;
++      req_ctx->request_sl = areq->src;
++      req_ctx->remaining_ahash_request_bytes = nbytes;
++
++      if (is_sec1) {
++              if (nbytes > TALITOS1_MAX_DATA_LEN)
++                      nbytes = TALITOS1_MAX_DATA_LEN;
++              else if (req_ctx->last_request)
++                      req_ctx->last = 1;
++      }
++
++      req_ctx->current_ahash_request_bytes = nbytes;
++
++      return ahash_process_req_one(req_ctx->areq,
++                                   req_ctx->current_ahash_request_bytes);
++}
++
++static int ahash_init(struct ahash_request *areq)
+ {
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct device *dev = ctx->dev;
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++      unsigned int size;
++      dma_addr_t dma;
++      /* Initialize the context */
++      req_ctx->buf_idx = 0;
++      req_ctx->nbuf = 0;
++      req_ctx->first = 1; /* first indicates h/w must init its context */
++      req_ctx->swinit = 0; /* assume h/w init of context */
++      size =  (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
++                      ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
++                      : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
++      req_ctx->hw_context_size = size;
++      req_ctx->last_request = 0;
+       req_ctx->last = 0;
++      INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
++
++      dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
++                           DMA_TO_DEVICE);
++      dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
++
++      return 0;
++}
++
++/*
++ * on h/w without explicit sha224 support, we initialize h/w context
++ * manually with sha224 constants, and tell it to run sha256.
++ */
++static int ahash_init_sha224_swinit(struct ahash_request *areq)
++{
++      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++
++      req_ctx->hw_context[0] = SHA224_H0;
++      req_ctx->hw_context[1] = SHA224_H1;
++      req_ctx->hw_context[2] = SHA224_H2;
++      req_ctx->hw_context[3] = SHA224_H3;
++      req_ctx->hw_context[4] = SHA224_H4;
++      req_ctx->hw_context[5] = SHA224_H5;
++      req_ctx->hw_context[6] = SHA224_H6;
++      req_ctx->hw_context[7] = SHA224_H7;
++
++      /* init 64-bit count */
++      req_ctx->hw_context[8] = 0;
++      req_ctx->hw_context[9] = 0;
++
++      ahash_init(areq);
++      req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
++
++      return 0;
++}
++
++static int ahash_update(struct ahash_request *areq)
++{
++      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++
++      req_ctx->last_request = 0;
+       return ahash_process_req(areq, areq->nbytes);
+ }
+@@ -2103,7 +2181,7 @@ static int ahash_final(struct ahash_request *areq)
+ {
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      req_ctx->last = 1;
++      req_ctx->last_request = 1;
+       return ahash_process_req(areq, 0);
+ }
+@@ -2112,7 +2190,7 @@ static int ahash_finup(struct ahash_request *areq)
+ {
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      req_ctx->last = 1;
++      req_ctx->last_request = 1;
+       return ahash_process_req(areq, areq->nbytes);
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.6/crypto-talitos-rename-first-last-to-first_desc-last_.patch b/queue-6.6/crypto-talitos-rename-first-last-to-first_desc-last_.patch
new file mode 100644 (file)
index 0000000..1d1659c
--- /dev/null
@@ -0,0 +1,204 @@
+From 7ff3d5875ff4b2fe27b3e8dcb5b61b923684457b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:56 +0200
+Subject: crypto: talitos - rename first/last to first_desc/last_desc
+
+From: Paul Louvel <paul.louvel@bootlin.com>
+
+commit a1b80018b8cec27fc06a8b04a7f8b5f6cfe86eae upstream.
+
+Previous commit introduces a new last_request variable in the context
+structure.
+
+Renaming the first/last existing member variable in the context
+structure to improve readability.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 46 ++++++++++++++++++++--------------------
+ 1 file changed, 23 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index ea6ae72c71ad62..fb1adc2956b899 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -869,8 +869,8 @@ struct talitos_ahash_req_ctx {
+       u8 buf[2][HASH_MAX_BLOCK_SIZE];
+       int buf_idx;
+       unsigned int swinit;
+-      unsigned int first;
+-      unsigned int last;
++      unsigned int first_desc;
++      unsigned int last_desc;
+       unsigned int last_request;
+       unsigned int to_hash_later;
+       unsigned int nbuf;
+@@ -889,8 +889,8 @@ struct talitos_export_state {
+       u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
+       u8 buf[HASH_MAX_BLOCK_SIZE];
+       unsigned int swinit;
+-      unsigned int first;
+-      unsigned int last;
++      unsigned int first_desc;
++      unsigned int last_desc;
+       unsigned int to_hash_later;
+       unsigned int nbuf;
+ };
+@@ -1722,7 +1722,7 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
+       if (desc->next_desc &&
+           desc->ptr[5].ptr != desc2->ptr[5].ptr)
+               unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
+-      if (req_ctx->last)
++      if (req_ctx->last_desc)
+               memcpy(areq->result, req_ctx->hw_context,
+                      crypto_ahash_digestsize(tfm));
+@@ -1759,7 +1759,7 @@ static void ahash_done(struct device *dev,
+                container_of(desc, struct talitos_edesc, desc);
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      if (!req_ctx->last && req_ctx->to_hash_later) {
++      if (!req_ctx->last_desc && req_ctx->to_hash_later) {
+               /* Position any partial block for next update/final/finup */
+               req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+               req_ctx->nbuf = req_ctx->to_hash_later;
+@@ -1825,7 +1825,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+       /* first DWORD empty */
+       /* hash context in */
+-      if (!req_ctx->first || req_ctx->swinit) {
++      if (!req_ctx->first_desc || req_ctx->swinit) {
+               map_single_talitos_ptr_nosync(dev, &desc->ptr[1],
+                                             req_ctx->hw_context_size,
+                                             req_ctx->hw_context,
+@@ -1833,7 +1833,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+               req_ctx->swinit = 0;
+       }
+       /* Indicate next op is not the first. */
+-      req_ctx->first = 0;
++      req_ctx->first_desc = 0;
+       /* HMAC key */
+       if (ctx->keylen)
+@@ -1866,7 +1866,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+       /* fifth DWORD empty */
+       /* hash/HMAC out -or- hash context out */
+-      if (req_ctx->last)
++      if (req_ctx->last_desc)
+               map_single_talitos_ptr(dev, &desc->ptr[5],
+                                      crypto_ahash_digestsize(tfm),
+                                      req_ctx->hw_context, DMA_FROM_DEVICE);
+@@ -1908,7 +1908,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+               if (sg_count > 1)
+                       sync_needed = true;
+               copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
+-              if (req_ctx->last)
++              if (req_ctx->last_desc)
+                       map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
+                                                     req_ctx->hw_context_size,
+                                                     req_ctx->hw_context,
+@@ -1964,7 +1964,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       bool is_sec1 = has_ftr_sec1(priv);
+       u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
+-      if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
++      if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) {
+               /* Buffer up to one whole block */
+               nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+               if (nents < 0) {
+@@ -1981,7 +1981,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       nbytes_to_hash = nbytes + req_ctx->nbuf;
+       to_hash_later = nbytes_to_hash & (blocksize - 1);
+-      if (req_ctx->last)
++      if (req_ctx->last_desc)
+               to_hash_later = 0;
+       else if (to_hash_later)
+               /* There is a partial block. Hash the full block(s) now */
+@@ -2041,19 +2041,19 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       edesc->desc.hdr = ctx->desc_hdr_template;
+       /* On last one, request SEC to pad; otherwise continue */
+-      if (req_ctx->last)
++      if (req_ctx->last_desc)
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
+       else
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
+       /* request SEC to INIT hash. */
+-      if (req_ctx->first && !req_ctx->swinit)
++      if (req_ctx->first_desc && !req_ctx->swinit)
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
+       /* When the tfm context has a keylen, it's an HMAC.
+        * A first or last (ie. not middle) descriptor must request HMAC.
+        */
+-      if (ctx->keylen && (req_ctx->first || req_ctx->last))
++      if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc))
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+       return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+@@ -2076,7 +2076,7 @@ static void sec1_ahash_process_remaining(struct work_struct *work)
+                       req_ctx->remaining_ahash_request_bytes;
+               if (req_ctx->last_request)
+-                      req_ctx->last = 1;
++                      req_ctx->last_desc = 1;
+       }
+       err = ahash_process_req_one(req_ctx->areq,
+@@ -2103,7 +2103,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+               if (nbytes > TALITOS1_MAX_DATA_LEN)
+                       nbytes = TALITOS1_MAX_DATA_LEN;
+               else if (req_ctx->last_request)
+-                      req_ctx->last = 1;
++                      req_ctx->last_desc = 1;
+       }
+       req_ctx->current_ahash_request_bytes = nbytes;
+@@ -2124,14 +2124,14 @@ static int ahash_init(struct ahash_request *areq)
+       /* Initialize the context */
+       req_ctx->buf_idx = 0;
+       req_ctx->nbuf = 0;
+-      req_ctx->first = 1; /* first indicates h/w must init its context */
++      req_ctx->first_desc = 1; /* first_desc indicates h/w must init its context */
+       req_ctx->swinit = 0; /* assume h/w init of context */
+       size =  (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+                       ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+                       : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+       req_ctx->hw_context_size = size;
+       req_ctx->last_request = 0;
+-      req_ctx->last = 0;
++      req_ctx->last_desc = 0;
+       INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
+       dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+@@ -2224,8 +2224,8 @@ static int ahash_export(struct ahash_request *areq, void *out)
+              req_ctx->hw_context_size);
+       memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
+       export->swinit = req_ctx->swinit;
+-      export->first = req_ctx->first;
+-      export->last = req_ctx->last;
++      export->first_desc = req_ctx->first_desc;
++      export->last_desc = req_ctx->last_desc;
+       export->to_hash_later = req_ctx->to_hash_later;
+       export->nbuf = req_ctx->nbuf;
+@@ -2250,8 +2250,8 @@ static int ahash_import(struct ahash_request *areq, const void *in)
+       memcpy(req_ctx->hw_context, export->hw_context, size);
+       memcpy(req_ctx->buf[0], export->buf, export->nbuf);
+       req_ctx->swinit = export->swinit;
+-      req_ctx->first = export->first;
+-      req_ctx->last = export->last;
++      req_ctx->first_desc = export->first_desc;
++      req_ctx->last_desc = export->last_desc;
+       req_ctx->to_hash_later = export->to_hash_later;
+       req_ctx->nbuf = export->nbuf;
+-- 
+2.53.0
+
diff --git a/queue-6.6/crypto-talitos-stop-using-crypto_ahash-init.patch b/queue-6.6/crypto-talitos-stop-using-crypto_ahash-init.patch
new file mode 100644 (file)
index 0000000..021c039
--- /dev/null
@@ -0,0 +1,62 @@
+From ede435a73fd99dc97049244c271c9ea42bb1cad3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:54 +0200
+Subject: crypto: talitos - stop using crypto_ahash::init
+
+From: Eric Biggers <ebiggers@google.com>
+
+commit 9826d1d6ed5f86cb3d61610b3b1fe31e96a40418 upstream.
+
+The function pointer crypto_ahash::init is an internal implementation
+detail of the ahash API that exists to help it support both ahash and
+shash algorithms.  With an upcoming refactoring of how the ahash API
+supports shash algorithms, this field will be removed.
+
+Some drivers are invoking crypto_ahash::init to call into their own
+code, which is unnecessary and inefficient.  The talitos driver is one
+of those drivers.  Make it just call its own code directly.
+
+Signed-off-by: Eric Biggers <ebiggers@google.com>
+Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index 4ca4fbd227bce1..a941ec08817eb4 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -2119,13 +2119,14 @@ static int ahash_finup(struct ahash_request *areq)
+ static int ahash_digest(struct ahash_request *areq)
+ {
+-      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      struct crypto_ahash *ahash = crypto_ahash_reqtfm(areq);
+-
+-      ahash->init(areq);
+-      req_ctx->last = 1;
++      ahash_init(areq);
++      return ahash_finup(areq);
++}
+-      return ahash_process_req(areq, areq->nbytes);
++static int ahash_digest_sha224_swinit(struct ahash_request *areq)
++{
++      ahash_init_sha224_swinit(areq);
++      return ahash_finup(areq);
+ }
+ static int ahash_export(struct ahash_request *areq, void *out)
+@@ -3242,6 +3243,8 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev,
+                   (!strcmp(alg->cra_name, "sha224") ||
+                    !strcmp(alg->cra_name, "hmac(sha224)"))) {
+                       t_alg->algt.alg.hash.init = ahash_init_sha224_swinit;
++                      t_alg->algt.alg.hash.digest =
++                              ahash_digest_sha224_swinit;
+                       t_alg->algt.desc_hdr_template =
+                                       DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
+                                       DESC_HDR_SEL0_MDEUA |
+-- 
+2.53.0
+
diff --git a/queue-6.6/kvm-arm64-initialize-hcr_el2.e2h-early.patch b/queue-6.6/kvm-arm64-initialize-hcr_el2.e2h-early.patch
new file mode 100644 (file)
index 0000000..ffdd9c8
--- /dev/null
@@ -0,0 +1,145 @@
+From b0b66e90f910d8e1a9ace4a3c328b618d67f08ab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:01 +0000
+Subject: KVM: arm64: Initialize HCR_EL2.E2H early
+
+From: Mark Rutland <mark.rutland@arm.com>
+
+[ Upstream commit 7a68b55ff39b0a1638acb1694c185d49f6077a0d ]
+
+On CPUs without FEAT_E2H0, HCR_EL2.E2H is RES1, but may reset to an
+UNKNOWN value out of reset and consequently may not read as 1 unless it
+has been explicitly initialized.
+
+We handled this for the head.S boot code in commits:
+
+  3944382fa6f22b54 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
+  b3320142f3db9b3f ("arm64: Fix early handling of FEAT_E2H0 not being implemented")
+
+Unfortunately, we forgot to apply a similar fix to the KVM PSCI entry
+points used when relaying CPU_ON, CPU_SUSPEND, and SYSTEM SUSPEND. When
+KVM is entered via these entry points, the value of HCR_EL2.E2H may be
+consumed before it has been initialized (e.g. by the 'init_el2_state'
+macro).
+
+Initialize HCR_EL2.E2H early in these paths such that it can be consumed
+reliably. The existing code in head.S is factored out into a new
+'init_el2_hcr' macro, and this is used in the __kvm_hyp_init_cpu()
+function common to all the relevant PSCI entry points.
+
+For clarity, I've tweaked the assembly used to check whether
+ID_AA64MMFR4_EL1.E2H0 is negative. The bitfield is extracted as a signed
+value, and this is checked with a signed-greater-or-equal (GE) comparison.
+
+As the hyp code will reconfigure HCR_EL2 later in ___kvm_hyp_init(), all
+bits other than E2H are initialized to zero in __kvm_hyp_init_cpu().
+
+Fixes: 3944382fa6f22b54 ("arm64: Treat HCR_EL2.E2H as RES1 when ID_AA64MMFR4_EL1.E2H0 is negative")
+Fixes: b3320142f3db9b3f ("arm64: Fix early handling of FEAT_E2H0 not being implemented")
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Cc: Ahmed Genidi <ahmed.genidi@arm.com>
+Cc: Ben Horgan <ben.horgan@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Leo Yan <leo.yan@arm.com>
+Cc: Marc Zyngier <maz@kernel.org>
+Cc: Oliver Upton <oliver.upton@linux.dev>
+Cc: Will Deacon <will@kernel.org>
+Link: https://lore.kernel.org/r/20250227180526.1204723-2-mark.rutland@arm.com
+[maz: fixed LT->GE thinko]
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+[ Backport: Resolved trivial conflict in arch/arm64/kvm/hyp/nvhe/hyp-init.S
+  caused by __kvm_init_el2_state not existing in 6.6.y (EL2 state is initialized
+  inline via init_el2_state / finalise_el2_state); placed init_el2_hcr 0
+  directly before the inline sequence. ]
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/el2_setup.h | 26 ++++++++++++++++++++++++++
+ arch/arm64/kernel/head.S           | 19 +------------------
+ arch/arm64/kvm/hyp/nvhe/hyp-init.S |  2 ++
+ 3 files changed, 29 insertions(+), 18 deletions(-)
+
+diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
+index b7afaa026842b7..3498dc5d02c188 100644
+--- a/arch/arm64/include/asm/el2_setup.h
++++ b/arch/arm64/include/asm/el2_setup.h
+@@ -16,6 +16,32 @@
+ #include <asm/sysreg.h>
+ #include <linux/irqchip/arm-gic-v3.h>
++.macro init_el2_hcr   val
++      mov_q   x0, \val
++
++      /*
++       * Compliant CPUs advertise their VHE-onlyness with
++       * ID_AA64MMFR4_EL1.E2H0 < 0. On such CPUs HCR_EL2.E2H is RES1, but it
++       * can reset into an UNKNOWN state and might not read as 1 until it has
++       * been initialized explicitly.
++       *
++       * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
++       * don't advertise it (they predate this relaxation).
++       *
++       * Initalize HCR_EL2.E2H so that later code can rely upon HCR_EL2.E2H
++       * indicating whether the CPU is running in E2H mode.
++       */
++      mrs_s   x1, SYS_ID_AA64MMFR4_EL1
++      sbfx    x1, x1, #ID_AA64MMFR4_EL1_E2H0_SHIFT, #ID_AA64MMFR4_EL1_E2H0_WIDTH
++      cmp     x1, #0
++      b.ge    .LnVHE_\@
++
++      orr     x0, x0, #HCR_E2H
++.LnVHE_\@:
++      msr     hcr_el2, x0
++      isb
++.endm
++
+ .macro __init_el2_sctlr
+       mov_q   x0, INIT_SCTLR_EL2_MMU_OFF
+       msr     sctlr_el2, x0
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index e0e710b36da378..ff7769821166a4 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -575,25 +575,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+       msr     sctlr_el2, x0
+       isb
+ 0:
+-      mov_q   x0, HCR_HOST_NVHE_FLAGS
+-
+-      /*
+-       * Compliant CPUs advertise their VHE-onlyness with
+-       * ID_AA64MMFR4_EL1.E2H0 < 0. HCR_EL2.E2H can be
+-       * RES1 in that case. Publish the E2H bit early so that
+-       * it can be picked up by the init_el2_state macro.
+-       *
+-       * Fruity CPUs seem to have HCR_EL2.E2H set to RAO/WI, but
+-       * don't advertise it (they predate this relaxation).
+-       */
+-      mrs_s   x1, SYS_ID_AA64MMFR4_EL1
+-      tbz     x1, #(ID_AA64MMFR4_EL1_E2H0_SHIFT + ID_AA64MMFR4_EL1_E2H0_WIDTH - 1), 1f
+-
+-      orr     x0, x0, #HCR_E2H
+-1:
+-      msr     hcr_el2, x0
+-      isb
++      init_el2_hcr    HCR_HOST_NVHE_FLAGS
+       init_el2_state
+       /* Hypervisor stub */
+diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+index 1cc06e6797bda3..3efa9cfaa9d48d 100644
+--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
++++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+@@ -202,6 +202,8 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
+ 2:    msr     SPsel, #1                       // We want to use SP_EL{1,2}
++      init_el2_hcr    0
++
+       /* Initialize EL2 CPU state to sane values. */
+       init_el2_state                          // Clobbers x0..x2
+       finalise_el2_state
+-- 
+2.53.0
+
diff --git a/queue-6.6/kvm-arm64-initialize-sctlr_el1-in-__kvm_hyp_init_cpu.patch b/queue-6.6/kvm-arm64-initialize-sctlr_el1-in-__kvm_hyp_init_cpu.patch
new file mode 100644 (file)
index 0000000..5ffc440
--- /dev/null
@@ -0,0 +1,116 @@
+From 0d77a47dd1214af477961e83eb4e4671a19a3bef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 22:36:02 +0000
+Subject: KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu()
+
+From: Ahmed Genidi <ahmed.genidi@arm.com>
+
+[ Upstream commit 3855a7b91d42ebf3513b7ccffc44807274978b3d ]
+
+When KVM is in protected mode, host calls to PSCI are proxied via EL2,
+and cold entries from CPU_ON, CPU_SUSPEND, and SYSTEM_SUSPEND bounce
+through __kvm_hyp_init_cpu() at EL2 before entering the host kernel's
+entry point at EL1. While __kvm_hyp_init_cpu() initializes SPSR_EL2 for
+the exception return to EL1, it does not initialize SCTLR_EL1.
+
+Due to this, it's possible to enter EL1 with SCTLR_EL1 in an UNKNOWN
+state. In practice this has been seen to result in kernel crashes after
+CPU_ON as a result of SCTLR_EL1.M being 1 in violation of the initial
+core configuration specified by PSCI.
+
+Fix this by initializing SCTLR_EL1 for cold entry to the host kernel.
+As it's necessary to write to SCTLR_EL12 in VHE mode, this
+initialization is moved into __kvm_host_psci_cpu_entry() where we can
+use write_sysreg_el1().
+
+The remnants of the '__init_el2_nvhe_prepare_eret' macro are folded into
+its only caller, as this is clearer than having the macro.
+
+Fixes: cdf367192766ad11 ("KVM: arm64: Intercept host's CPU_ON SMCs")
+Reported-by: Leo Yan <leo.yan@arm.com>
+Signed-off-by: Ahmed Genidi <ahmed.genidi@arm.com>
+[ Mark: clarify commit message, handle E2H, move to C, remove macro ]
+Signed-off-by: Mark Rutland <mark.rutland@arm.com>
+Cc: Ahmed Genidi <ahmed.genidi@arm.com>
+Cc: Ben Horgan <ben.horgan@arm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Leo Yan <leo.yan@arm.com>
+Cc: Marc Zyngier <maz@kernel.org>
+Cc: Oliver Upton <oliver.upton@linux.dev>
+Cc: Will Deacon <will@kernel.org>
+Reviewed-by: Leo Yan <leo.yan@arm.com>
+Link: https://lore.kernel.org/r/20250227180526.1204723-3-mark.rutland@arm.com
+Signed-off-by: Marc Zyngier <maz@kernel.org>
+[ Backport: Resolved context conflicts when removing the
+  __init_el2_nvhe_prepare_eret macro and invocation:
+  - arch/arm64/include/asm/el2_setup.h: conflicted because 6.6.y lacks later
+    GCS/MPAM macros (__init_el2_gcs / __init_el2_mpam) surrounding the definition.
+  - arch/arm64/kvm/hyp/nvhe/hyp-init.S: conflicted because __kvm_init_el2_state
+    does not exist in 6.6.y (EL2 state is initialized inline). ]
+Signed-off-by: Colton Lewis <coltonlewis@google.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/include/asm/el2_setup.h   | 4 ----
+ arch/arm64/kernel/head.S             | 3 ++-
+ arch/arm64/kvm/hyp/nvhe/hyp-init.S   | 1 -
+ arch/arm64/kvm/hyp/nvhe/psci-relay.c | 3 +++
+ 4 files changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
+index 3498dc5d02c188..76b0d50d286d59 100644
+--- a/arch/arm64/include/asm/el2_setup.h
++++ b/arch/arm64/include/asm/el2_setup.h
+@@ -229,10 +229,6 @@
+ .Lskip_fgt_\@:
+ .endm
+-.macro __init_el2_nvhe_prepare_eret
+-      mov     x0, #INIT_PSTATE_EL1
+-      msr     spsr_el2, x0
+-.endm
+ /**
+  * Initialize EL2 registers to sane values. This should be called early on all
+diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
+index ff7769821166a4..9996029853d236 100644
+--- a/arch/arm64/kernel/head.S
++++ b/arch/arm64/kernel/head.S
+@@ -601,7 +601,8 @@ SYM_INNER_LABEL(init_el2, SYM_L_LOCAL)
+       msr     sctlr_el1, x1
+       mov     x2, xzr
+ 3:
+-      __init_el2_nvhe_prepare_eret
++      mov     x0, #INIT_PSTATE_EL1
++      msr     spsr_el2, x0
+       mov     w0, #BOOT_CPU_MODE_EL2
+       orr     x0, x0, x2
+diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-init.S b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+index 3efa9cfaa9d48d..9b2ada54be5384 100644
+--- a/arch/arm64/kvm/hyp/nvhe/hyp-init.S
++++ b/arch/arm64/kvm/hyp/nvhe/hyp-init.S
+@@ -207,7 +207,6 @@ SYM_CODE_START_LOCAL(__kvm_hyp_init_cpu)
+       /* Initialize EL2 CPU state to sane values. */
+       init_el2_state                          // Clobbers x0..x2
+       finalise_el2_state
+-      __init_el2_nvhe_prepare_eret
+       /* Enable MMU, set vectors and stack. */
+       mov     x0, x28
+diff --git a/arch/arm64/kvm/hyp/nvhe/psci-relay.c b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
+index d57bcb6ab94d25..5688a16e2ea75d 100644
+--- a/arch/arm64/kvm/hyp/nvhe/psci-relay.c
++++ b/arch/arm64/kvm/hyp/nvhe/psci-relay.c
+@@ -218,6 +218,9 @@ asmlinkage void __noreturn __kvm_host_psci_cpu_entry(bool is_cpu_on)
+       if (is_cpu_on)
+               release_boot_args(boot_args);
++      write_sysreg_el1(INIT_SCTLR_EL1_MMU_OFF, SYS_SCTLR);
++      write_sysreg(INIT_PSTATE_EL1, SPSR_EL2);
++
+       __host_enter(host_ctxt);
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.6/loongarch-add-pio-for-early-access-before-acpi-pci-r.patch b/queue-6.6/loongarch-add-pio-for-early-access-before-acpi-pci-r.patch
new file mode 100644 (file)
index 0000000..8ba05af
--- /dev/null
@@ -0,0 +1,117 @@
+From babac320fef51d3733e78497cf3a44ee5ed4b031 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 20:26:13 +0800
+Subject: LoongArch: Add PIO for early access before ACPI PCI root register
+
+From: Huacai Chen <chenhuacai@loongson.cn>
+
+commit 6061e65f95713b01f4313cda6637dfe3aa5412b4 upstream.
+
+For ACPI system we suppose the ISA/LPC PIO range is registered together
+with PCI root bridge. But the fact is there may be some early access to
+the ISA/LPC PIO range before ACPI PCI root register (most of them are
+due to abnormal BIOS). Unconditionally register the ISA/LPC PIO range
+usually causes ACPI PCI root register fail because of the address range
+confliction. So we add a pair of helpers: acpi_add_early_pio() to add
+PIO for early access, and acpi_remove_early_pio() to remove PIO before
+PCI root register. Since acpi_remove_early_pio() may be called multiple
+times, we add an acpi_pio flag to ensure PIO be removed only once.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/loongarch/include/asm/acpi.h |  2 ++
+ arch/loongarch/kernel/acpi.c      | 28 ++++++++++++++++++++++++++++
+ arch/loongarch/kernel/setup.c     |  2 ++
+ arch/loongarch/pci/acpi.c         |  2 ++
+ 4 files changed, 34 insertions(+)
+
+diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
+index 49e29b29996f0f..4f31109714c0ab 100644
+--- a/arch/loongarch/include/asm/acpi.h
++++ b/arch/loongarch/include/asm/acpi.h
+@@ -37,6 +37,8 @@ static inline bool acpi_has_cpu_in_madt(void)
+ extern struct list_head acpi_wakeup_device_list;
+ extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
++extern void acpi_add_early_pio(void);
++extern void acpi_remove_early_pio(void);
+ extern int __init parse_acpi_topology(void);
+ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
+diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
+index 1f529b13490b3b..34101b753eaac3 100644
+--- a/arch/loongarch/kernel/acpi.c
++++ b/arch/loongarch/kernel/acpi.c
+@@ -14,6 +14,7 @@
+ #include <linux/memblock.h>
+ #include <linux/of_fdt.h>
+ #include <linux/serial_core.h>
++#include <linux/vmalloc.h>
+ #include <asm/io.h>
+ #include <asm/numa.h>
+ #include <asm/loongson.h>
+@@ -57,6 +58,33 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+               return ioremap_cache(phys, size);
+ }
++#define PIO_BASE (unsigned long)PCI_IOBASE
++#define PIO_SIZE ALIGN(ISA_IOSIZE, PAGE_SIZE)
++
++static bool acpi_pio;
++
++/* Add PIO for early access */
++void acpi_add_early_pio(void)
++{
++      if (!acpi_disabled) {
++              acpi_pio = true;
++              ioremap_page_range(PIO_BASE, PIO_BASE + PIO_SIZE,
++                              LOONGSON_LIO_BASE, pgprot_device(PAGE_KERNEL));
++      }
++}
++
++/* Remove PIO for PCI register */
++void acpi_remove_early_pio(void)
++{
++      if (!acpi_pio)
++              return;
++
++      if (!acpi_disabled) {
++              acpi_pio = false;
++              vunmap_range(PIO_BASE, PIO_BASE + PIO_SIZE);
++      }
++}
++
+ #ifdef CONFIG_SMP
+ static int set_processor_mask(u32 id, u32 flags)
+ {
+diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
+index 2e34ece474eece..729b0660b61c1a 100644
+--- a/arch/loongarch/kernel/setup.c
++++ b/arch/loongarch/kernel/setup.c
+@@ -530,6 +530,8 @@ static __init int arch_reserve_pio_range(void)
+ {
+       struct device_node *np;
++      acpi_add_early_pio();
++
+       for_each_node_by_name(np, "isa") {
+               struct of_range range;
+               struct of_range_parser parser;
+diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
+index 2d584a59a2a049..b53dae9d57c899 100644
+--- a/arch/loongarch/pci/acpi.c
++++ b/arch/loongarch/pci/acpi.c
+@@ -65,6 +65,8 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
+       struct resource_entry *entry, *tmp;
+       struct acpi_device *device = ci->bridge;
++      acpi_remove_early_pio();
++
+       status = acpi_pci_probe_root_resources(ci);
+       if (status > 0) {
+               acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
+-- 
+2.53.0
+
diff --git a/queue-6.6/net-drop-the-lock-in-skb_may_tx_timestamp.patch b/queue-6.6/net-drop-the-lock-in-skb_may_tx_timestamp.patch
new file mode 100644 (file)
index 0000000..35ae856
--- /dev/null
@@ -0,0 +1,118 @@
+From 4cc4b1d9c56de54140d02dd39e66e874f5580aab Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 20:58:16 +0800
+Subject: net: Drop the lock in skb_may_tx_timestamp()
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+commit 983512f3a87fd8dc4c94dfa6b596b6e57df5aad7 upstream.
+
+skb_may_tx_timestamp() may acquire sock::sk_callback_lock. The lock must
+not be taken in IRQ context, only softirq is okay. A few drivers receive
+the timestamp via a dedicated interrupt and complete the TX timestamp
+from that handler. This will lead to a deadlock if the lock is already
+write-locked on the same CPU.
+
+Taking the lock can be avoided. The socket (pointed by the skb) will
+remain valid until the skb is released. The ->sk_socket and ->file
+member will be set to NULL once the user closes the socket which may
+happen before the timestamp arrives.
+If we happen to observe the pointer while the socket is closing but
+before the pointer is set to NULL then we may use it because both
+pointer (and the file's cred member) are RCU freed.
+
+Drop the lock. Use READ_ONCE() to obtain the individual pointer. Add a
+matching WRITE_ONCE() where the pointer are cleared.
+
+Link: https://lore.kernel.org/all/20260205145104.iWinkXHv@linutronix.de
+Fixes: b245be1f4db1a ("net-timestamp: no-payload only sysctl")
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Reviewed-by: Willem de Bruijn <willemb@google.com>
+Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20260220183858.N4ERjFW6@linutronix.de
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ adapted sk_set_socket() in include/net/sock.h to fix the conflict from
+ not having commit 5d6b58c932ec ("net: lockless sock_i_ino()") and the
+ additional previous changes required by it.
+ It comes down to just now having the lines of
+    if (sock) {
+            WRITE_ONCE(sk->sk_uid, SOCK_INODE(sock)->i_uid);
+            WRITE_ONCE(sk->sk_ino, SOCK_INODE(sock)->i_ino);
+    }
+ below the changed line. ]
+Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/sock.h |  2 +-
+ net/core/skbuff.c  | 23 ++++++++++++++++++-----
+ net/socket.c       |  2 +-
+ 3 files changed, 20 insertions(+), 7 deletions(-)
+
+diff --git a/include/net/sock.h b/include/net/sock.h
+index a6944844553afe..c1f129a532b200 100644
+--- a/include/net/sock.h
++++ b/include/net/sock.h
+@@ -2155,7 +2155,7 @@ static inline int sk_rx_queue_get(const struct sock *sk)
+ static inline void sk_set_socket(struct sock *sk, struct socket *sock)
+ {
+-      sk->sk_socket = sock;
++      WRITE_ONCE(sk->sk_socket, sock);
+ }
+ static inline wait_queue_head_t *sk_sleep(struct sock *sk)
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index c5e2ae6d0406bd..732204d99822a2 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -5258,15 +5258,28 @@ static void __skb_complete_tx_timestamp(struct sk_buff *skb,
+ static bool skb_may_tx_timestamp(struct sock *sk, bool tsonly)
+ {
+-      bool ret;
++      struct socket *sock;
++      struct file *file;
++      bool ret = false;
+       if (likely(READ_ONCE(sysctl_tstamp_allow_data) || tsonly))
+               return true;
+-      read_lock_bh(&sk->sk_callback_lock);
+-      ret = sk->sk_socket && sk->sk_socket->file &&
+-            file_ns_capable(sk->sk_socket->file, &init_user_ns, CAP_NET_RAW);
+-      read_unlock_bh(&sk->sk_callback_lock);
++      /* The sk pointer remains valid as long as the skb is. The sk_socket and
++       * file pointer may become NULL if the socket is closed. Both structures
++       * (including file->cred) are RCU freed which means they can be accessed
++       * within a RCU read section.
++       */
++      rcu_read_lock();
++      sock = READ_ONCE(sk->sk_socket);
++      if (!sock)
++              goto out;
++      file = READ_ONCE(sock->file);
++      if (!file)
++              goto out;
++      ret = file_ns_capable(file, &init_user_ns, CAP_NET_RAW);
++out:
++      rcu_read_unlock();
+       return ret;
+ }
+diff --git a/net/socket.c b/net/socket.c
+index fa242d7e51c791..ae31c54664632c 100644
+--- a/net/socket.c
++++ b/net/socket.c
+@@ -671,7 +671,7 @@ static void __sock_release(struct socket *sock, struct inode *inode)
+               iput(SOCK_INODE(sock));
+               return;
+       }
+-      sock->file = NULL;
++      WRITE_ONCE(sock->file, NULL);
+ }
+ /**
+-- 
+2.53.0
+
diff --git a/queue-6.6/perf-core-detach-event-groups-during-remove_on_exec.patch b/queue-6.6/perf-core-detach-event-groups-during-remove_on_exec.patch
new file mode 100644 (file)
index 0000000..a4f168a
--- /dev/null
@@ -0,0 +1,99 @@
+From a492ad32315e54d55173da7f252a0d86e678a0c3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 23:29:58 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 73a86db06cc9b1..d45bce2acdbc75 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4449,7 +4449,8 @@ static void perf_event_enable_on_exec(struct perf_event_context *ctx)
+ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+-                                struct perf_event_context *ctx);
++                                struct perf_event_context *ctx,
++                                unsigned long detach_flags);
+ /*
+  * Removes all events from the current task that have been marked
+@@ -4476,7 +4477,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+               modified = true;
+-              perf_event_exit_event(event, ctx);
++              perf_event_exit_event(event, ctx, DETACH_GROUP);
+       }
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -13230,10 +13231,11 @@ static void sync_child_event(struct perf_event *child_event)
+ }
+ static void
+-perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
++perf_event_exit_event(struct perf_event *event,
++                    struct perf_event_context *ctx,
++                    unsigned long detach_flags)
+ {
+       struct perf_event *parent_event = event->parent;
+-      unsigned long detach_flags = 0;
+       if (parent_event) {
+               /*
+@@ -13248,7 +13250,7 @@ perf_event_exit_event(struct perf_event *event, struct perf_event_context *ctx)
+                * Do destroy all inherited groups, we don't care about those
+                * and being thorough is better.
+                */
+-              detach_flags = DETACH_GROUP | DETACH_CHILD;
++              detach_flags |= DETACH_GROUP | DETACH_CHILD;
+               mutex_lock(&parent_event->child_mutex);
+       }
+@@ -13328,7 +13330,7 @@ static void perf_event_exit_task_context(struct task_struct *child)
+       perf_event_task(child, child_ctx, 0);
+       list_for_each_entry_safe(child_event, next, &child_ctx->event_list, event_entry)
+-              perf_event_exit_event(child_event, child_ctx);
++              perf_event_exit_event(child_event, child_ctx, 0);
+       mutex_unlock(&child_ctx->mutex);
+-- 
+2.53.0
+
diff --git a/queue-6.6/revert-crypto-talitos-fix-sec1-32k-ahash-request-lim.patch b/queue-6.6/revert-crypto-talitos-fix-sec1-32k-ahash-request-lim.patch
new file mode 100644 (file)
index 0000000..d4f206f
--- /dev/null
@@ -0,0 +1,363 @@
+From 287c9c848fbe5458d88c57c8799996e7cad64ba9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:53 +0200
+Subject: Revert "crypto: talitos - fix SEC1 32k ahash request limitation"
+
+From: Goetz Goerisch <ggoerisch@gmail.com>
+
+This reverts commit 00463d5f864ae28b7938d5acd0ddd800d5457e8b.
+Which was backported without applying upstream
+commit 9826d1d6ed5f86cb3d61610b3b1fe31e96a40418 first.
+
+Commit a1b80018b8cec27fc06a8b04a7f8b5f6cfe86eae
+was backported to 6.6.y with a866e2b1c65edaee2e1bb1024ee2c761ced335f8
+It renames last to last_desc but misses one occurrence which leads to compile errors on mpc85xx
+
+drivers/crypto/talitos.c: In function 'ahash_digest':
+drivers/crypto/talitos.c:2204:16: error: 'struct talitos_ahash_req_ctx' has no member named 'last'
+ 2204 | req_ctx->last = 1;
+      |        ^~~~
+
+Instead of renaming req_ctx->last, commit 9826d1d6ed5f8 ("crypto: talitos - stop
+using crypto_ahash::init") should be applied.
+Ideally before commit 00463d5f864a ("crypto: talitos - fix SEC1 32k ahash
+request limitation") to avoid any compilation breakage and ensure correctness of
+the code.
+
+Reverting and applying in correct order.
+
+Link: https://lore.kernel.org/all/DIOA24QU02W5.2RSVK05RE7BJK@bootlin.com/
+Signed-off-by: Goetz Goerisch <ggoerisch@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 216 +++++++++++++--------------------------
+ 1 file changed, 69 insertions(+), 147 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index f78a44f991013b..4ca4fbd227bce1 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -12,7 +12,6 @@
+  * All rights reserved.
+  */
+-#include <linux/workqueue.h>
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/mod_devicetable.h>
+@@ -871,18 +870,10 @@ struct talitos_ahash_req_ctx {
+       unsigned int swinit;
+       unsigned int first;
+       unsigned int last;
+-      unsigned int last_request;
+       unsigned int to_hash_later;
+       unsigned int nbuf;
+       struct scatterlist bufsl[2];
+       struct scatterlist *psrc;
+-
+-      struct scatterlist request_bufsl[2];
+-      struct ahash_request *areq;
+-      struct scatterlist *request_sl;
+-      unsigned int remaining_ahash_request_bytes;
+-      unsigned int current_ahash_request_bytes;
+-      struct work_struct sec1_ahash_process_remaining;
+ };
+ struct talitos_export_state {
+@@ -1768,20 +1759,7 @@ static void ahash_done(struct device *dev,
+       kfree(edesc);
+-      if (err) {
+-              ahash_request_complete(areq, err);
+-              return;
+-      }
+-
+-      req_ctx->remaining_ahash_request_bytes -=
+-              req_ctx->current_ahash_request_bytes;
+-
+-      if (!req_ctx->remaining_ahash_request_bytes) {
+-              ahash_request_complete(areq, 0);
+-              return;
+-      }
+-
+-      schedule_work(&req_ctx->sec1_ahash_process_remaining);
++      ahash_request_complete(areq, err);
+ }
+ /*
+@@ -1947,7 +1925,60 @@ static struct talitos_edesc *ahash_edesc_alloc(struct ahash_request *areq,
+                                  nbytes, 0, 0, 0, areq->base.flags, false);
+ }
+-static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes)
++static int ahash_init(struct ahash_request *areq)
++{
++      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
++      struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
++      struct device *dev = ctx->dev;
++      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++      unsigned int size;
++      dma_addr_t dma;
++
++      /* Initialize the context */
++      req_ctx->buf_idx = 0;
++      req_ctx->nbuf = 0;
++      req_ctx->first = 1; /* first indicates h/w must init its context */
++      req_ctx->swinit = 0; /* assume h/w init of context */
++      size =  (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
++                      ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
++                      : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
++      req_ctx->hw_context_size = size;
++
++      dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
++                           DMA_TO_DEVICE);
++      dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
++
++      return 0;
++}
++
++/*
++ * on h/w without explicit sha224 support, we initialize h/w context
++ * manually with sha224 constants, and tell it to run sha256.
++ */
++static int ahash_init_sha224_swinit(struct ahash_request *areq)
++{
++      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
++
++      req_ctx->hw_context[0] = SHA224_H0;
++      req_ctx->hw_context[1] = SHA224_H1;
++      req_ctx->hw_context[2] = SHA224_H2;
++      req_ctx->hw_context[3] = SHA224_H3;
++      req_ctx->hw_context[4] = SHA224_H4;
++      req_ctx->hw_context[5] = SHA224_H5;
++      req_ctx->hw_context[6] = SHA224_H6;
++      req_ctx->hw_context[7] = SHA224_H7;
++
++      /* init 64-bit count */
++      req_ctx->hw_context[8] = 0;
++      req_ctx->hw_context[9] = 0;
++
++      ahash_init(areq);
++      req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
++
++      return 0;
++}
++
++static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+ {
+       struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+       struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+@@ -1966,12 +1997,12 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+               /* Buffer up to one whole block */
+-              nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
++              nents = sg_nents_for_len(areq->src, nbytes);
+               if (nents < 0) {
+                       dev_err(dev, "Invalid number of src SG.\n");
+                       return nents;
+               }
+-              sg_copy_to_buffer(req_ctx->request_sl, nents,
++              sg_copy_to_buffer(areq->src, nents,
+                                 ctx_buf + req_ctx->nbuf, nbytes);
+               req_ctx->nbuf += nbytes;
+               return 0;
+@@ -1998,7 +2029,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+               sg_init_table(req_ctx->bufsl, nsg);
+               sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
+               if (nsg > 1)
+-                      sg_chain(req_ctx->bufsl, 2, req_ctx->request_sl);
++                      sg_chain(req_ctx->bufsl, 2, areq->src);
+               req_ctx->psrc = req_ctx->bufsl;
+       } else if (is_sec1 && req_ctx->nbuf && req_ctx->nbuf < blocksize) {
+               int offset;
+@@ -2007,26 +2038,26 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+                       offset = blocksize - req_ctx->nbuf;
+               else
+                       offset = nbytes_to_hash - req_ctx->nbuf;
+-              nents = sg_nents_for_len(req_ctx->request_sl, offset);
++              nents = sg_nents_for_len(areq->src, offset);
+               if (nents < 0) {
+                       dev_err(dev, "Invalid number of src SG.\n");
+                       return nents;
+               }
+-              sg_copy_to_buffer(req_ctx->request_sl, nents,
++              sg_copy_to_buffer(areq->src, nents,
+                                 ctx_buf + req_ctx->nbuf, offset);
+               req_ctx->nbuf += offset;
+-              req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, req_ctx->request_sl,
++              req_ctx->psrc = scatterwalk_ffwd(req_ctx->bufsl, areq->src,
+                                                offset);
+       } else
+-              req_ctx->psrc = req_ctx->request_sl;
++              req_ctx->psrc = areq->src;
+       if (to_hash_later) {
+-              nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
++              nents = sg_nents_for_len(areq->src, nbytes);
+               if (nents < 0) {
+                       dev_err(dev, "Invalid number of src SG.\n");
+                       return nents;
+               }
+-              sg_pcopy_to_buffer(req_ctx->request_sl, nents,
++              sg_pcopy_to_buffer(areq->src, nents,
+                                  req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
+                                     to_hash_later,
+                                     nbytes - to_hash_later);
+@@ -2034,7 +2065,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       req_ctx->to_hash_later = to_hash_later;
+       /* Allocate extended descriptor */
+-      edesc = ahash_edesc_alloc(req_ctx->areq, nbytes_to_hash);
++      edesc = ahash_edesc_alloc(areq, nbytes_to_hash);
+       if (IS_ERR(edesc))
+               return PTR_ERR(edesc);
+@@ -2056,123 +2087,14 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       if (ctx->keylen && (req_ctx->first || req_ctx->last))
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+-      return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+-}
+-
+-static void sec1_ahash_process_remaining(struct work_struct *work)
+-{
+-      struct talitos_ahash_req_ctx *req_ctx =
+-              container_of(work, struct talitos_ahash_req_ctx,
+-                           sec1_ahash_process_remaining);
+-      int err = 0;
+-
+-      req_ctx->request_sl = scatterwalk_ffwd(req_ctx->request_bufsl,
+-                                             req_ctx->request_sl, TALITOS1_MAX_DATA_LEN);
+-
+-      if (req_ctx->remaining_ahash_request_bytes > TALITOS1_MAX_DATA_LEN)
+-              req_ctx->current_ahash_request_bytes = TALITOS1_MAX_DATA_LEN;
+-      else {
+-              req_ctx->current_ahash_request_bytes =
+-                      req_ctx->remaining_ahash_request_bytes;
+-
+-              if (req_ctx->last_request)
+-                      req_ctx->last = 1;
+-      }
+-
+-      err = ahash_process_req_one(req_ctx->areq,
+-                                  req_ctx->current_ahash_request_bytes);
+-
+-      if (err != -EINPROGRESS)
+-              ahash_request_complete(req_ctx->areq, err);
+-}
+-
+-static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+-{
+-      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+-      struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+-      struct device *dev = ctx->dev;
+-      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      struct talitos_private *priv = dev_get_drvdata(dev);
+-      bool is_sec1 = has_ftr_sec1(priv);
+-
+-      req_ctx->areq = areq;
+-      req_ctx->request_sl = areq->src;
+-      req_ctx->remaining_ahash_request_bytes = nbytes;
+-
+-      if (is_sec1) {
+-              if (nbytes > TALITOS1_MAX_DATA_LEN)
+-                      nbytes = TALITOS1_MAX_DATA_LEN;
+-              else if (req_ctx->last_request)
+-                      req_ctx->last = 1;
+-      }
+-
+-      req_ctx->current_ahash_request_bytes = nbytes;
+-
+-      return ahash_process_req_one(req_ctx->areq,
+-                                   req_ctx->current_ahash_request_bytes);
+-}
+-
+-static int ahash_init(struct ahash_request *areq)
+-{
+-      struct crypto_ahash *tfm = crypto_ahash_reqtfm(areq);
+-      struct talitos_ctx *ctx = crypto_ahash_ctx(tfm);
+-      struct device *dev = ctx->dev;
+-      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      unsigned int size;
+-      dma_addr_t dma;
+-
+-      /* Initialize the context */
+-      req_ctx->buf_idx = 0;
+-      req_ctx->nbuf = 0;
+-      req_ctx->first = 1; /* first indicates h/w must init its context */
+-      req_ctx->swinit = 0; /* assume h/w init of context */
+-      size =  (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+-                      ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+-                      : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+-      req_ctx->hw_context_size = size;
+-      req_ctx->last_request = 0;
+-      req_ctx->last = 0;
+-      INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
+-
+-      dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+-                           DMA_TO_DEVICE);
+-      dma_unmap_single(dev, dma, req_ctx->hw_context_size, DMA_TO_DEVICE);
+-
+-      return 0;
+-}
+-
+-/*
+- * on h/w without explicit sha224 support, we initialize h/w context
+- * manually with sha224 constants, and tell it to run sha256.
+- */
+-static int ahash_init_sha224_swinit(struct ahash_request *areq)
+-{
+-      struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-
+-      req_ctx->hw_context[0] = SHA224_H0;
+-      req_ctx->hw_context[1] = SHA224_H1;
+-      req_ctx->hw_context[2] = SHA224_H2;
+-      req_ctx->hw_context[3] = SHA224_H3;
+-      req_ctx->hw_context[4] = SHA224_H4;
+-      req_ctx->hw_context[5] = SHA224_H5;
+-      req_ctx->hw_context[6] = SHA224_H6;
+-      req_ctx->hw_context[7] = SHA224_H7;
+-
+-      /* init 64-bit count */
+-      req_ctx->hw_context[8] = 0;
+-      req_ctx->hw_context[9] = 0;
+-
+-      ahash_init(areq);
+-      req_ctx->swinit = 1;/* prevent h/w initting context with sha256 values*/
+-
+-      return 0;
++      return common_nonsnoop_hash(edesc, areq, nbytes_to_hash, ahash_done);
+ }
+ static int ahash_update(struct ahash_request *areq)
+ {
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      req_ctx->last_request = 0;
++      req_ctx->last = 0;
+       return ahash_process_req(areq, areq->nbytes);
+ }
+@@ -2181,7 +2103,7 @@ static int ahash_final(struct ahash_request *areq)
+ {
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      req_ctx->last_request = 1;
++      req_ctx->last = 1;
+       return ahash_process_req(areq, 0);
+ }
+@@ -2190,7 +2112,7 @@ static int ahash_finup(struct ahash_request *areq)
+ {
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      req_ctx->last_request = 1;
++      req_ctx->last = 1;
+       return ahash_process_req(areq, areq->nbytes);
+ }
+-- 
+2.53.0
+
diff --git a/queue-6.6/revert-crypto-talitos-rename-first-last-to-first_des.patch b/queue-6.6/revert-crypto-talitos-rename-first-last-to-first_des.patch
new file mode 100644 (file)
index 0000000..c644a79
--- /dev/null
@@ -0,0 +1,217 @@
+From a18cb66676462286f40ddfc5b4311087e5dec840 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 21:39:52 +0200
+Subject: Revert "crypto: talitos - rename first/last to first_desc/last_desc"
+
+From: Goetz Goerisch <ggoerisch@gmail.com>
+
+This reverts commit a866e2b1c65edaee2e1bb1024ee2c761ced335f8.
+
+Which was backported without applying upstream
+commit 9826d1d6ed5f86cb3d61610b3b1fe31e96a40418 first.
+
+Commit a1b80018b8cec27fc06a8b04a7f8b5f6cfe86eae
+was backported to 6.6.y with a866e2b1c65edaee2e1bb1024ee2c761ced335f8
+It renames last to last_desc but misses one occurrence which leads to compile errors on mpc85xx
+
+drivers/crypto/talitos.c: In function 'ahash_digest':
+drivers/crypto/talitos.c:2204:16: error: 'struct talitos_ahash_req_ctx' has no member named 'last'
+ 2204 | req_ctx->last = 1;
+      |        ^~~~
+
+Instead of renaming req_ctx->last, commit 9826d1d6ed5f8 ("crypto: talitos - stop
+using crypto_ahash::init") should be applied.
+Ideally before commit 00463d5f864a ("crypto: talitos - fix SEC1 32k ahash
+request limitation") to avoid any compilation breakage and ensure correctness of
+the code.
+
+Reverting and applying in correct order.
+
+Link: https://lore.kernel.org/all/DIOA24QU02W5.2RSVK05RE7BJK@bootlin.com/
+Signed-off-by: Goetz Goerisch <ggoerisch@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/crypto/talitos.c | 46 ++++++++++++++++++++--------------------
+ 1 file changed, 23 insertions(+), 23 deletions(-)
+
+diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
+index 347483f6fc5dd6..f78a44f991013b 100644
+--- a/drivers/crypto/talitos.c
++++ b/drivers/crypto/talitos.c
+@@ -869,8 +869,8 @@ struct talitos_ahash_req_ctx {
+       u8 buf[2][HASH_MAX_BLOCK_SIZE];
+       int buf_idx;
+       unsigned int swinit;
+-      unsigned int first_desc;
+-      unsigned int last_desc;
++      unsigned int first;
++      unsigned int last;
+       unsigned int last_request;
+       unsigned int to_hash_later;
+       unsigned int nbuf;
+@@ -889,8 +889,8 @@ struct talitos_export_state {
+       u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
+       u8 buf[HASH_MAX_BLOCK_SIZE];
+       unsigned int swinit;
+-      unsigned int first_desc;
+-      unsigned int last_desc;
++      unsigned int first;
++      unsigned int last;
+       unsigned int to_hash_later;
+       unsigned int nbuf;
+ };
+@@ -1722,7 +1722,7 @@ static void common_nonsnoop_hash_unmap(struct device *dev,
+       if (desc->next_desc &&
+           desc->ptr[5].ptr != desc2->ptr[5].ptr)
+               unmap_single_talitos_ptr(dev, &desc2->ptr[5], DMA_FROM_DEVICE);
+-      if (req_ctx->last_desc)
++      if (req_ctx->last)
+               memcpy(areq->result, req_ctx->hw_context,
+                      crypto_ahash_digestsize(tfm));
+@@ -1759,7 +1759,7 @@ static void ahash_done(struct device *dev,
+                container_of(desc, struct talitos_edesc, desc);
+       struct talitos_ahash_req_ctx *req_ctx = ahash_request_ctx(areq);
+-      if (!req_ctx->last_desc && req_ctx->to_hash_later) {
++      if (!req_ctx->last && req_ctx->to_hash_later) {
+               /* Position any partial block for next update/final/finup */
+               req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
+               req_ctx->nbuf = req_ctx->to_hash_later;
+@@ -1825,7 +1825,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+       /* first DWORD empty */
+       /* hash context in */
+-      if (!req_ctx->first_desc || req_ctx->swinit) {
++      if (!req_ctx->first || req_ctx->swinit) {
+               map_single_talitos_ptr_nosync(dev, &desc->ptr[1],
+                                             req_ctx->hw_context_size,
+                                             req_ctx->hw_context,
+@@ -1833,7 +1833,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+               req_ctx->swinit = 0;
+       }
+       /* Indicate next op is not the first. */
+-      req_ctx->first_desc = 0;
++      req_ctx->first = 0;
+       /* HMAC key */
+       if (ctx->keylen)
+@@ -1866,7 +1866,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+       /* fifth DWORD empty */
+       /* hash/HMAC out -or- hash context out */
+-      if (req_ctx->last_desc)
++      if (req_ctx->last)
+               map_single_talitos_ptr(dev, &desc->ptr[5],
+                                      crypto_ahash_digestsize(tfm),
+                                      req_ctx->hw_context, DMA_FROM_DEVICE);
+@@ -1908,7 +1908,7 @@ static int common_nonsnoop_hash(struct talitos_edesc *edesc,
+               if (sg_count > 1)
+                       sync_needed = true;
+               copy_talitos_ptr(&desc2->ptr[5], &desc->ptr[5], is_sec1);
+-              if (req_ctx->last_desc)
++              if (req_ctx->last)
+                       map_single_talitos_ptr_nosync(dev, &desc->ptr[5],
+                                                     req_ctx->hw_context_size,
+                                                     req_ctx->hw_context,
+@@ -1964,7 +1964,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       bool is_sec1 = has_ftr_sec1(priv);
+       u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
+-      if (!req_ctx->last_desc && (nbytes + req_ctx->nbuf <= blocksize)) {
++      if (!req_ctx->last && (nbytes + req_ctx->nbuf <= blocksize)) {
+               /* Buffer up to one whole block */
+               nents = sg_nents_for_len(req_ctx->request_sl, nbytes);
+               if (nents < 0) {
+@@ -1981,7 +1981,7 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       nbytes_to_hash = nbytes + req_ctx->nbuf;
+       to_hash_later = nbytes_to_hash & (blocksize - 1);
+-      if (req_ctx->last_desc)
++      if (req_ctx->last)
+               to_hash_later = 0;
+       else if (to_hash_later)
+               /* There is a partial block. Hash the full block(s) now */
+@@ -2041,19 +2041,19 @@ static int ahash_process_req_one(struct ahash_request *areq, unsigned int nbytes
+       edesc->desc.hdr = ctx->desc_hdr_template;
+       /* On last one, request SEC to pad; otherwise continue */
+-      if (req_ctx->last_desc)
++      if (req_ctx->last)
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_PAD;
+       else
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_CONT;
+       /* request SEC to INIT hash. */
+-      if (req_ctx->first_desc && !req_ctx->swinit)
++      if (req_ctx->first && !req_ctx->swinit)
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_INIT;
+       /* When the tfm context has a keylen, it's an HMAC.
+        * A first or last (ie. not middle) descriptor must request HMAC.
+        */
+-      if (ctx->keylen && (req_ctx->first_desc || req_ctx->last_desc))
++      if (ctx->keylen && (req_ctx->first || req_ctx->last))
+               edesc->desc.hdr |= DESC_HDR_MODE0_MDEU_HMAC;
+       return common_nonsnoop_hash(edesc, req_ctx->areq, nbytes_to_hash, ahash_done);
+@@ -2076,7 +2076,7 @@ static void sec1_ahash_process_remaining(struct work_struct *work)
+                       req_ctx->remaining_ahash_request_bytes;
+               if (req_ctx->last_request)
+-                      req_ctx->last_desc = 1;
++                      req_ctx->last = 1;
+       }
+       err = ahash_process_req_one(req_ctx->areq,
+@@ -2103,7 +2103,7 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
+               if (nbytes > TALITOS1_MAX_DATA_LEN)
+                       nbytes = TALITOS1_MAX_DATA_LEN;
+               else if (req_ctx->last_request)
+-                      req_ctx->last_desc = 1;
++                      req_ctx->last = 1;
+       }
+       req_ctx->current_ahash_request_bytes = nbytes;
+@@ -2124,14 +2124,14 @@ static int ahash_init(struct ahash_request *areq)
+       /* Initialize the context */
+       req_ctx->buf_idx = 0;
+       req_ctx->nbuf = 0;
+-      req_ctx->first_desc = 1; /* first_desc indicates h/w must init its context */
++      req_ctx->first = 1; /* first indicates h/w must init its context */
+       req_ctx->swinit = 0; /* assume h/w init of context */
+       size =  (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
+                       ? TALITOS_MDEU_CONTEXT_SIZE_MD5_SHA1_SHA256
+                       : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
+       req_ctx->hw_context_size = size;
+       req_ctx->last_request = 0;
+-      req_ctx->last_desc = 0;
++      req_ctx->last = 0;
+       INIT_WORK(&req_ctx->sec1_ahash_process_remaining, sec1_ahash_process_remaining);
+       dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
+@@ -2223,8 +2223,8 @@ static int ahash_export(struct ahash_request *areq, void *out)
+              req_ctx->hw_context_size);
+       memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
+       export->swinit = req_ctx->swinit;
+-      export->first_desc = req_ctx->first_desc;
+-      export->last_desc = req_ctx->last_desc;
++      export->first = req_ctx->first;
++      export->last = req_ctx->last;
+       export->to_hash_later = req_ctx->to_hash_later;
+       export->nbuf = req_ctx->nbuf;
+@@ -2249,8 +2249,8 @@ static int ahash_import(struct ahash_request *areq, const void *in)
+       memcpy(req_ctx->hw_context, export->hw_context, size);
+       memcpy(req_ctx->buf[0], export->buf, export->nbuf);
+       req_ctx->swinit = export->swinit;
+-      req_ctx->first_desc = export->first_desc;
+-      req_ctx->last_desc = export->last_desc;
++      req_ctx->first = export->first;
++      req_ctx->last = export->last;
+       req_ctx->to_hash_later = export->to_hash_later;
+       req_ctx->nbuf = export->nbuf;
+-- 
+2.53.0
+
diff --git a/queue-6.6/revert-loongarch-add-pio-for-early-access-before-acp.patch b/queue-6.6/revert-loongarch-add-pio-for-early-access-before-acp.patch
new file mode 100644 (file)
index 0000000..a2fc973
--- /dev/null
@@ -0,0 +1,104 @@
+From 7ae162b72c0f0e84ec950564118408de781a7813 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 12:56:04 -0400
+Subject: Revert "LoongArch: Add PIO for early access before ACPI PCI root
+ register"
+
+This reverts commit e4c9b6d07a546969396aa7564a5c2938e4720c80.
+
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/loongarch/include/asm/acpi.h |  2 --
+ arch/loongarch/kernel/acpi.c      | 28 ----------------------------
+ arch/loongarch/kernel/setup.c     |  2 --
+ arch/loongarch/pci/acpi.c         |  2 --
+ 4 files changed, 34 deletions(-)
+
+diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
+index 4f31109714c0ab..49e29b29996f0f 100644
+--- a/arch/loongarch/include/asm/acpi.h
++++ b/arch/loongarch/include/asm/acpi.h
+@@ -37,8 +37,6 @@ static inline bool acpi_has_cpu_in_madt(void)
+ extern struct list_head acpi_wakeup_device_list;
+ extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
+-extern void acpi_add_early_pio(void);
+-extern void acpi_remove_early_pio(void);
+ extern int __init parse_acpi_topology(void);
+ static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
+diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
+index 4f4f8a9e7e3bb7..1f529b13490b3b 100644
+--- a/arch/loongarch/kernel/acpi.c
++++ b/arch/loongarch/kernel/acpi.c
+@@ -14,7 +14,6 @@
+ #include <linux/memblock.h>
+ #include <linux/of_fdt.h>
+ #include <linux/serial_core.h>
+-#include <linux/vmalloc.h>
+ #include <asm/io.h>
+ #include <asm/numa.h>
+ #include <asm/loongson.h>
+@@ -58,33 +57,6 @@ void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size)
+               return ioremap_cache(phys, size);
+ }
+-#define PIO_BASE (unsigned long)PCI_IOBASE
+-#define PIO_SIZE ALIGN(ISA_IOSIZE, PAGE_SIZE)
+-
+-static bool acpi_pio;
+-
+-/* Add PIO for early access */
+-void acpi_add_early_pio(void)
+-{
+-      if (!acpi_disabled) {
+-              acpi_pio = true;
+-              vmap_page_range(PIO_BASE, PIO_BASE + PIO_SIZE,
+-                              LOONGSON_LIO_BASE, pgprot_device(PAGE_KERNEL));
+-      }
+-}
+-
+-/* Remove PIO for PCI register */
+-void acpi_remove_early_pio(void)
+-{
+-      if (!acpi_pio)
+-              return;
+-
+-      if (!acpi_disabled) {
+-              acpi_pio = false;
+-              vunmap_range(PIO_BASE, PIO_BASE + PIO_SIZE);
+-      }
+-}
+-
+ #ifdef CONFIG_SMP
+ static int set_processor_mask(u32 id, u32 flags)
+ {
+diff --git a/arch/loongarch/kernel/setup.c b/arch/loongarch/kernel/setup.c
+index 729b0660b61c1a..2e34ece474eece 100644
+--- a/arch/loongarch/kernel/setup.c
++++ b/arch/loongarch/kernel/setup.c
+@@ -530,8 +530,6 @@ static __init int arch_reserve_pio_range(void)
+ {
+       struct device_node *np;
+-      acpi_add_early_pio();
+-
+       for_each_node_by_name(np, "isa") {
+               struct of_range range;
+               struct of_range_parser parser;
+diff --git a/arch/loongarch/pci/acpi.c b/arch/loongarch/pci/acpi.c
+index b53dae9d57c899..2d584a59a2a049 100644
+--- a/arch/loongarch/pci/acpi.c
++++ b/arch/loongarch/pci/acpi.c
+@@ -65,8 +65,6 @@ static int acpi_prepare_root_resources(struct acpi_pci_root_info *ci)
+       struct resource_entry *entry, *tmp;
+       struct acpi_device *device = ci->bridge;
+-      acpi_remove_early_pio();
+-
+       status = acpi_pci_probe_root_resources(ci);
+       if (status > 0) {
+               acpi_evaluate_integer(device->handle, "PCIH", NULL, &pci_h);
+-- 
+2.53.0
+
index ee3ea4180af44e52000a990dfdb556c8f3e82db0..c932cd28648e7d5940200eed0351d980d6a1e2cc 100644 (file)
@@ -62,3 +62,20 @@ acpi-cppc-suppress-ubsan-warning-caused-by-field-misuse.patch
 acpi-nfit-core-fix-possible-null-pointer-dereference.patch
 loongarch-add-pio-for-early-access-before-acpi-pci-root-register.patch
 rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
+perf-core-detach-event-groups-during-remove_on_exec.patch
+revert-crypto-talitos-rename-first-last-to-first_des.patch
+revert-crypto-talitos-fix-sec1-32k-ahash-request-lim.patch
+crypto-talitos-stop-using-crypto_ahash-init.patch
+crypto-talitos-fix-sec1-32k-ahash-request-limitation.patch
+crypto-talitos-rename-first-last-to-first_desc-last_.patch
+arm64-sysreg-add-layout-for-id_aa64mmfr4_el1.patch
+arm64-treat-hcr_el2.e2h-as-res1-when-id_aa64mmfr4_el.patch
+arm64-fix-early-handling-of-feat_e2h0-not-being-impl.patch
+kvm-arm64-initialize-hcr_el2.e2h-early.patch
+kvm-arm64-initialize-sctlr_el1-in-__kvm_hyp_init_cpu.patch
+arm64-revamp-hcr_el2.e2h-res1-detection.patch
+arm64-sysreg-correct-sign-definitions-for-eiesb-and-.patch
+virtio_net-support-dynamic-rss-indirection-table-siz.patch
+revert-loongarch-add-pio-for-early-access-before-acp.patch
+loongarch-add-pio-for-early-access-before-acpi-pci-r.patch
+net-drop-the-lock-in-skb_may_tx_timestamp.patch
diff --git a/queue-6.6/virtio_net-support-dynamic-rss-indirection-table-siz.patch b/queue-6.6/virtio_net-support-dynamic-rss-indirection-table-siz.patch
new file mode 100644 (file)
index 0000000..6b5b61a
--- /dev/null
@@ -0,0 +1,154 @@
+From 49bd6abe10fe9f28e9e19b4dd1a29e70bf1381c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jul 2026 11:19:54 +0000
+Subject: virtio_net: Support dynamic rss indirection table size
+
+From: Philo Lu <lulie@linux.alibaba.com>
+
+commit 86a48a00efdf61197b6658e52c6140463eb313dc upstream.
+
+When reading/writing virtio_net_ctrl_rss, the indirection table size is
+obtained from vi->rss_indir_table_size, initialized during virtnet_probe().
+However, the indirection_table was statically sized as
+VIRTIO_NET_RSS_MAX_TABLE_LEN=128, potentially causing issues when
+vi->rss_indir_table_size exceeds this limit.
+
+This patch implements dynamic allocation for the indirection table,
+allocated alongside vi->rss after vi->rss_indir_table_size is initialized,
+and freed in virtnet_remove().
+
+In virtnet_commit_rss_command(), scatter-gather lists for RSS are
+initialized differently based on hash_report presence, so indirection_table
+is unused when !vi->has_rss. Therefore, allocation is unnecessary for
+hash_report-only scenarios.
+
+Fixes: c7114b1249fa ("drivers/net/virtio_net: Added basic RSS support.")
+Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
+Signed-off-by: Xuan Zhuo <xuanzhuo@linux.alibaba.com>
+Acked-by: Joe Damato <jdamato@fastly.com>
+Acked-by: Michael S. Tsirkin <mst@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+[ Hyokyung Kim: 6.6.y predates the refactor that moved the RSS config into
+  struct virtnet_info, so struct virtio_net_ctrl_rss is still embedded in
+  struct control_buf and reached through the heap-allocated vi->ctrl. Every
+  adaptation below follows from that single difference:
+  - the new allocation and all indirection_table accesses use vi->ctrl->rss
+    in place of upstream's vi->rss;
+  - because vi->ctrl is allocated in virtnet_alloc_queues() (via init_vqs())
+    and freed in virtnet_free_queues(), the table is allocated and freed there
+    too, not in virtnet_probe()/virtnet_remove(), so its lifetime tracks
+    vi->ctrl across the probe error-unwind and freeze/restore paths;
+  - since freeing the table now dereferences vi->ctrl, vi->ctrl is set to NULL
+    after each kfree so a re-entered virtnet_free_queues() cannot dereference
+    or free a stale pointer;
+  - the table is allocated with kcalloc() so it is zero-filled when
+    reallocated on the restore path (upstream never reallocates it). ]
+Signed-off-by: Hyokyung Kim <pulpannie@gmail.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/virtio_net.c | 43 +++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 38 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
+index 33f61922c13994..5bcd1296851c6c 100644
+--- a/drivers/net/virtio_net.c
++++ b/drivers/net/virtio_net.c
+@@ -208,15 +208,16 @@ struct receive_queue {
+  * because table sizes may be differ according to the device configuration.
+  */
+ #define VIRTIO_NET_RSS_MAX_KEY_SIZE     40
+-#define VIRTIO_NET_RSS_MAX_TABLE_LEN    128
+ struct virtio_net_ctrl_rss {
+       u32 hash_types;
+       u16 indirection_table_mask;
+       u16 unclassified_queue;
+-      u16 indirection_table[VIRTIO_NET_RSS_MAX_TABLE_LEN];
++      u16 hash_cfg_reserved; /* for HASH_CONFIG (see virtio_net_hash_config for details) */
+       u16 max_tx_vq;
+       u8 hash_key_length;
+       u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE];
++
++      u16 *indirection_table;
+ };
+ /* Control VQ buffers: protected by the rtnl lock */
+@@ -3011,6 +3012,25 @@ static int virtnet_set_ringparam(struct net_device *dev,
+       return 0;
+ }
++static int rss_indirection_table_alloc(struct virtio_net_ctrl_rss *rss, u16 indir_table_size)
++{
++      if (!indir_table_size) {
++              rss->indirection_table = NULL;
++              return 0;
++      }
++
++      rss->indirection_table = kcalloc(indir_table_size, sizeof(u16), GFP_KERNEL);
++      if (!rss->indirection_table)
++              return -ENOMEM;
++
++      return 0;
++}
++
++static void rss_indirection_table_free(struct virtio_net_ctrl_rss *rss)
++{
++      kfree(rss->indirection_table);
++}
++
+ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+ {
+       struct net_device *dev = vi->dev;
+@@ -3020,11 +3040,15 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)
+       /* prepare sgs */
+       sg_init_table(sgs, 4);
+-      sg_buf_size = offsetof(struct virtio_net_ctrl_rss, indirection_table);
++      sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved);
+       sg_set_buf(&sgs[0], &vi->ctrl->rss, sg_buf_size);
+-      sg_buf_size = sizeof(uint16_t) * (vi->ctrl->rss.indirection_table_mask + 1);
+-      sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++      if (vi->has_rss) {
++              sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size;
++              sg_set_buf(&sgs[1], vi->ctrl->rss.indirection_table, sg_buf_size);
++      } else {
++              sg_set_buf(&sgs[1], &vi->ctrl->rss.hash_cfg_reserved, sizeof(uint16_t));
++      }
+       sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key)
+                       - offsetof(struct virtio_net_ctrl_rss, max_tx_vq);
+@@ -4080,7 +4104,10 @@ static void virtnet_free_queues(struct virtnet_info *vi)
+       kfree(vi->rq);
+       kfree(vi->sq);
++      if (vi->ctrl)
++              rss_indirection_table_free(&vi->ctrl->rss);
+       kfree(vi->ctrl);
++      vi->ctrl = NULL;
+ }
+ static void _free_receive_bufs(struct virtnet_info *vi)
+@@ -4266,6 +4293,9 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+               vi->ctrl = kzalloc(sizeof(*vi->ctrl), GFP_KERNEL);
+               if (!vi->ctrl)
+                       goto err_ctrl;
++              if ((vi->has_rss || vi->has_rss_hash_report) &&
++                  rss_indirection_table_alloc(&vi->ctrl->rss, vi->rss_indir_table_size))
++                      goto err_sq;
+       } else {
+               vi->ctrl = NULL;
+       }
+@@ -4298,7 +4328,10 @@ static int virtnet_alloc_queues(struct virtnet_info *vi)
+ err_rq:
+       kfree(vi->sq);
+ err_sq:
++      if (vi->ctrl)
++              rss_indirection_table_free(&vi->ctrl->rss);
+       kfree(vi->ctrl);
++      vi->ctrl = NULL;
+ err_ctrl:
+       return -ENOMEM;
+ }
+-- 
+2.53.0
+
diff --git a/queue-7.1/bpf-prefer-dirty-packs-for-ebpf-allocations.patch b/queue-7.1/bpf-prefer-dirty-packs-for-ebpf-allocations.patch
new file mode 100644 (file)
index 0000000..7a0f14d
--- /dev/null
@@ -0,0 +1,49 @@
+From 1c034229fe9b37575bcee8d520d1adce8f108e64 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:24:47 -0700
+Subject: bpf: Prefer dirty packs for eBPF allocations
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+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 <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 bba4acd61d4126..de61e1894452ef 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -988,10 +988,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/queue-7.1/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch b/queue-7.1/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch
new file mode 100644 (file)
index 0000000..0b05676
--- /dev/null
@@ -0,0 +1,88 @@
+From 55f010526b57111e1f86243083eb827291f72db9 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:24:31 -0700
+Subject: bpf: Prefer packs that won't trigger an IBPB flush on allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+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 <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 1bf4b8dffe9158..bba4acd61d4126 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -948,8 +948,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);
+@@ -981,8 +981,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/queue-7.1/bpf-restrict-jit-predictor-flush-to-cbpf.patch b/queue-7.1/bpf-restrict-jit-predictor-flush-to-cbpf.patch
new file mode 100644 (file)
index 0000000..d5f9a12
--- /dev/null
@@ -0,0 +1,242 @@
+From b05e8192788b05cd84c2a34d2f2520c301ebbed0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:41 -0700
+Subject: bpf: Restrict JIT predictor flush to cBPF
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+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.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/arm64/net/bpf_jit_comp.c   |  4 ++--
+ arch/loongarch/net/bpf_jit.c    |  5 +++--
+ arch/powerpc/net/bpf_jit_comp.c |  4 ++--
+ 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 +-
+ 9 files changed, 25 insertions(+), 18 deletions(-)
+
+diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
+index 0816c40fc7af95..9491c987e50c01 100644
+--- a/arch/arm64/net/bpf_jit_comp.c
++++ b/arch/arm64/net/bpf_jit_comp.c
+@@ -2094,7 +2094,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+       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)
+               goto out_off;
+@@ -2782,7 +2782,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/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c
+index 24913dc7f4e835..e14a8aa47fc8ea 100644
+--- a/arch/loongarch/net/bpf_jit.c
++++ b/arch/loongarch/net/bpf_jit.c
+@@ -1762,7 +1762,7 @@ static int invoke_bpf(struct jit_ctx *ctx, struct bpf_tramp_links *tl,
+ 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)
+@@ -2228,7 +2228,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+       image_size = prog_size + extable_size;
+       /* Now we know the size of the structure to make */
+       ro_header = bpf_jit_binary_pack_alloc(image_size, &ro_image_ptr, sizeof(u32),
+-                                            &header, &image_ptr, jit_fill_hole);
++                                            &header, &image_ptr, jit_fill_hole,
++                                            bpf_prog_was_classic(prog));
+       if (!ro_header)
+               goto out_offset;
+diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
+index 53ab97ad607453..73ff8a64bb7fad 100644
+--- a/arch/powerpc/net/bpf_jit_comp.c
++++ b/arch/powerpc/net/bpf_jit_comp.c
+@@ -295,7 +295,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+       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)
+               goto out_err;
+@@ -583,7 +583,7 @@ bool bpf_jit_inlines_helper_call(s32 imm)
+ void *arch_alloc_bpf_trampoline(unsigned int size)
+ {
+-      return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns);
++      return bpf_prog_pack_alloc(size, bpf_jit_fill_ill_insns, false);
+ }
+ void arch_free_bpf_trampoline(void *image, unsigned int size)
+diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
+index 2f1109dbf105b7..404a98a0fc90e8 100644
+--- a/arch/riscv/net/bpf_jit_comp64.c
++++ b/arch/riscv/net/bpf_jit_comp64.c
+@@ -1321,7 +1321,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 4365d07aaf547c..ce3bd3762e08cc 100644
+--- a/arch/riscv/net/bpf_jit_core.c
++++ b/arch/riscv/net/bpf_jit_core.c
+@@ -109,7 +109,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+                               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)
+                               goto out_offset;
+diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
+index ea9e707e8abffb..ef8b112fd7b692 100644
+--- a/arch/x86/net/bpf_jit_comp.c
++++ b/arch/x86/net/bpf_jit_comp.c
+@@ -3520,7 +3520,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)
+@@ -3831,7 +3831,8 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_verifier_env *env, struct bpf_pr
+                       /* 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)
+                               goto out_addrs;
+                       prog->aux->extable = (void *) image + roundup(proglen, align);
+diff --git a/include/linux/filter.h b/include/linux/filter.h
+index 2a7e6cbbbe1d3f..ea654453e43a34 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -1315,7 +1315,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)
+@@ -1329,7 +1329,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 f49b9b23f95e60..1b7e74e63bd4bc 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -942,7 +942,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;
+@@ -957,7 +957,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);
+@@ -989,7 +989,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);
+@@ -1149,7 +1151,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;
+@@ -1162,7 +1165,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/queue-7.1/bpf-skip-redundant-ibpb-in-pack-allocator.patch b/queue-7.1/bpf-skip-redundant-ibpb-in-pack-allocator.patch
new file mode 100644 (file)
index 0000000..fce072f
--- /dev/null
@@ -0,0 +1,81 @@
+From 1c643965be4743b7ff9104fb164c62b9fab89477 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:56 -0700
+Subject: bpf: Skip redundant IBPB in pack allocator
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+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 <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 1b7e74e63bd4bc..1bf4b8dffe9158 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -876,6 +876,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[];
+ };
+@@ -928,6 +929,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);
+@@ -990,8 +993,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);
+@@ -1029,6 +1039,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/queue-7.1/bpf-support-for-hardening-against-jit-spraying.patch b/queue-7.1/bpf-support-for-hardening-against-jit-spraying.patch
new file mode 100644 (file)
index 0000000..391c55b
--- /dev/null
@@ -0,0 +1,120 @@
+From d520d5dd207edf3e4d35aa76882de4d9c6c2c48b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:10 -0700
+Subject: bpf: Support for hardening against JIT spraying
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+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 <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 88a241aac36a27..2a7e6cbbbe1d3f 100644
+--- a/include/linux/filter.h
++++ b/include/linux/filter.h
+@@ -21,6 +21,7 @@
+ #include <linux/if_vlan.h>
+ #include <linux/vmalloc.h>
+ #include <linux/sockptr.h>
++#include <linux/static_call.h>
+ #include <linux/u64_stats_sync.h>
+ #include <net/sch_generic.h>
+@@ -1291,6 +1292,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 6aa2a8b2403065..f49b9b23f95e60 100644
+--- a/kernel/bpf/core.c
++++ b/kernel/bpf/core.c
+@@ -20,6 +20,7 @@
+ #include <uapi/linux/btf.h>
+ #include <linux/filter.h>
+ #include <linux/skbuff.h>
++#include <linux/static_call.h>
+ #include <linux/vmalloc.h>
+ #include <linux/prandom.h>
+ #include <linux/bpf.h>
+@@ -883,6 +884,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);
+@@ -941,6 +951,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) {
+@@ -971,6 +989,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/queue-7.1/perf-core-detach-event-groups-during-remove_on_exec.patch b/queue-7.1/perf-core-detach-event-groups-during-remove_on_exec.patch
new file mode 100644 (file)
index 0000000..3728f11
--- /dev/null
@@ -0,0 +1,111 @@
+From 7d4ef3691eca33dabb0d53abf0f41274bff1c6b6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 14 Jun 2026 23:22:18 +0900
+Subject: perf/core: Detach event groups during remove_on_exec
+
+From: Taeyang Lee <0wn@theori.io>
+
+[ Upstream commit 037a3c43edfb597665dd34457cd22b14692f2ba3 ]
+
+perf_event_remove_on_exec() removes events by calling
+perf_event_exit_event(). For top-level events, this removes the event from
+the context with DETACH_EXIT only.
+
+This can leave inconsistent group state when a removed event is a group
+leader and the group contains siblings without remove_on_exec. If the group
+was active, the surviving siblings can remain active and attached to the
+removed leader's sibling list, but are no longer represented by a valid
+group leader on the PMU context active lists.
+
+A later close of the removed leader uses DETACH_GROUP and can promote the
+still-active siblings from this stale group state. The next schedule-in can
+then add an already-linked active_list entry again, corrupting the PMU
+context active list.
+
+With DEBUG_LIST enabled, this is caught as a list_add double-add in
+merge_sched_in().
+
+Fix this by detaching group relationships when remove_on_exec removes an
+event. This preserves the existing task-exit and revoke behavior, while
+ensuring surviving siblings are ungrouped before the removed event leaves
+the context.
+
+Fixes: 2e498d0a74e5 ("perf: Add support for event removal on exec")
+Signed-off-by: Taeyang Lee <0wn@theori.io>
+Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/events/core.c | 17 +++++++++--------
+ 1 file changed, 9 insertions(+), 8 deletions(-)
+
+diff --git a/kernel/events/core.c b/kernel/events/core.c
+index 7935d5663944ee..bab0f3bd4fa8d8 100644
+--- a/kernel/events/core.c
++++ b/kernel/events/core.c
+@@ -4728,7 +4728,7 @@ static void perf_remove_from_owner(struct perf_event *event);
+ static void perf_event_exit_event(struct perf_event *event,
+                                 struct perf_event_context *ctx,
+                                 struct task_struct *task,
+-                                bool revoke);
++                                unsigned long detach_flags);
+ /*
+  * Removes all events from the current task that have been marked
+@@ -4755,7 +4755,7 @@ static void perf_event_remove_on_exec(struct perf_event_context *ctx)
+               modified = true;
+-              perf_event_exit_event(event, ctx, ctx->task, false);
++              perf_event_exit_event(event, ctx, ctx->task, DETACH_GROUP);
+       }
+       raw_spin_lock_irqsave(&ctx->lock, flags);
+@@ -12900,7 +12900,7 @@ static void __pmu_detach_event(struct pmu *pmu, struct perf_event *event,
+       /*
+        * De-schedule the event and mark it REVOKED.
+        */
+-      perf_event_exit_event(event, ctx, ctx->task, true);
++      perf_event_exit_event(event, ctx, ctx->task, DETACH_REVOKE);
+       /*
+        * All _free_event() bits that rely on event->pmu:
+@@ -14488,12 +14488,13 @@ static void
+ perf_event_exit_event(struct perf_event *event,
+                     struct perf_event_context *ctx,
+                     struct task_struct *task,
+-                    bool revoke)
++                    unsigned long detach_flags)
+ {
+       struct perf_event *parent_event = event->parent;
+-      unsigned long detach_flags = DETACH_EXIT;
+       unsigned int attach_state;
++      detach_flags |= DETACH_EXIT;
++
+       if (parent_event) {
+               /*
+                * Do not destroy the 'original' grouping; because of the
+@@ -14516,8 +14517,8 @@ perf_event_exit_event(struct perf_event *event,
+                       sync_child_event(event, task);
+       }
+-      if (revoke)
+-              detach_flags |= DETACH_GROUP | DETACH_REVOKE;
++      if (detach_flags & DETACH_REVOKE)
++              detach_flags |= DETACH_GROUP;
+       perf_remove_from_context(event, detach_flags);
+       /*
+@@ -14605,7 +14606,7 @@ static void perf_event_exit_task_context(struct task_struct *task, bool exit)
+               perf_event_task(task, ctx, 0);
+       list_for_each_entry_safe(child_event, next, &ctx->event_list, event_entry)
+-              perf_event_exit_event(child_event, ctx, exit ? task : NULL, false);
++              perf_event_exit_event(child_event, ctx, exit ? task : NULL, 0);
+       mutex_unlock(&ctx->mutex);
+-- 
+2.53.0
+
index d34f661f8eef526653fbc29ac4cbf711265e1632..bd3b1dc87f6d97252320d0aaae8139edf0197d41 100644 (file)
@@ -20,3 +20,10 @@ rust-block-fix-gendisk-cleanup-paths.patch
 rust-doctest-fix-incorrect-pattern-in-replacement.patch
 rust-kbuild-set-frame-pointer-llvm-module-flag-for-config_frame_pointer.patch
 futex-requeue-revert-prevent-null-pointer-dereference-in-remove_waiter-on-self-deadlock.patch
+perf-core-detach-event-groups-during-remove_on_exec.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
diff --git a/queue-7.1/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch b/queue-7.1/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch
new file mode 100644 (file)
index 0000000..e84ae59
--- /dev/null
@@ -0,0 +1,143 @@
+From 8f1d854bb7030ea41378cc781b7222e48978708d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jul 2026 15:23:25 -0700
+Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation
+
+From: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+
+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.
+
+Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
+Acked-by: Daniel Borkmann <daniel@iogearbox.net>
+Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
+Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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 4f4b5e8a157430..b68892e6d58c47 100644
+--- a/arch/x86/include/asm/nospec-branch.h
++++ b/arch/x86/include/asm/nospec-branch.h
+@@ -388,6 +388,10 @@ extern void srso_alias_return_thunk(void);
+ extern void entry_untrain_ret(void);
+ extern void write_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 83f51cab0b1e39..d9af230c051259 100644
+--- a/arch/x86/kernel/cpu/bugs.c
++++ b/arch/x86/kernel/cpu/bugs.c
+@@ -16,6 +16,7 @@
+ #include <linux/sched/smt.h>
+ #include <linux/pgtable.h>
+ #include <linux/bpf.h>
++#include <linux/filter.h>
+ #include <linux/kvm_types.h>
+ #include <asm/spec-ctrl.h>
+@@ -1651,8 +1652,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"
+@@ -2095,8 +2109,7 @@ static void __init bhi_apply_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;
+@@ -2238,6 +2251,27 @@ static void __init spectre_v2_update_mitigation(void)
+               pr_info("%s\n", spectre_v2_strings[spectre_v2_enabled]);
+ }
++#ifdef CONFIG_BPF_JIT
++static void __bpf_arch_ibpb(void *unused)
++{
++      write_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_apply_mitigation(void)
+ {
+       if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+@@ -2314,6 +2348,14 @@ static void __init spectre_v2_apply_mitigation(void)
+               setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
+               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
+ }
+ static void update_stibp_msr(void * __unused)
+@@ -3490,9 +3532,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_VMEXIT))
+               return "; BHI: Vulnerable, KVM: SW loop";
+-- 
+2.53.0
+