From: Sasha Levin Date: Fri, 10 Jul 2026 21:02:24 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6ce4712d0b83988c4fc418b6ce2529202cae490f;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- 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 index 0000000000..8bee227036 --- /dev/null +++ b/queue-5.15/locking-rtmutex-skip-remove_waiter-when-waiter-is-no.patch @@ -0,0 +1,72 @@ +From a84c8d44d6c542c5843abe7b580475f0ea12e8f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 10:59:49 -0400 +Subject: locking/rtmutex: Skip remove_waiter() when waiter is not enqueued + +From: Davidlohr Bueso + +[ 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 +Signed-off-by: Thomas Gleixner +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 +--- + 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 index 0000000000..b4668fb46f --- /dev/null +++ b/queue-5.15/perf-core-detach-event-groups-during-remove_on_exec.patch @@ -0,0 +1,98 @@ +From 3badcf0525a192bdf080670715b14358a443ff6b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) +Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..aeac8a8766 --- /dev/null +++ b/queue-5.15/rtmutex-use-waiter-task-instead-of-current-in-remove.patch @@ -0,0 +1,87 @@ +From e8757c81615774dbe75e0859f9525dd733240ebd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 10:59:48 -0400 +Subject: rtmutex: Use waiter::task instead of current in remove_waiter() + +From: Keenan Dong + +[ 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 +Reported-by: Yifan Wu +Reported-by: Juefei Pu +Reported-by: Xin Liu +Signed-off-by: Keenan Dong +Signed-off-by: Thomas Gleixner +Cc: stable@vger.kernel.org +Signed-off-by: Sasha Levin +--- + 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(¤t->pi_lock); ++ raw_spin_lock(&waiter_task->pi_lock); + rt_mutex_dequeue(lock, waiter); +- current->pi_blocked_on = NULL; +- raw_spin_unlock(¤t->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 + diff --git a/queue-5.15/series b/queue-5.15/series index 13e281e022..e5b6c6aac7 100644 --- a/queue-5.15/series +++ b/queue-5.15/series @@ -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 index 0000000000..0ef1f5dfe5 --- /dev/null +++ b/queue-6.1/perf-core-detach-event-groups-during-remove_on_exec.patch @@ -0,0 +1,99 @@ +From f6f4951c2cf47b7dd924f6539926d68a1b845398 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) +Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.1/series b/queue-6.1/series index b384cc251e..42fbeb8e33 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -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 index 0000000000..8e48ea2a08 --- /dev/null +++ b/queue-6.1/virtio_net-support-dynamic-rss-indirection-table-siz.patch @@ -0,0 +1,154 @@ +From fdae2106a7ec9598da34c7de2f1f528b5d28fbcf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Jul 2026 11:25:21 +0000 +Subject: virtio_net: Support dynamic rss indirection table size + +From: Philo Lu + +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 +Signed-off-by: Xuan Zhuo +Acked-by: Joe Damato +Acked-by: Michael S. Tsirkin +Signed-off-by: Paolo Abeni +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..1fe7732ff5 --- /dev/null +++ b/queue-6.12/perf-core-detach-event-groups-during-remove_on_exec.patch @@ -0,0 +1,99 @@ +From 57e54b3034f105c415058add64a0f5b462f83737 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) +Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..b81855e6d3 --- /dev/null +++ b/queue-6.12/rust-kasan-kasan-rust-requires-clang.patch @@ -0,0 +1,40 @@ +From 3001d0c22e2f93bf90c6fe056e96630b6d5a10d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 20:03:59 +0200 +Subject: rust: kasan: KASAN+RUST requires clang + +From: Alice Ryhl + +[ 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 +Reviewed-by: Gary Guo +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.12/series b/queue-6.12/series index 24bf8cec15..5fc35e4868 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -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 index 0000000000..6f871a25b2 --- /dev/null +++ b/queue-6.18/fscrypt-fix-key-setup-in-edge-case-with-multiple-dat.patch @@ -0,0 +1,429 @@ +From 0f01cb9f5084015014a40f1541853d3081857f69 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..97231b6d11 --- /dev/null +++ b/queue-6.18/fscrypt-replace-mk_users-keyring-with-simple-list.patch @@ -0,0 +1,454 @@ +From 8572b924e77f5d7c92c3270def5f810131ee2856 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Jun 2026 15:19:21 -0700 +Subject: fscrypt: Replace mk_users keyring with simple list + +From: Eric Biggers + +[ 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 +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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..d37cf3b96b --- /dev/null +++ b/queue-6.18/perf-core-detach-event-groups-during-remove_on_exec.patch @@ -0,0 +1,111 @@ +From 0459843e2962de0309deca8d97f06c75479adba5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) +Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..63ff73355f --- /dev/null +++ b/queue-6.18/rust-kasan-kasan-rust-requires-clang.patch @@ -0,0 +1,40 @@ +From 43f26212403918d90b27dfae878f9e0c7f8158e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 19:59:43 +0200 +Subject: rust: kasan: KASAN+RUST requires clang + +From: Alice Ryhl + +[ 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 +Reviewed-by: Gary Guo +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 +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-6.18/series b/queue-6.18/series index e307ec6abd..9efc790bf6 100644 --- a/queue-6.18/series +++ b/queue-6.18/series @@ -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 index 0000000000..2f6efdc31a --- /dev/null +++ b/queue-6.6/arm64-fix-early-handling-of-feat_e2h0-not-being-impl.patch @@ -0,0 +1,92 @@ +From 2342107063f0bbeb4272bc4ad5f4a359b9b09068 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 22:36:00 +0000 +Subject: arm64: Fix early handling of FEAT_E2H0 not being implemented + +From: Marc Zyngier + +[ 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 +Acked-by: Catalin Marinas +Link: https://lore.kernel.org/r/20240321115414.3169115-1-maz@kernel.org +Signed-off-by: Oliver Upton +Signed-off-by: Colton Lewis +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..4055b957c5 --- /dev/null +++ b/queue-6.6/arm64-revamp-hcr_el2.e2h-res1-detection.patch @@ -0,0 +1,113 @@ +From 820ad08c8680c42de17c2470541a1d68b6937375 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 22:36:03 +0000 +Subject: arm64: Revamp HCR_EL2.E2H RES1 detection + +From: Marc Zyngier + +[ 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 +Acked-by: Mark Rutland +Acked-by: Catalin Marinas +Reviewed-by: Oliver Upton +Tested-by: Jan Kotas +Signed-off-by: Marc Zyngier +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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..249a4f820d --- /dev/null +++ b/queue-6.6/arm64-sysreg-add-layout-for-id_aa64mmfr4_el1.patch @@ -0,0 +1,78 @@ +From eae585cefd26bee9a9c7bf93127f942fe74fecf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 22:35:58 +0000 +Subject: arm64: sysreg: Add layout for ID_AA64MMFR4_EL1 + +From: Marc Zyngier + +[ 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 +Signed-off-by: Marc Zyngier +Reviewed-by: Catalin Marinas +Reviewed-by: Miguel Luis +Link: https://lore.kernel.org/r/20240122181344.258974-5-maz@kernel.org +Signed-off-by: Oliver Upton +Signed-off-by: Colton Lewis +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..e1a1518ad1 --- /dev/null +++ b/queue-6.6/arm64-sysreg-correct-sign-definitions-for-eiesb-and-.patch @@ -0,0 +1,53 @@ +From 4d28c6b03345d42076b2cd50522ac3ff5de150e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Aug 2025 10:51:42 +0100 +Subject: arm64: sysreg: Correct sign definitions for EIESB and DoubleLock + +From: Fuad Tabba + +[ 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 +Acked-by: Mark Rutland +Signed-off-by: Will Deacon +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..9376353e9a --- /dev/null +++ b/queue-6.6/arm64-treat-hcr_el2.e2h-as-res1-when-id_aa64mmfr4_el.patch @@ -0,0 +1,75 @@ +From f1de5423d12f895e07cc6891613229f018e70a6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +[ 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 +Signed-off-by: Marc Zyngier +Reviewed-by: Catalin Marinas +Link: https://lore.kernel.org/r/20240122181344.258974-8-maz@kernel.org +Signed-off-by: Oliver Upton +Signed-off-by: Colton Lewis +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..de6602a963 --- /dev/null +++ b/queue-6.6/crypto-talitos-fix-sec1-32k-ahash-request-limitation.patch @@ -0,0 +1,362 @@ +From 8b29c044e1ae8a35b483b0978e6fbb4c0976ea30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 21:39:55 +0200 +Subject: crypto: talitos - fix SEC1 32k ahash request limitation + +From: Paul Louvel + +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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 + #include + #include + #include +@@ -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 index 0000000000..1d1659c172 --- /dev/null +++ b/queue-6.6/crypto-talitos-rename-first-last-to-first_desc-last_.patch @@ -0,0 +1,204 @@ +From 7ff3d5875ff4b2fe27b3e8dcb5b61b923684457b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 21:39:56 +0200 +Subject: crypto: talitos - rename first/last to first_desc/last_desc + +From: Paul Louvel + +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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..021c03902c --- /dev/null +++ b/queue-6.6/crypto-talitos-stop-using-crypto_ahash-init.patch @@ -0,0 +1,62 @@ +From ede435a73fd99dc97049244c271c9ea42bb1cad3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 21:39:54 +0200 +Subject: crypto: talitos - stop using crypto_ahash::init + +From: Eric Biggers + +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 +Signed-off-by: Herbert Xu +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..ffdd9c8427 --- /dev/null +++ b/queue-6.6/kvm-arm64-initialize-hcr_el2.e2h-early.patch @@ -0,0 +1,145 @@ +From b0b66e90f910d8e1a9ace4a3c328b618d67f08ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 22:36:01 +0000 +Subject: KVM: arm64: Initialize HCR_EL2.E2H early + +From: Mark Rutland + +[ 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 +Cc: Ahmed Genidi +Cc: Ben Horgan +Cc: Catalin Marinas +Cc: Leo Yan +Cc: Marc Zyngier +Cc: Oliver Upton +Cc: Will Deacon +Link: https://lore.kernel.org/r/20250227180526.1204723-2-mark.rutland@arm.com +[maz: fixed LT->GE thinko] +Signed-off-by: Marc Zyngier +[ 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 +Signed-off-by: Sasha Levin +--- + 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 + #include + ++.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 index 0000000000..5ffc440362 --- /dev/null +++ b/queue-6.6/kvm-arm64-initialize-sctlr_el1-in-__kvm_hyp_init_cpu.patch @@ -0,0 +1,116 @@ +From 0d77a47dd1214af477961e83eb4e4671a19a3bef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 22:36:02 +0000 +Subject: KVM: arm64: Initialize SCTLR_EL1 in __kvm_hyp_init_cpu() + +From: Ahmed Genidi + +[ 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 +Signed-off-by: Ahmed Genidi +[ Mark: clarify commit message, handle E2H, move to C, remove macro ] +Signed-off-by: Mark Rutland +Cc: Ahmed Genidi +Cc: Ben Horgan +Cc: Catalin Marinas +Cc: Leo Yan +Cc: Marc Zyngier +Cc: Oliver Upton +Cc: Will Deacon +Reviewed-by: Leo Yan +Link: https://lore.kernel.org/r/20250227180526.1204723-3-mark.rutland@arm.com +Signed-off-by: Marc Zyngier +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..8ba05afa1c --- /dev/null +++ b/queue-6.6/loongarch-add-pio-for-early-access-before-acpi-pci-r.patch @@ -0,0 +1,117 @@ +From babac320fef51d3733e78497cf3a44ee5ed4b031 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Jul 2026 20:26:13 +0800 +Subject: LoongArch: Add PIO for early access before ACPI PCI root register + +From: Huacai Chen + +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: +Signed-off-by: Huacai Chen +Signed-off-by: Sasha Levin +--- + 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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..35ae856231 --- /dev/null +++ b/queue-6.6/net-drop-the-lock-in-skb_may_tx_timestamp.patch @@ -0,0 +1,118 @@ +From 4cc4b1d9c56de54140d02dd39e66e874f5580aab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 20:58:16 +0800 +Subject: net: Drop the lock in skb_may_tx_timestamp() + +From: Sebastian Andrzej Siewior + +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 +Reviewed-by: Willem de Bruijn +Reviewed-by: Jason Xing +Reviewed-by: Eric Dumazet +Link: https://patch.msgid.link/20260220183858.N4ERjFW6@linutronix.de +Signed-off-by: Paolo Abeni +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..a4f168a84c --- /dev/null +++ b/queue-6.6/perf-core-detach-event-groups-during-remove_on_exec.patch @@ -0,0 +1,99 @@ +From a492ad32315e54d55173da7f252a0d86e678a0c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) +Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..d4f206fcc4 --- /dev/null +++ b/queue-6.6/revert-crypto-talitos-fix-sec1-32k-ahash-request-lim.patch @@ -0,0 +1,363 @@ +From 287c9c848fbe5458d88c57c8799996e7cad64ba9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 21:39:53 +0200 +Subject: Revert "crypto: talitos - fix SEC1 32k ahash request limitation" + +From: Goetz Goerisch + +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 +Signed-off-by: Sasha Levin +--- + 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 + #include + #include + #include +@@ -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 index 0000000000..c644a79eb6 --- /dev/null +++ b/queue-6.6/revert-crypto-talitos-rename-first-last-to-first_des.patch @@ -0,0 +1,217 @@ +From a18cb66676462286f40ddfc5b4311087e5dec840 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 21:39:52 +0200 +Subject: Revert "crypto: talitos - rename first/last to first_desc/last_desc" + +From: Goetz Goerisch + +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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..a2fc973221 --- /dev/null +++ b/queue-6.6/revert-loongarch-add-pio-for-early-access-before-acp.patch @@ -0,0 +1,104 @@ +From 7ae162b72c0f0e84ec950564118408de781a7813 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 +--- + 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 + #include + #include +-#include + #include + #include + #include +@@ -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 + diff --git a/queue-6.6/series b/queue-6.6/series index ee3ea4180a..c932cd2864 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -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 index 0000000000..6b5b61a6c1 --- /dev/null +++ b/queue-6.6/virtio_net-support-dynamic-rss-indirection-table-siz.patch @@ -0,0 +1,154 @@ +From 49bd6abe10fe9f28e9e19b4dd1a29e70bf1381c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 10 Jul 2026 11:19:54 +0000 +Subject: virtio_net: Support dynamic rss indirection table size + +From: Philo Lu + +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 +Signed-off-by: Xuan Zhuo +Acked-by: Joe Damato +Acked-by: Michael S. Tsirkin +Signed-off-by: Paolo Abeni +[ 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 +Signed-off-by: Sasha Levin +--- + 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 index 0000000000..7a0f14da26 --- /dev/null +++ b/queue-7.1/bpf-prefer-dirty-packs-for-ebpf-allocations.patch @@ -0,0 +1,49 @@ +From 1c034229fe9b37575bcee8d520d1adce8f108e64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 15:24:47 -0700 +Subject: bpf: Prefer dirty packs for eBPF allocations + +From: Pawan Gupta + +commit b72e29e0f7ee329d89f86db8700c8ea99b4a370a upstream. + +The pack allocator only flushes predictors when reusing a dirty pack for +cBPF, eBPF allocations never trigger a flush. Currently, eBPF picks the +first free pack, which could be a clean pack. As an optimization, leaving +a clean pack for cBPF can avoid flushes. + +Prefer dirty packs for eBPF and keep clean packs free for cBPF. This +mirrors the existing cBPF preference for clean packs: each program kind +prefers the pack that avoids an extra flush, and falls back to the other +kind only when no preferred pack has room. eBPF reuse of a dirty pack is +harmless since eBPF being privileged does not flush. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 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 index 0000000000..0b05676524 --- /dev/null +++ b/queue-7.1/bpf-prefer-packs-that-won-t-trigger-an-ibpb-flush-on.patch @@ -0,0 +1,88 @@ +From 55f010526b57111e1f86243083eb827291f72db9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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 + +commit a9b1f19a6a673ba06820898d0f1ad02883ea1639 upstream. + +Currently BPF pack allocator picks the chunks from the first available +pack. While this is okay, it naturally leads to more frequent flushes +when there are multiple packs in the system that weren't used since the +last flush. + +As an optimization prefer allocating the new programs from packs that +are unused since last flush. When all packs are dirty, allocation forces +a flush and marks all packs clean. + +Below are some future optimizations ideas: + + 1. Currently, the "dirty" tracking is only done at the pack-level. + Flush frequency can further be reduced with chunk-level tracking. + This requires a new bitmap per-pack to track the dirty state. + 2. IBPB flush is done on all CPUs, even if only a single CPU ran the + BPF program. On a system with hundreds of CPUs this could be a + major bottleneck forcing hundreds of IPIs to deliver the flush. + The solution is to track the CPUs where a BPF program ran, and + issue IBPB only on those CPUs. + 3. Avoid IBPB when flush is already done at other sources (e.g. + context switch). + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 27 ++++++++++++++++++++++++--- + 1 file changed, 24 insertions(+), 3 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 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 index 0000000000..d5f9a12b88 --- /dev/null +++ b/queue-7.1/bpf-restrict-jit-predictor-flush-to-cbpf.patch @@ -0,0 +1,242 @@ +From b05e8192788b05cd84c2a34d2f2520c301ebbed0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 15:23:41 -0700 +Subject: bpf: Restrict JIT predictor flush to cBPF + +From: Pawan Gupta + +commit 0bb99f2cfaae6822d734d69722de30af823efdf3 upstream. + +Currently predictor flush on memory reuse is done for all BPF JIT +allocations, but only cBPF programs can be loaded by an unprivileged user. +eBPF is privileged by default, and flushing predictors for all CPUs on +every eBPF reuse penalizes the common case for no security benefit. + +eBPF allocations can be frequent on busy systems, only flush predictors +for cBPF programs. Trampoline and dispatcher allocations also skip the +flush as they are eBPF-only. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + arch/arm64/net/bpf_jit_comp.c | 4 ++-- + arch/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 index 0000000000..fce072f488 --- /dev/null +++ b/queue-7.1/bpf-skip-redundant-ibpb-in-pack-allocator.patch @@ -0,0 +1,81 @@ +From 1c643965be4743b7ff9104fb164c62b9fab89477 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 15:23:56 -0700 +Subject: bpf: Skip redundant IBPB in pack allocator + +From: Pawan Gupta + +commit a23c1c5396a91680703360d1ee28a44657c503c4 upstream. + +bpf_prog_pack_alloc() issues IBPB on all CPUs on every cBPF allocation, +even when reusing chunks from an existing pack where no new memory was +touched since the last IBPB. + +Since IBPB on all CPUs is heavy, Dave Hansen suggested to track allocation +since last IBPB, and only issue IBPB at reuse for the chunks that have not +seen an IBPB since they were last freed. + +Track per-pack whether an IBPB is needed via arch_flush_needed. Set it when +allocating a chunk, reset on IBPB flush. On reuse, conditionally issue the +flush. Since IBPB invalidates all BTB entries, clear the flag on all packs +after flushing. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + kernel/bpf/core.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index 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 index 0000000000..391c55b954 --- /dev/null +++ b/queue-7.1/bpf-support-for-hardening-against-jit-spraying.patch @@ -0,0 +1,120 @@ +From d520d5dd207edf3e4d35aa76882de4d9c6c2c48b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 15:23:10 -0700 +Subject: bpf: Support for hardening against JIT spraying + +From: Pawan Gupta + +commit 96cce16e26dd02a8678f1e87f88a4b5cdb63b995 upstream. + +The BPF JIT allocator packs many small programs into larger executable +allocations and reuses space within those allocations as programs are +loaded and freed. When fresh code is written into space that a previous +program occupied, an indirect jump into the new program can reuse a branch +prediction left behind by the old one. + +Flush the indirect branch predictors before reusing JIT memory so that +indirect jumps into a newly written program don't reuse predictions from an +old program that occupied the same space. + +Introduce bpf_arch_pred_flush_enabled static key and bpf_arch_pred_flush +static call for flushing the branch predictors on JIT memory reuse. +Architectures that need a flush, can update it to a predictor flush +function. By default, its a NOP and does not emit any CALL. + +Allocations larger than a pack are not covered by this flush. That is safe +because cBPF programs (the unprivileged attack surface) are bounded well +below a pack size. Issue a warning if this assumption is ever violated +while the flush is active. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + include/linux/filter.h | 10 ++++++++++ + kernel/bpf/core.c | 19 +++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/include/linux/filter.h b/include/linux/filter.h +index 88a241aac36a27..2a7e6cbbbe1d3f 100644 +--- a/include/linux/filter.h ++++ b/include/linux/filter.h +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + + #include +@@ -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 + #include + #include ++#include + #include + #include + #include +@@ -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 index 0000000000..3728f112a5 --- /dev/null +++ b/queue-7.1/perf-core-detach-event-groups-during-remove_on_exec.patch @@ -0,0 +1,111 @@ +From 7d4ef3691eca33dabb0d53abf0f41274bff1c6b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +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) +Link: https://patch.msgid.link/ai65GgZcC0LAlWLG@Taeyangs-MacBook-Pro.local +Signed-off-by: Sasha Levin +--- + 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 + diff --git a/queue-7.1/series b/queue-7.1/series index d34f661f8e..bd3b1dc87f 100644 --- a/queue-7.1/series +++ b/queue-7.1/series @@ -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 index 0000000000..e84ae5972d --- /dev/null +++ b/queue-7.1/x86-bugs-enable-ibpb-flush-on-bpf-jit-allocation.patch @@ -0,0 +1,143 @@ +From 8f1d854bb7030ea41378cc781b7222e48978708d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Jul 2026 15:23:25 -0700 +Subject: x86/bugs: Enable IBPB flush on BPF JIT allocation + +From: Pawan Gupta + +commit a3af84b0fa00ead01fcd0e28b5d773ff25990a0d upstream. + +Enable hardening against JIT spraying when Spectre-v2 mitigations are in +use. Specifically, issue an IBPB flush on BPF JIT memory reuse. Skip +enabling the IBPB flush if the BPF dispatcher is already using a retpoline +sequence. + +This hardening applies only when BPF-JIT is in use. Guard the enabling +under CONFIG_BPF_JIT so that bugs.c still builds with CONFIG_BPF_JIT=n. + +Signed-off-by: Pawan Gupta +Acked-by: Daniel Borkmann +Acked-by: Dave Hansen +Signed-off-by: Daniel Borkmann +Signed-off-by: Sasha Levin +--- + arch/x86/include/asm/nospec-branch.h | 4 +++ + arch/x86/kernel/cpu/bugs.c | 50 +++++++++++++++++++++++++--- + 2 files changed, 49 insertions(+), 5 deletions(-) + +diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h +index 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 + #include + #include ++#include + #include + + #include +@@ -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 +