Recreate RHEL 6.12.0-211.31.1 from CS10/upstream backports
- Drop AlmaLinux ahead-of-RHEL eventpoll CVE-2026-46242 fix (1417), superseded by the RHEL eventpoll series in 211.31.1 - Temporarily drop the rtmutex remove_waiter() fixes (1418, 1420) - Add RHEL 211.31.1 backports recreated from CS10/upstream (1421-1444)
This commit is contained in:
parent
4f6054905f
commit
5edaaf4d17
@ -1,99 +0,0 @@
|
||||
From: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu, 23 Apr 2026 11:56:09 +0200
|
||||
Subject: [PATCH] eventpoll: fix ep_remove struct eventpoll / struct file UAF
|
||||
|
||||
CVE: CVE-2026-46242
|
||||
|
||||
Upstream commit a6dc643c69311677c574a0f17a3f4d66a5f3744b, adapted to the
|
||||
pre-e9e5cd40d7c4 ("eventpoll: kill __ep_remove()") code shape still used
|
||||
by this kernel, where the removal path is the monolithic __ep_remove(ep,
|
||||
epi, force) rather than upstream's ep_remove()/ep_remove_epi()/
|
||||
ep_remove_file() split.
|
||||
|
||||
ep_remove() used epi->ffd.file across the file->f_lock critical section
|
||||
without holding a reference. A concurrent __fput() taking the
|
||||
eventpoll_release() fastpath could free the file (and, for the
|
||||
epoll-watches-epoll case, the watched struct eventpoll) mid-section,
|
||||
leading to a use-after-free / attacker-controllable kmem_cache_free().
|
||||
|
||||
Pin the file with epi_fget() before entering the critical section and
|
||||
release it afterwards. A failed pin means __fput() is already in flight
|
||||
and will remove the epi via eventpoll_release_file() (which blocks on
|
||||
ep->mtx), so it is safe to bail. The pin is taken only on the !force
|
||||
path: the force path is reached from eventpoll_release_file() itself,
|
||||
i.e. from within __fput() where f_count has already dropped to zero and
|
||||
epi_fget() would necessarily fail; there @file is still valid and no
|
||||
concurrent __fput() can race, so it keeps using epi->ffd.file directly.
|
||||
A successful pin also makes the in-lock epi->dying recheck redundant; the
|
||||
cheap lockless READ_ONCE(epi->dying) fast-path bailout is kept.
|
||||
|
||||
Fixes: 58c9b016e128 ("epoll: use refcount to reduce ep_mutex contention")
|
||||
Reported-by: Jaeyoung Chung <jjy600901@snu.ac.kr>
|
||||
Signed-off-by: Christian Brauner <brauner@kernel.org>
|
||||
---
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index f4efb5b..68e58d0 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -821,6 +821,8 @@ static void ep_free(struct eventpoll *ep)
|
||||
kfree(ep);
|
||||
}
|
||||
|
||||
+static struct file *epi_fget(const struct epitem *epi);
|
||||
+
|
||||
/*
|
||||
* Removes a "struct epitem" from the eventpoll RB tree and deallocates
|
||||
* all the associated resources. Must be called with "mtx" held.
|
||||
@@ -832,6 +834,7 @@ static void ep_free(struct eventpoll *ep)
|
||||
static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
{
|
||||
struct file *file = epi->ffd.file;
|
||||
+ struct file *to_put = NULL;
|
||||
struct epitems_head *to_free;
|
||||
struct hlist_head *head;
|
||||
|
||||
@@ -842,13 +845,27 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
*/
|
||||
ep_unregister_pollwait(ep, epi);
|
||||
|
||||
- /* Remove the current item from the list of epoll hooks */
|
||||
- spin_lock(&file->f_lock);
|
||||
- if (epi->dying && !force) {
|
||||
- spin_unlock(&file->f_lock);
|
||||
- return false;
|
||||
+ if (!force) {
|
||||
+ /* cheap sync with eventpoll_release_file() */
|
||||
+ if (unlikely(READ_ONCE(epi->dying)))
|
||||
+ return false;
|
||||
+ /*
|
||||
+ * Grabbing a reference proves we are not racing
|
||||
+ * eventpoll_release_file() and are not going to: a concurrent
|
||||
+ * __fput() cannot free @file (nor, for the epoll-on-epoll
|
||||
+ * case, the watched eventpoll) across the f_lock section
|
||||
+ * below. A failed pin means @file already reached refcount
|
||||
+ * zero and __fput() is in flight; it will remove this epi via
|
||||
+ * eventpoll_release_file(), so bail out here.
|
||||
+ */
|
||||
+ file = epi_fget(epi);
|
||||
+ if (!file)
|
||||
+ return false;
|
||||
+ to_put = file;
|
||||
}
|
||||
|
||||
+ /* Remove the current item from the list of epoll hooks */
|
||||
+ spin_lock(&file->f_lock);
|
||||
to_free = NULL;
|
||||
head = file->f_ep;
|
||||
if (head->first == &epi->fllink && !epi->fllink.next) {
|
||||
@@ -882,6 +899,8 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
kfree_rcu(epi, rcu);
|
||||
|
||||
percpu_counter_dec(&ep->user->epoll_watches);
|
||||
+ if (to_put)
|
||||
+ fput(to_put);
|
||||
return true;
|
||||
}
|
||||
|
||||
--
|
||||
2.43.0
|
||||
|
||||
@ -1,86 +0,0 @@
|
||||
From 3bfdc63936dd4773109b7b8c280c0f3b5ae7d349 Mon Sep 17 00:00:00 2001
|
||||
From: Keenan Dong <keenanat2000@gmail.com>
|
||||
Date: Wed, 8 Apr 2026 16:46:00 +0800
|
||||
Subject: [PATCH] rtmutex: Use waiter::task instead of current in
|
||||
remove_waiter()
|
||||
|
||||
remove_waiter() is used by the slowlock paths, but it is also used for
|
||||
proxy-lock rollback in rt_mutex_start_proxy_lock() when invoked from
|
||||
futex_requeue().
|
||||
|
||||
In the latter case waiter::task is not current, but remove_waiter()
|
||||
operates on current for the dequeue operation. That results in several
|
||||
problems:
|
||||
|
||||
1) the rbtree dequeue happens without waiter::task::pi_lock being held
|
||||
|
||||
2) the waiter task's pi_blocked_on state is not cleared, which leaves a
|
||||
dangling pointer primed for UAF around.
|
||||
|
||||
3) rt_mutex_adjust_prio_chain() operates on the wrong top priority waiter
|
||||
task
|
||||
|
||||
Use waiter::task instead of current in all related operations in
|
||||
remove_waiter() to cure those problems.
|
||||
|
||||
[ tglx: Fixup rt_mutex_adjust_prio_chain(), add a comment and amend the
|
||||
changelog ]
|
||||
|
||||
Fixes: 8161239a8bcc ("rtmutex: Simplify PI algorithm and make highest prio task get lock")
|
||||
Reported-by: Yuan Tan <yuantan098@gmail.com>
|
||||
Reported-by: Yifan Wu <yifanwucs@gmail.com>
|
||||
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
|
||||
Reported-by: Xin Liu <bird@lzu.edu.cn>
|
||||
Signed-off-by: Keenan Dong <keenanat2000@gmail.com>
|
||||
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
|
||||
(cherry picked from commit 3bfdc63936dd4773109b7b8c280c0f3b5ae7d349)
|
||||
[AlmaLinux: adapted to a10 (6.12); context/line offsets only. scoped_guard(raw_spinlock, ...) is available in this tree (include/linux/cleanup.h + DEFINE_LOCK_GUARD_1 raw_spinlock in include/linux/spinlock.h), so the upstream form is used verbatim.]
|
||||
---
|
||||
kernel/locking/rtmutex.c | 13 ++++++++-----
|
||||
1 file changed, 8 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
|
||||
index 4a8df18..e6f305d 100644
|
||||
--- a/kernel/locking/rtmutex.c
|
||||
+++ b/kernel/locking/rtmutex.c
|
||||
@@ -1534,20 +1534,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);
|
||||
- rt_mutex_dequeue(lock, waiter);
|
||||
- current->pi_blocked_on = NULL;
|
||||
- raw_spin_unlock(¤t->pi_lock);
|
||||
+ scoped_guard(raw_spinlock, &waiter_task->pi_lock) {
|
||||
+ rt_mutex_dequeue(lock, waiter);
|
||||
+ waiter_task->pi_blocked_on = NULL;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* Only update priority if the waiter was the highest priority
|
||||
@@ -1583,7 +1586,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.50.1
|
||||
@ -1,70 +0,0 @@
|
||||
From 40a25d59e85b3c8709ac2424d44f65610467871e Mon Sep 17 00:00:00 2001
|
||||
From: Davidlohr Bueso <dave@stgolabs.net>
|
||||
Date: Thu, 7 May 2026 04:29:13 -0700
|
||||
Subject: [PATCH] locking/rtmutex: Skip remove_waiter() when waiter is not
|
||||
enqueued
|
||||
|
||||
syzbot triggered the following splat in remove_waiter() via
|
||||
FUTEX_CMP_REQUEUE_PI:
|
||||
|
||||
KASAN: null-ptr-deref in range [0x0000000000000a88-0x0000000000000a8f]
|
||||
class_raw_spinlock_constructor
|
||||
remove_waiter+0x159/0x1200 kernel/locking/rtmutex.c:1561
|
||||
rt_mutex_start_proxy_lock+0x103/0x120
|
||||
futex_requeue+0x10e4/0x20d0
|
||||
__x64_sys_futex+0x34f/0x4d0
|
||||
|
||||
task_blocks_on_rt_mutex() does not arm the waiter upon deadlock detection,
|
||||
leaving waiter->task nil, where 3bfdc63936dd ("rtmutex: Use waiter::task instead
|
||||
of current in remove_waiter()") made this fatal.
|
||||
|
||||
Furthermore, rt_mutex_start_proxy_lock() should not be calling into remove_waiter()
|
||||
upon a successfully grabbing the rtmutex. 1a1fb985f2e2 ("futex: Handle early deadlock
|
||||
return correctly"), moved the remove_waiter() out of __rt_mutex_start_proxy_lock()
|
||||
(where 'ret' was only ever 0 or < 0) into the wrapper. Tighten this check to
|
||||
account for try_to_take_rt_mutex().
|
||||
|
||||
Fixes: 3bfdc63936dd ("rtmutex: Use waiter::task instead of current in remove_waiter()")
|
||||
Reported-by: syzbot+78147abe6c524f183ee9@syzkaller.appspotmail.com
|
||||
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
|
||||
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
|
||||
Cc: stable@vger.kernel.org
|
||||
Closes: https://lore.kernel.org/all/69f114ac.050a0220.ac8b.0003.GAE@google.com/
|
||||
Link: https://patch.msgid.link/20260507112913.1019537-1-dave@stgolabs.net
|
||||
|
||||
(cherry picked from commit 40a25d59e85b3c8709ac2424d44f65610467871e)
|
||||
[AlmaLinux: adapted to a10 (6.12); context/line offsets only. Both hunks apply: remove_waiter() in kernel/locking/rtmutex.c (depends on waiter_task local from 3bfdc63936dd) and rt_mutex_start_proxy_lock() in kernel/locking/rtmutex_api.c. In this tree __rt_mutex_start_proxy_lock() returns 1 on try_to_take_rt_mutex() success, so the ret<0 tightening is required to avoid calling remove_waiter() on lock acquisition.]
|
||||
---
|
||||
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 e6f305d..15111dc 100644
|
||||
--- a/kernel/locking/rtmutex.c
|
||||
+++ b/kernel/locking/rtmutex.c
|
||||
@@ -1547,6 +1547,9 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
|
||||
|
||||
lockdep_assert_held(&lock->wait_lock);
|
||||
|
||||
+ if (!waiter_task) /* never enqueued */
|
||||
+ return;
|
||||
+
|
||||
scoped_guard(raw_spinlock, &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 6614ccd..341a540 100644
|
||||
--- a/kernel/locking/rtmutex_api.c
|
||||
+++ b/kernel/locking/rtmutex_api.c
|
||||
@@ -347,7 +347,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, &wake_q);
|
||||
- if (unlikely(ret))
|
||||
+ if (unlikely(ret < 0))
|
||||
remove_waiter(lock, waiter);
|
||||
preempt_disable();
|
||||
raw_spin_unlock_irq(&lock->wait_lock);
|
||||
--
|
||||
2.50.1
|
||||
@ -0,0 +1,71 @@
|
||||
From 942ef6b142b4e78e63c115e806f67ab31b8106d6 Mon Sep 17 00:00:00 2001
|
||||
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
|
||||
Date: Mon, 30 Mar 2026 08:07:00 +0000
|
||||
Subject: [PATCH] net: page_pool: avoid false positive warning if NAPI was
|
||||
never added
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-162141
|
||||
|
||||
commit c1e00bc4be06cacee6307cedb9b55bbaddb5044d
|
||||
Author: Jakub Kicinski <kuba@kernel.org>
|
||||
Date: Thu Feb 6 14:56:37 2025 -0800
|
||||
|
||||
net: page_pool: avoid false positive warning if NAPI was never added
|
||||
|
||||
We expect NAPI to be in disabled state when page pool is torn down.
|
||||
But it is also legal if the NAPI is completely uninitialized.
|
||||
|
||||
Reviewed-by: Mina Almasry <almasrymina@google.com>
|
||||
Link: https://patch.msgid.link/20250206225638.1387810-4-kuba@kernel.org
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
|
||||
|
||||
diff --git a/net/core/dev.h b/net/core/dev.h
|
||||
index ddf018a0d..f4fc420f7 100644
|
||||
--- a/net/core/dev.h
|
||||
+++ b/net/core/dev.h
|
||||
@@ -347,6 +347,18 @@ void xdp_do_check_flushed(struct napi_struct *napi);
|
||||
static inline void xdp_do_check_flushed(struct napi_struct *napi) { }
|
||||
#endif
|
||||
|
||||
+/* Best effort check that NAPI is not idle (can't be scheduled to run) */
|
||||
+static inline void napi_assert_will_not_race(const struct napi_struct *napi)
|
||||
+{
|
||||
+ /* uninitialized instance, can't race */
|
||||
+ if (!napi->poll_list.next)
|
||||
+ return;
|
||||
+
|
||||
+ /* SCHED bit is set on disabled instances */
|
||||
+ WARN_ON(!test_bit(NAPI_STATE_SCHED, &napi->state));
|
||||
+ WARN_ON(READ_ONCE(napi->list_owner) != -1);
|
||||
+}
|
||||
+
|
||||
void kick_defer_list_purge(struct softnet_data *sd, unsigned int cpu);
|
||||
|
||||
#define XMIT_RECURSION_LIMIT 8
|
||||
diff --git a/net/core/page_pool.c b/net/core/page_pool.c
|
||||
index 06531b7b7..15b08364d 100644
|
||||
--- a/net/core/page_pool.c
|
||||
+++ b/net/core/page_pool.c
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <trace/events/page_pool.h>
|
||||
|
||||
+#include RH_KABI_HIDE_INCLUDE("dev.h")
|
||||
#include "mp_dmabuf_devmem.h"
|
||||
#include "netmem_priv.h"
|
||||
#include "page_pool_priv.h"
|
||||
@@ -1196,11 +1197,7 @@ void page_pool_disable_direct_recycling(struct page_pool *pool)
|
||||
if (!pool->p.napi)
|
||||
return;
|
||||
|
||||
- /* To avoid races with recycling and additional barriers make sure
|
||||
- * pool and NAPI are unlinked when NAPI is disabled.
|
||||
- */
|
||||
- WARN_ON(!test_bit(NAPI_STATE_SCHED, &pool->p.napi->state));
|
||||
- WARN_ON(READ_ONCE(pool->p.napi->list_owner) != -1);
|
||||
+ napi_assert_will_not_race(pool->p.napi);
|
||||
|
||||
mutex_lock(&page_pools_lock);
|
||||
WRITE_ONCE(pool->p.napi, NULL);
|
||||
@ -0,0 +1,82 @@
|
||||
From f975a0955276579e2176a134366ed586071c7c6a Mon Sep 17 00:00:00 2001
|
||||
From: Dipayaan Roy <dipayanroy@linux.microsoft.com>
|
||||
Date: Tue, 24 Feb 2026 04:38:36 -0800
|
||||
Subject: [PATCH] net: mana: Fix double destroy_workqueue on service rescan PCI
|
||||
path
|
||||
|
||||
While testing corner cases in the driver, a use-after-free crash
|
||||
was found on the service rescan PCI path.
|
||||
|
||||
When mana_serv_reset() calls mana_gd_suspend(), mana_gd_cleanup()
|
||||
destroys gc->service_wq. If the subsequent mana_gd_resume() fails
|
||||
with -ETIMEDOUT or -EPROTO, the code falls through to
|
||||
mana_serv_rescan() which triggers pci_stop_and_remove_bus_device().
|
||||
This invokes the PCI .remove callback (mana_gd_remove), which calls
|
||||
mana_gd_cleanup() a second time, attempting to destroy the already-
|
||||
freed workqueue. Fix this by NULL-checking gc->service_wq in
|
||||
mana_gd_cleanup() and setting it to NULL after destruction.
|
||||
|
||||
Call stack of issue for reference:
|
||||
[Sat Feb 21 18:53:48 2026] Call Trace:
|
||||
[Sat Feb 21 18:53:48 2026] <TASK>
|
||||
[Sat Feb 21 18:53:48 2026] mana_gd_cleanup+0x33/0x70 [mana]
|
||||
[Sat Feb 21 18:53:48 2026] mana_gd_remove+0x3a/0xc0 [mana]
|
||||
[Sat Feb 21 18:53:48 2026] pci_device_remove+0x41/0xb0
|
||||
[Sat Feb 21 18:53:48 2026] device_remove+0x46/0x70
|
||||
[Sat Feb 21 18:53:48 2026] device_release_driver_internal+0x1e3/0x250
|
||||
[Sat Feb 21 18:53:48 2026] device_release_driver+0x12/0x20
|
||||
[Sat Feb 21 18:53:48 2026] pci_stop_bus_device+0x6a/0x90
|
||||
[Sat Feb 21 18:53:48 2026] pci_stop_and_remove_bus_device+0x13/0x30
|
||||
[Sat Feb 21 18:53:48 2026] mana_do_service+0x180/0x290 [mana]
|
||||
[Sat Feb 21 18:53:48 2026] mana_serv_func+0x24/0x50 [mana]
|
||||
[Sat Feb 21 18:53:48 2026] process_one_work+0x190/0x3d0
|
||||
[Sat Feb 21 18:53:48 2026] worker_thread+0x16e/0x2e0
|
||||
[Sat Feb 21 18:53:48 2026] kthread+0xf7/0x130
|
||||
[Sat Feb 21 18:53:48 2026] ? __pfx_worker_thread+0x10/0x10
|
||||
[Sat Feb 21 18:53:48 2026] ? __pfx_kthread+0x10/0x10
|
||||
[Sat Feb 21 18:53:48 2026] ret_from_fork+0x269/0x350
|
||||
[Sat Feb 21 18:53:48 2026] ? __pfx_kthread+0x10/0x10
|
||||
[Sat Feb 21 18:53:48 2026] ret_from_fork_asm+0x1a/0x30
|
||||
[Sat Feb 21 18:53:48 2026] </TASK>
|
||||
|
||||
Fixes: 505cc26bcae0 ("net: mana: Add support for auxiliary device servicing events")
|
||||
Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com>
|
||||
Signed-off-by: Dipayaan Roy <dipayanroy@linux.microsoft.com>
|
||||
Reviewed-by: Simon Horman <horms@kernel.org>
|
||||
Link: https://patch.msgid.link/aZ2bzL64NagfyHpg@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
|
||||
index 0055c231acf6..3926d18f1840 100644
|
||||
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
|
||||
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
|
||||
@@ -1946,7 +1946,10 @@ static void mana_gd_cleanup(struct pci_dev *pdev)
|
||||
|
||||
mana_gd_remove_irqs(pdev);
|
||||
|
||||
- destroy_workqueue(gc->service_wq);
|
||||
+ if (gc->service_wq) {
|
||||
+ destroy_workqueue(gc->service_wq);
|
||||
+ gc->service_wq = NULL;
|
||||
+ }
|
||||
dev_dbg(&pdev->dev, "mana gdma cleanup successful\n");
|
||||
}
|
||||
|
||||
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
|
||||
index 9b5a72ada5c4..f69e42651359 100644
|
||||
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
|
||||
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
|
||||
@@ -3762,7 +3762,9 @@ void mana_rdma_remove(struct gdma_dev *gd)
|
||||
}
|
||||
|
||||
WRITE_ONCE(gd->rdma_teardown, true);
|
||||
- flush_workqueue(gc->service_wq);
|
||||
+
|
||||
+ if (gc->service_wq)
|
||||
+ flush_workqueue(gc->service_wq);
|
||||
|
||||
if (gd->adev)
|
||||
remove_adev(gd);
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,33 @@
|
||||
From 87c2302813abc55c46485711a678e3c312b00666 Mon Sep 17 00:00:00 2001
|
||||
From: Shiraz Saleem <shirazsaleem@microsoft.com>
|
||||
Date: Mon, 9 Mar 2026 10:24:43 -0700
|
||||
Subject: [PATCH] net/mana: Null service_wq on setup error to prevent double
|
||||
destroy
|
||||
|
||||
In mana_gd_setup() error path, set gc->service_wq to NULL after
|
||||
destroy_workqueue() to match the cleanup in mana_gd_cleanup().
|
||||
This prevents a use-after-free if the workqueue pointer is checked
|
||||
after a failed setup.
|
||||
|
||||
Fixes: f975a0955276 ("net: mana: Fix double destroy_workqueue on service rescan PCI path")
|
||||
Signed-off-by: Shiraz Saleem <shirazsaleem@microsoft.com>
|
||||
Signed-off-by: Konstantin Taranov <kotaranov@microsoft.com>
|
||||
Reviewed-by: Simon Horman <horms@kernel.org>
|
||||
Link: https://patch.msgid.link/20260309172443.688392-1-kotaranov@linux.microsoft.com
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
|
||||
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
|
||||
index 37d2f108a839..786186c9a115 100644
|
||||
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
|
||||
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
|
||||
@@ -1934,6 +1934,7 @@ static int mana_gd_setup(struct pci_dev *pdev)
|
||||
mana_gd_remove_irqs(pdev);
|
||||
free_workqueue:
|
||||
destroy_workqueue(gc->service_wq);
|
||||
+ gc->service_wq = NULL;
|
||||
dev_err(&pdev->dev, "%s failed (error %d)\n", __func__, err);
|
||||
return err;
|
||||
}
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
From 77695a69baca9b99d95fad09fc78c2318736604f Mon Sep 17 00:00:00 2001
|
||||
From: Pengpeng Hou <pengpeng@iscas.ac.cn>
|
||||
Date: Wed, 25 Mar 2026 15:41:52 +0800
|
||||
Subject: [PATCH] net/ipv6: ioam6: prevent schema length wraparound in trace
|
||||
fill
|
||||
|
||||
[ Upstream commit 5e67ba9bb531e1ec6599a82a065dea9040b9ce50 ]
|
||||
|
||||
ioam6_fill_trace_data() stores the schema contribution to the trace
|
||||
length in a u8. With bit 22 enabled and the largest schema payload,
|
||||
sclen becomes 1 + 1020 / 4, wraps from 256 to 0, and bypasses the
|
||||
remaining-space check. __ioam6_fill_trace_data() then positions the
|
||||
write cursor without reserving the schema area but still copies the
|
||||
4-byte schema header and the full schema payload, overrunning the trace
|
||||
buffer.
|
||||
|
||||
Keep sclen in an unsigned int so the remaining-space check and the write
|
||||
cursor calculation both see the full schema length.
|
||||
|
||||
Fixes: 8c6f6fa67726 ("ipv6: ioam: IOAM Generic Netlink API")
|
||||
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
|
||||
Reviewed-by: Justin Iurman <justin.iurman@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Sasha Levin <sashal@kernel.org>
|
||||
|
||||
diff --git a/net/ipv6/ioam6.c b/net/ipv6/ioam6.c
|
||||
index a4b7b60..bdffb79 100644
|
||||
--- a/net/ipv6/ioam6.c
|
||||
+++ b/net/ipv6/ioam6.c
|
||||
@@ -698,7 +698,7 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
|
||||
struct ioam6_namespace *ns,
|
||||
struct ioam6_trace_hdr *trace,
|
||||
struct ioam6_schema *sc,
|
||||
- u8 sclen, bool is_input)
|
||||
+ unsigned int sclen, bool is_input)
|
||||
{
|
||||
struct net_device *dev = skb_dst_dev(skb);
|
||||
struct timespec64 ts;
|
||||
@@ -929,7 +929,7 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
|
||||
bool is_input)
|
||||
{
|
||||
struct ioam6_schema *sc;
|
||||
- u8 sclen = 0;
|
||||
+ unsigned int sclen = 0;
|
||||
|
||||
/* Skip if Overflow flag is set
|
||||
*/
|
||||
@ -0,0 +1,63 @@
|
||||
From 1d724378d2b1c0a475bc1743dbba105ded1b7a9d Mon Sep 17 00:00:00 2001
|
||||
From: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
|
||||
Date: Wed, 3 Jun 2026 19:00:19 +0000
|
||||
Subject: [PATCH] procfs: fix missing RCU protection when reading real_parent
|
||||
in do_task_stat()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-181905
|
||||
CVE: CVE-2026-46259
|
||||
Backported from tree(s): linux
|
||||
|
||||
commit 76149d53502cf17ef3ae454ff384551236fba867
|
||||
Author: Jinliang Zheng <alexjlzheng@tencent.com>
|
||||
Date: Wed Jan 28 16:30:07 2026 +0800
|
||||
|
||||
procfs: fix missing RCU protection when reading real_parent in do_task_stat()
|
||||
|
||||
When reading /proc/[pid]/stat, do_task_stat() accesses task->real_parent
|
||||
without proper RCU protection, which leads to:
|
||||
|
||||
cpu 0 cpu 1
|
||||
----- -----
|
||||
do_task_stat
|
||||
var = task->real_parent
|
||||
release_task
|
||||
call_rcu(delayed_put_task_struct)
|
||||
task_tgid_nr_ns(var)
|
||||
rcu_read_lock <--- Too late to protect task->real_parent!
|
||||
task_pid_ptr <--- UAF!
|
||||
rcu_read_unlock
|
||||
|
||||
This patch uses task_ppid_nr_ns() instead of task_tgid_nr_ns() to add
|
||||
proper RCU protection for accessing task->real_parent.
|
||||
|
||||
Link: https://lkml.kernel.org/r/20260128083007.3173016-1-alexjlzheng@tencent.com
|
||||
Fixes: 06fffb1267c9 ("do_task_stat: don't take rcu_read_lock()")
|
||||
Signed-off-by: Jinliang Zheng <alexjlzheng@tencent.com>
|
||||
Acked-by: Oleg Nesterov <oleg@redhat.com>
|
||||
Cc: David Hildenbrand <david@kernel.org>
|
||||
Cc: Ingo Molnar <mingo@kernel.org>
|
||||
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
|
||||
Cc: Mateusz Guzik <mjguzik@gmail.com>
|
||||
Cc: ruippan <ruippan@tencent.com>
|
||||
Cc: Usama Arif <usamaarif642@gmail.com>
|
||||
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
|
||||
|
||||
Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
|
||||
|
||||
diff --git a/fs/proc/array.c b/fs/proc/array.c
|
||||
index d6a0369caa93..11704686c097 100644
|
||||
--- a/fs/proc/array.c
|
||||
+++ b/fs/proc/array.c
|
||||
@@ -531,7 +531,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
|
||||
}
|
||||
|
||||
sid = task_session_nr_ns(task, ns);
|
||||
- ppid = task_tgid_nr_ns(task->real_parent, ns);
|
||||
+ ppid = task_ppid_nr_ns(task, ns);
|
||||
pgid = task_pgrp_nr_ns(task, ns);
|
||||
|
||||
unlock_task_sighand(task, &flags);
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
42
1426-tg3-fix-race-for-querying-speed-duplex.patch
Normal file
42
1426-tg3-fix-race-for-querying-speed-duplex.patch
Normal file
@ -0,0 +1,42 @@
|
||||
From 61ea0d078a3ccf72afe38e00b891dbe48cf25c87 Mon Sep 17 00:00:00 2001
|
||||
From: Thomas Walsh <thwalsh@redhat.com>
|
||||
Date: Fri, 5 Jun 2026 17:21:58 -0400
|
||||
Subject: [PATCH] tg3: Fix race for querying speed/duplex
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-182561
|
||||
|
||||
commit bb417456c7814d1493d98b7dd9c040bf3ce3b4ed
|
||||
Author: Thomas Bogendoerfer <tbogendoerfer@suse.de>
|
||||
Date: Wed Mar 25 12:20:53 2026 +0100
|
||||
|
||||
tg3: Fix race for querying speed/duplex
|
||||
|
||||
When driver signals carrier up via netif_carrier_on() its internal
|
||||
link_up state isn't updated immediately. This leads to inconsistent
|
||||
speed/duplex in /proc/net/bonding/bondX where the speed and duplex
|
||||
is shown as unknown while ethtool shows correct values. Fix this by
|
||||
using netif_carrier_ok() for link checking in get_ksettings function.
|
||||
|
||||
Fixes: 84421b99cedc ("tg3: Update link_up flag for phylib devices")
|
||||
Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
|
||||
Reviewed-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
Signed-off-by: Thomas Walsh <thwalsh@redhat.com>
|
||||
|
||||
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
|
||||
index 98abd0491abe..39754ee9d393 100644
|
||||
--- a/drivers/net/ethernet/broadcom/tg3.c
|
||||
+++ b/drivers/net/ethernet/broadcom/tg3.c
|
||||
@@ -12289,7 +12289,7 @@ static int tg3_get_link_ksettings(struct net_device *dev,
|
||||
ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
|
||||
advertising);
|
||||
|
||||
- if (netif_running(dev) && tp->link_up) {
|
||||
+ if (netif_running(dev) && netif_carrier_ok(dev)) {
|
||||
cmd->base.speed = tp->link_config.active_speed;
|
||||
cmd->base.duplex = tp->link_config.active_duplex;
|
||||
ethtool_convert_legacy_u32_to_link_mode(
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
From 14dc02b7c9eabd99199d9668ba1c0b4a29ed9a27 Mon Sep 17 00:00:00 2001
|
||||
From: Paulo Alcantara <paalcant@redhat.com>
|
||||
Date: Wed, 1 Jul 2026 15:54:57 -0300
|
||||
Subject: [PATCH] smb: client: fix off-by-8 bounds check in check_wsl_eas()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180047
|
||||
|
||||
commit 3d8b9d06bd3ac4c6846f5498800b0f5f8062e53b
|
||||
Author: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
Date: Mon Apr 6 15:49:37 2026 +0200
|
||||
|
||||
smb: client: fix off-by-8 bounds check in check_wsl_eas()
|
||||
|
||||
The bounds check uses (u8 *)ea + nlen + 1 + vlen as the end of the EA
|
||||
name and value, but ea_data sits at offset sizeof(struct
|
||||
smb2_file_full_ea_info) = 8 from ea, not at offset 0. The strncmp()
|
||||
later reads ea->ea_data[0..nlen-1] and the value bytes follow at
|
||||
ea_data[nlen+1..nlen+vlen], so the actual end is ea->ea_data + nlen + 1
|
||||
+ vlen. Isn't pointer math fun?
|
||||
|
||||
The earlier check (u8 *)ea > end - sizeof(*ea) only guarantees the
|
||||
8-byte header is in bounds, but since the last EA is placed within 8
|
||||
bytes of the end of the response, the name and value bytes are read past
|
||||
the end of iov.
|
||||
|
||||
Fix this mess all up by using ea->ea_data as the base for the bounds
|
||||
check.
|
||||
|
||||
An "untrusted" server can use this to leak up to 8 bytes of kernel heap
|
||||
into the EA name comparison and influence which WSL xattr the data is
|
||||
interpreted as.
|
||||
|
||||
Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com>
|
||||
Cc: Shyam Prasad N <sprasad@microsoft.com>
|
||||
Cc: Tom Talpey <tom@talpey.com>
|
||||
Cc: Bharath SM <bharathsm@microsoft.com>
|
||||
Cc: linux-cifs@vger.kernel.org
|
||||
Cc: samba-technical@lists.samba.org
|
||||
Cc: stable <stable@kernel.org>
|
||||
Assisted-by: gregkh_clanker_t1000
|
||||
Reviewed-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
|
||||
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
Signed-off-by: Steve French <stfrench@microsoft.com>
|
||||
|
||||
Signed-off-by: Paulo Alcantara <paalcant@redhat.com>
|
||||
|
||||
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
|
||||
index ea05bb4b82a1..715ff58f1742 100644
|
||||
--- a/fs/smb/client/smb2inode.c
|
||||
+++ b/fs/smb/client/smb2inode.c
|
||||
@@ -128,7 +128,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
|
||||
nlen = ea->ea_name_length;
|
||||
vlen = le16_to_cpu(ea->ea_value_length);
|
||||
if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
|
||||
- (u8 *)ea + nlen + 1 + vlen > end)
|
||||
+ (u8 *)ea->ea_data + nlen + 1 + vlen > end)
|
||||
return -EINVAL;
|
||||
|
||||
switch (vlen) {
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
From b4c153a8f7b3cf32752c8c0a81193535507baba7 Mon Sep 17 00:00:00 2001
|
||||
From: Paulo Alcantara <paalcant@redhat.com>
|
||||
Date: Wed, 1 Jul 2026 15:55:06 -0300
|
||||
Subject: [PATCH] smb/client: fix out-of-bounds read in smb2_compound_op()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180047
|
||||
CVE: CVE-2026-46155
|
||||
|
||||
commit 8d09328dfda089675e4c049f3f256064a1d1996b
|
||||
Author: Zisen Ye <zisenye@stu.xidian.edu.cn>
|
||||
Date: Wed May 6 11:49:08 2026 +0800
|
||||
|
||||
smb/client: fix out-of-bounds read in smb2_compound_op()
|
||||
|
||||
If a server sends a truncated response but a large OutputBufferLength, and
|
||||
terminates the EA list early, check_wsl_eas() returns success without
|
||||
validating that the entire OutputBufferLength fits within iov_len.
|
||||
|
||||
Then smb2_compound_op() does:
|
||||
memcpy(idata->wsl.eas, data[0], size[0]);
|
||||
|
||||
Where size[0] is OutputBufferLength. If iov_len is smaller than size[0],
|
||||
memcpy can read beyond the end of the rsp_iov allocation and leak adjacent
|
||||
kernel heap memory.
|
||||
|
||||
Link: https://lore.kernel.org/linux-cifs/d998240c-aca9-420d-9dbd-f5ba24af19e0@chenxiaosong.com/
|
||||
Fixes: ea41367b2a60 ("smb: client: introduce SMB2_OP_QUERY_WSL_EA")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Zisen Ye <zisenye@stu.xidian.edu.cn>
|
||||
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
|
||||
Signed-off-by: Steve French <stfrench@microsoft.com>
|
||||
|
||||
Signed-off-by: Paulo Alcantara <paalcant@redhat.com>
|
||||
|
||||
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
|
||||
index 715ff58f1742..2cdd46228e31 100644
|
||||
--- a/fs/smb/client/smb2inode.c
|
||||
+++ b/fs/smb/client/smb2inode.c
|
||||
@@ -111,7 +111,7 @@ static int check_wsl_eas(struct kvec *rsp_iov)
|
||||
u32 outlen, next;
|
||||
u16 vlen;
|
||||
u8 nlen;
|
||||
- u8 *end;
|
||||
+ u8 *ea_end, *iov_end;
|
||||
|
||||
outlen = le32_to_cpu(rsp->OutputBufferLength);
|
||||
if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
|
||||
@@ -120,15 +120,19 @@ static int check_wsl_eas(struct kvec *rsp_iov)
|
||||
|
||||
ea = (void *)((u8 *)rsp_iov->iov_base +
|
||||
le16_to_cpu(rsp->OutputBufferOffset));
|
||||
- end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
|
||||
+ ea_end = (u8 *)ea + outlen;
|
||||
+ iov_end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
|
||||
+ if (ea_end > iov_end)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
for (;;) {
|
||||
- if ((u8 *)ea > end - sizeof(*ea))
|
||||
+ if ((u8 *)ea > ea_end - sizeof(*ea))
|
||||
return -EINVAL;
|
||||
|
||||
nlen = ea->ea_name_length;
|
||||
vlen = le16_to_cpu(ea->ea_value_length);
|
||||
if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
|
||||
- (u8 *)ea->ea_data + nlen + 1 + vlen > end)
|
||||
+ (u8 *)ea->ea_data + nlen + 1 + vlen > ea_end)
|
||||
return -EINVAL;
|
||||
|
||||
switch (vlen) {
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
66
1429-epoll-annotate-racy-check.patch
Normal file
66
1429-epoll-annotate-racy-check.patch
Normal file
@ -0,0 +1,66 @@
|
||||
From bde1be0c6e5eeb145576344159be1f51cb8d5d8b Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 15:53:22 +0800
|
||||
Subject: [PATCH] epoll: annotate racy check
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 6474353a5e3d0b2cf610153cea0c61f576a36d0a
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Wed Sep 25 11:05:16 2024 +0200
|
||||
|
||||
epoll: annotate racy check
|
||||
|
||||
Epoll relies on a racy fastpath check during __fput() in
|
||||
eventpoll_release() to avoid the hit of pointlessly acquiring a
|
||||
semaphore. Annotate that race by using WRITE_ONCE() and READ_ONCE().
|
||||
|
||||
Link: https://lore.kernel.org/r/66edfb3c.050a0220.3195df.001a.GAE@google.com
|
||||
Link: https://lore.kernel.org/r/20240925-fungieren-anbauen-79b334b00542@brauner
|
||||
Reviewed-by: Jan Kara <jack@suse.cz>
|
||||
Reported-by: syzbot+3b6b32dc50537a49bb4a@syzkaller.appspotmail.com
|
||||
Signed-off-by: Christian Brauner <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index a7efeb499e4b..616f97e9b75b 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -852,7 +852,8 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
to_free = NULL;
|
||||
head = file->f_ep;
|
||||
if (head->first == &epi->fllink && !epi->fllink.next) {
|
||||
- file->f_ep = NULL;
|
||||
+ /* See eventpoll_release() for details. */
|
||||
+ WRITE_ONCE(file->f_ep, NULL);
|
||||
if (!is_file_epoll(file)) {
|
||||
struct epitems_head *v;
|
||||
v = container_of(head, struct epitems_head, epitems);
|
||||
@@ -1630,7 +1631,8 @@ static int attach_epitem(struct file *file, struct epitem *epi)
|
||||
spin_unlock(&file->f_lock);
|
||||
goto allocate;
|
||||
}
|
||||
- file->f_ep = head;
|
||||
+ /* See eventpoll_release() for details. */
|
||||
+ WRITE_ONCE(file->f_ep, head);
|
||||
to_free = NULL;
|
||||
}
|
||||
hlist_add_head_rcu(&epi->fllink, file->f_ep);
|
||||
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
|
||||
index 3337745d81bd..0c0d00fcd131 100644
|
||||
--- a/include/linux/eventpoll.h
|
||||
+++ b/include/linux/eventpoll.h
|
||||
@@ -42,7 +42,7 @@ static inline void eventpoll_release(struct file *file)
|
||||
* because the file in on the way to be removed and nobody ( but
|
||||
* eventpoll ) has still a reference to this file.
|
||||
*/
|
||||
- if (likely(!file->f_ep))
|
||||
+ if (likely(!READ_ONCE(file->f_ep)))
|
||||
return;
|
||||
|
||||
/*
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
From 2b62eb17ec16b6a7d341497e48e331f84280cd58 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 15:54:24 +0800
|
||||
Subject: [PATCH] eventpoll: defer struct eventpoll free to RCU grace period
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-173837
|
||||
Upstream status: Linus
|
||||
|
||||
CVE: CVE-2026-43074
|
||||
|
||||
commit 07712db80857d5d09ae08f3df85a708ecfc3b61f
|
||||
Author: Nicholas Carlini <nicholas@carlini.com>
|
||||
Date: Tue Mar 31 15:25:32 2026 +0200
|
||||
|
||||
eventpoll: defer struct eventpoll free to RCU grace period
|
||||
|
||||
In certain situations, ep_free() in eventpoll.c will kfree the epi->ep
|
||||
eventpoll struct while it still being used by another concurrent thread.
|
||||
Defer the kfree() to an RCU callback to prevent UAF.
|
||||
|
||||
Fixes: f2e467a48287 ("eventpoll: Fix semi-unbounded recursion")
|
||||
Signed-off-by: Nicholas Carlini <nicholas@carlini.com>
|
||||
Signed-off-by: Christian Brauner <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 616f97e9b75b..0368ab69138a 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -225,6 +225,9 @@ struct eventpoll {
|
||||
*/
|
||||
refcount_t refcount;
|
||||
|
||||
+ /* used to defer freeing past ep_get_upwards_depth_proc() RCU walk */
|
||||
+ struct rcu_head rcu;
|
||||
+
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
/* used to track busy poll napi_id */
|
||||
unsigned int napi_id;
|
||||
@@ -818,7 +821,8 @@ static void ep_free(struct eventpoll *ep)
|
||||
mutex_destroy(&ep->mtx);
|
||||
free_uid(ep->user);
|
||||
wakeup_source_unregister(ep->ws);
|
||||
- kfree(ep);
|
||||
+ /* ep_get_upwards_depth_proc() may still hold epi->ep under RCU */
|
||||
+ kfree_rcu(ep, rcu);
|
||||
}
|
||||
|
||||
/*
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
39
1431-eventpoll-use-hlist-is-singular-node-in-ep-remove.patch
Normal file
39
1431-eventpoll-use-hlist-is-singular-node-in-ep-remove.patch
Normal file
@ -0,0 +1,39 @@
|
||||
From 1fe6204c6ea38fc1d370d9bbb9fd6a800104e5c8 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 15:54:59 +0800
|
||||
Subject: [PATCH] eventpoll: use hlist_is_singular_node() in __ep_remove()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 3d9fd0abc94d8cd430cc7cd7d37ce5e5aae2cd2b
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:04 2026 +0200
|
||||
|
||||
eventpoll: use hlist_is_singular_node() in __ep_remove()
|
||||
|
||||
Replace the open-coded "epi is the only entry in file->f_ep" check
|
||||
with hlist_is_singular_node(). Same semantics, and the helper avoids
|
||||
the head-cacheline access in the common false case.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-1-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 0368ab69138a..2dd87800bfbf 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -855,7 +855,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
|
||||
to_free = NULL;
|
||||
head = file->f_ep;
|
||||
- if (head->first == &epi->fllink && !epi->fllink.next) {
|
||||
+ if (hlist_is_singular_node(&epi->fllink, head)) {
|
||||
/* See eventpoll_release() for details. */
|
||||
WRITE_ONCE(file->f_ep, NULL);
|
||||
if (!is_file_epoll(file)) {
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
84
1432-eventpoll-split-ep-remove.patch
Normal file
84
1432-eventpoll-split-ep-remove.patch
Normal file
@ -0,0 +1,84 @@
|
||||
From 83db11e5ba3c57104945247e11c1891355a12fb6 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 15:55:51 +0800
|
||||
Subject: [PATCH] eventpoll: split __ep_remove()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 0f7bdfd413000985de09fc39eb9efa1e091a3ce0
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:05 2026 +0200
|
||||
|
||||
eventpoll: split __ep_remove()
|
||||
|
||||
Split __ep_remove() to delineate file removal from epoll item removal.
|
||||
|
||||
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-2-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 2dd87800bfbf..001c87b6ddab 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -825,6 +825,9 @@ static void ep_free(struct eventpoll *ep)
|
||||
kfree_rcu(ep, rcu);
|
||||
}
|
||||
|
||||
+static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file);
|
||||
+static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi);
|
||||
+
|
||||
/*
|
||||
* Removes a "struct epitem" from the eventpoll RB tree and deallocates
|
||||
* all the associated resources. Must be called with "mtx" held.
|
||||
@@ -836,8 +839,6 @@ static void ep_free(struct eventpoll *ep)
|
||||
static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
{
|
||||
struct file *file = epi->ffd.file;
|
||||
- struct epitems_head *to_free;
|
||||
- struct hlist_head *head;
|
||||
|
||||
lockdep_assert_irqs_enabled();
|
||||
|
||||
@@ -853,8 +854,21 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
return false;
|
||||
}
|
||||
|
||||
- to_free = NULL;
|
||||
- head = file->f_ep;
|
||||
+ __ep_remove_file(ep, epi, file);
|
||||
+ return __ep_remove_epi(ep, epi);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Called with &file->f_lock held,
|
||||
+ * returns with it released
|
||||
+ */
|
||||
+static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file)
|
||||
+{
|
||||
+ struct epitems_head *to_free = NULL;
|
||||
+ struct hlist_head *head = file->f_ep;
|
||||
+
|
||||
+ lockdep_assert_held(&ep->mtx);
|
||||
+
|
||||
if (hlist_is_singular_node(&epi->fllink, head)) {
|
||||
/* See eventpoll_release() for details. */
|
||||
WRITE_ONCE(file->f_ep, NULL);
|
||||
@@ -868,6 +882,11 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
hlist_del_rcu(&epi->fllink);
|
||||
spin_unlock(&file->f_lock);
|
||||
free_ephead(to_free);
|
||||
+}
|
||||
+
|
||||
+static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
+{
|
||||
+ lockdep_assert_held(&ep->mtx);
|
||||
|
||||
rb_erase_cached(&epi->rbn, &ep->rbr);
|
||||
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
134
1433-eventpoll-kill-ep-remove.patch
Normal file
134
1433-eventpoll-kill-ep-remove.patch
Normal file
@ -0,0 +1,134 @@
|
||||
From 9a9a41f8aa46741f965703f520542e9e8fdbe59f Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 15:56:21 +0800
|
||||
Subject: [PATCH] eventpoll: kill __ep_remove()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit e9e5cd40d7c403e19f21d0f7b8b8ba3a76b58330
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:06 2026 +0200
|
||||
|
||||
eventpoll: kill __ep_remove()
|
||||
|
||||
Remove the boolean conditional in __ep_remove() and restructure the code
|
||||
so the check for racing with eventpoll_release_file() are only done in
|
||||
the ep_remove_safe() path where they belong.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-3-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 001c87b6ddab..cb75868ba1de 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -825,49 +825,18 @@ static void ep_free(struct eventpoll *ep)
|
||||
kfree_rcu(ep, rcu);
|
||||
}
|
||||
|
||||
-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file);
|
||||
-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi);
|
||||
-
|
||||
-/*
|
||||
- * Removes a "struct epitem" from the eventpoll RB tree and deallocates
|
||||
- * all the associated resources. Must be called with "mtx" held.
|
||||
- * If the dying flag is set, do the removal only if force is true.
|
||||
- * This prevents ep_clear_and_put() from dropping all the ep references
|
||||
- * while running concurrently with eventpoll_release_file().
|
||||
- * Returns true if the eventpoll can be disposed.
|
||||
- */
|
||||
-static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)
|
||||
-{
|
||||
- struct file *file = epi->ffd.file;
|
||||
-
|
||||
- lockdep_assert_irqs_enabled();
|
||||
-
|
||||
- /*
|
||||
- * Removes poll wait queue hooks.
|
||||
- */
|
||||
- ep_unregister_pollwait(ep, epi);
|
||||
-
|
||||
- /* Remove the current item from the list of epoll hooks */
|
||||
- spin_lock(&file->f_lock);
|
||||
- if (epi->dying && !force) {
|
||||
- spin_unlock(&file->f_lock);
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- __ep_remove_file(ep, epi, file);
|
||||
- return __ep_remove_epi(ep, epi);
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* Called with &file->f_lock held,
|
||||
* returns with it released
|
||||
*/
|
||||
-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file)
|
||||
+static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,
|
||||
+ struct file *file)
|
||||
{
|
||||
struct epitems_head *to_free = NULL;
|
||||
struct hlist_head *head = file->f_ep;
|
||||
|
||||
lockdep_assert_held(&ep->mtx);
|
||||
+ lockdep_assert_held(&file->f_lock);
|
||||
|
||||
if (hlist_is_singular_node(&epi->fllink, head)) {
|
||||
/* See eventpoll_release() for details. */
|
||||
@@ -914,7 +883,25 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
*/
|
||||
static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)
|
||||
{
|
||||
- if (__ep_remove(ep, epi, false))
|
||||
+ struct file *file = epi->ffd.file;
|
||||
+
|
||||
+ lockdep_assert_irqs_enabled();
|
||||
+ lockdep_assert_held(&ep->mtx);
|
||||
+
|
||||
+ ep_unregister_pollwait(ep, epi);
|
||||
+
|
||||
+ /* sync with eventpoll_release_file() */
|
||||
+ if (unlikely(READ_ONCE(epi->dying)))
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock(&file->f_lock);
|
||||
+ if (epi->dying) {
|
||||
+ spin_unlock(&file->f_lock);
|
||||
+ return;
|
||||
+ }
|
||||
+ __ep_remove_file(ep, epi, file);
|
||||
+
|
||||
+ if (__ep_remove_epi(ep, epi))
|
||||
WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
|
||||
}
|
||||
|
||||
@@ -1146,7 +1133,7 @@ void eventpoll_release_file(struct file *file)
|
||||
spin_lock(&file->f_lock);
|
||||
if (file->f_ep && file->f_ep->first) {
|
||||
epi = hlist_entry(file->f_ep->first, struct epitem, fllink);
|
||||
- epi->dying = true;
|
||||
+ WRITE_ONCE(epi->dying, true);
|
||||
spin_unlock(&file->f_lock);
|
||||
|
||||
/*
|
||||
@@ -1155,7 +1142,13 @@ void eventpoll_release_file(struct file *file)
|
||||
*/
|
||||
ep = epi->ep;
|
||||
mutex_lock(&ep->mtx);
|
||||
- dispose = __ep_remove(ep, epi, true);
|
||||
+
|
||||
+ ep_unregister_pollwait(ep, epi);
|
||||
+
|
||||
+ spin_lock(&file->f_lock);
|
||||
+ __ep_remove_file(ep, epi, file);
|
||||
+ dispose = __ep_remove_epi(ep, epi);
|
||||
+
|
||||
mutex_unlock(&ep->mtx);
|
||||
|
||||
if (dispose && ep_refcount_dec_and_test(ep))
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
98
1434-eventpoll-rename-ep-remove-safe-back-to-ep-remove.patch
Normal file
98
1434-eventpoll-rename-ep-remove-safe-back-to-ep-remove.patch
Normal file
@ -0,0 +1,98 @@
|
||||
From 4e16f36e52dfe03056ec8c4daaef79b1715bb341 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 15:58:37 +0800
|
||||
Subject: [PATCH] eventpoll: rename ep_remove_safe() back to ep_remove()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 0bade234723e40e4937be912e105785d6a51464e
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:07 2026 +0200
|
||||
|
||||
eventpoll: rename ep_remove_safe() back to ep_remove()
|
||||
|
||||
The current name is just confusing and doesn't clarify anything.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-4-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index cb75868ba1de..efc9e3e1e3f5 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -881,7 +881,7 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
/*
|
||||
* ep_remove variant for callers owing an additional reference to the ep
|
||||
*/
|
||||
-static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)
|
||||
+static void ep_remove(struct eventpoll *ep, struct epitem *epi)
|
||||
{
|
||||
struct file *file = epi->ffd.file;
|
||||
|
||||
@@ -928,7 +928,7 @@ static void ep_clear_and_put(struct eventpoll *ep)
|
||||
|
||||
/*
|
||||
* Walks through the whole tree and try to free each "struct epitem".
|
||||
- * Note that ep_remove_safe() will not remove the epitem in case of a
|
||||
+ * Note that ep_remove() will not remove the epitem in case of a
|
||||
* racing eventpoll_release_file(); the latter will do the removal.
|
||||
* At this point we are sure no poll callbacks will be lingering around.
|
||||
* Since we still own a reference to the eventpoll struct, the loop can't
|
||||
@@ -937,7 +937,7 @@ static void ep_clear_and_put(struct eventpoll *ep)
|
||||
for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = next) {
|
||||
next = rb_next(rbp);
|
||||
epi = rb_entry(rbp, struct epitem, rbn);
|
||||
- ep_remove_safe(ep, epi);
|
||||
+ ep_remove(ep, epi);
|
||||
cond_resched();
|
||||
}
|
||||
|
||||
@@ -1714,21 +1714,21 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
|
||||
mutex_unlock(&tep->mtx);
|
||||
|
||||
/*
|
||||
- * ep_remove_safe() calls in the later error paths can't lead to
|
||||
+ * ep_remove() calls in the later error paths can't lead to
|
||||
* ep_free() as the ep file itself still holds an ep reference.
|
||||
*/
|
||||
ep_get(ep);
|
||||
|
||||
/* now check if we've created too many backpaths */
|
||||
if (unlikely(full_check && reverse_path_check())) {
|
||||
- ep_remove_safe(ep, epi);
|
||||
+ ep_remove(ep, epi);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (epi->event.events & EPOLLWAKEUP) {
|
||||
error = ep_create_wakeup_source(epi);
|
||||
if (error) {
|
||||
- ep_remove_safe(ep, epi);
|
||||
+ ep_remove(ep, epi);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
@@ -1752,7 +1752,7 @@ static int ep_insert(struct eventpoll *ep, const struct epoll_event *event,
|
||||
* high memory pressure.
|
||||
*/
|
||||
if (unlikely(!epq.epi)) {
|
||||
- ep_remove_safe(ep, epi);
|
||||
+ ep_remove(ep, epi);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -2415,7 +2415,7 @@ int do_epoll_ctl(int epfd, int op, int fd, struct epoll_event *epds,
|
||||
* The eventpoll itself is still alive: the refcount
|
||||
* can't go to zero here.
|
||||
*/
|
||||
- ep_remove_safe(ep, epi);
|
||||
+ ep_remove(ep, epi);
|
||||
error = 0;
|
||||
} else {
|
||||
error = -ENOENT;
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
98
1435-eventpoll-move-epi-fget-up.patch
Normal file
98
1435-eventpoll-move-epi-fget-up.patch
Normal file
@ -0,0 +1,98 @@
|
||||
From 8c1707336e5674c16c2a24c9cdf2b5018b166a09 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 16:00:26 +0800
|
||||
Subject: [PATCH] eventpoll: move epi_fget() up
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 86e87059e6d1fd5115a31949726450ed03c1073b
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:08 2026 +0200
|
||||
|
||||
eventpoll: move epi_fget() up
|
||||
|
||||
We'll need it when removing files so move it up. No functional change.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-5-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index efc9e3e1e3f5..ded53c6fbd6f 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -825,6 +825,34 @@ static void ep_free(struct eventpoll *ep)
|
||||
kfree_rcu(ep, rcu);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * The ffd.file pointer may be in the process of being torn down due to
|
||||
+ * being closed, but we may not have finished eventpoll_release() yet.
|
||||
+ *
|
||||
+ * Normally, even with the atomic_long_inc_not_zero, the file may have
|
||||
+ * been free'd and then gotten re-allocated to something else (since
|
||||
+ * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
|
||||
+ *
|
||||
+ * But for epoll, users hold the ep->mtx mutex, and as such any file in
|
||||
+ * the process of being free'd will block in eventpoll_release_file()
|
||||
+ * and thus the underlying file allocation will not be free'd, and the
|
||||
+ * file re-use cannot happen.
|
||||
+ *
|
||||
+ * For the same reason we can avoid a rcu_read_lock() around the
|
||||
+ * operation - 'ffd.file' cannot go away even if the refcount has
|
||||
+ * reached zero (but we must still not call out to ->poll() functions
|
||||
+ * etc).
|
||||
+ */
|
||||
+static struct file *epi_fget(const struct epitem *epi)
|
||||
+{
|
||||
+ struct file *file;
|
||||
+
|
||||
+ file = epi->ffd.file;
|
||||
+ if (!file_ref_get(&file->f_ref))
|
||||
+ file = NULL;
|
||||
+ return file;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Called with &file->f_lock held,
|
||||
* returns with it released
|
||||
@@ -1017,34 +1045,6 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep
|
||||
return res;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * The ffd.file pointer may be in the process of being torn down due to
|
||||
- * being closed, but we may not have finished eventpoll_release() yet.
|
||||
- *
|
||||
- * Normally, even with the atomic_long_inc_not_zero, the file may have
|
||||
- * been free'd and then gotten re-allocated to something else (since
|
||||
- * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
|
||||
- *
|
||||
- * But for epoll, users hold the ep->mtx mutex, and as such any file in
|
||||
- * the process of being free'd will block in eventpoll_release_file()
|
||||
- * and thus the underlying file allocation will not be free'd, and the
|
||||
- * file re-use cannot happen.
|
||||
- *
|
||||
- * For the same reason we can avoid a rcu_read_lock() around the
|
||||
- * operation - 'ffd.file' cannot go away even if the refcount has
|
||||
- * reached zero (but we must still not call out to ->poll() functions
|
||||
- * etc).
|
||||
- */
|
||||
-static struct file *epi_fget(const struct epitem *epi)
|
||||
-{
|
||||
- struct file *file;
|
||||
-
|
||||
- file = epi->ffd.file;
|
||||
- if (!file_ref_get(&file->f_ref))
|
||||
- file = NULL;
|
||||
- return file;
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* Differs from ep_eventpoll_poll() in that internal callers already have
|
||||
* the ep->mtx so we need to start from depth=1, such that mutex_lock_nested()
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
From 6175a9a692e559e7f0635d3a32d20fe94bae8280 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 15:57:24 +0800
|
||||
Subject: [PATCH] eventpoll: drop vestigial __ prefix from
|
||||
ep_remove_{file,epi}()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
Conflict: I don't know how this commit is present when commit
|
||||
d3608d9e2f5a ("eventpoll: fix ep_remove struct eventpoll /
|
||||
struct file UAF") is applied since its time stamp is later than
|
||||
the afore mentioned commit. I've applied it here purely to avoid
|
||||
the subsequent conflict.
|
||||
|
||||
commit 0feaf644f7180c4a91b6b405a881afbfd958f1cf
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Fri Apr 24 00:23:18 2026 +0200
|
||||
|
||||
eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}()
|
||||
|
||||
With __ep_remove() gone, the double-underscore on __ep_remove_file()
|
||||
and __ep_remove_epi() no longer contrasts with a __-less parent and
|
||||
just reads as noise. Rename both to ep_remove_file() and
|
||||
ep_remove_epi(). No functional change.
|
||||
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index ded53c6fbd6f..1246c0517aa6 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -857,7 +857,7 @@ static struct file *epi_fget(const struct epitem *epi)
|
||||
* Called with &file->f_lock held,
|
||||
* returns with it released
|
||||
*/
|
||||
-static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,
|
||||
+static void ep_remove_file(struct eventpoll *ep, struct epitem *epi,
|
||||
struct file *file)
|
||||
{
|
||||
struct epitems_head *to_free = NULL;
|
||||
@@ -881,7 +881,7 @@ static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,
|
||||
free_ephead(to_free);
|
||||
}
|
||||
|
||||
-static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
+static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
{
|
||||
lockdep_assert_held(&ep->mtx);
|
||||
|
||||
@@ -927,9 +927,9 @@ static void ep_remove(struct eventpoll *ep, struct epitem *epi)
|
||||
spin_unlock(&file->f_lock);
|
||||
return;
|
||||
}
|
||||
- __ep_remove_file(ep, epi, file);
|
||||
+ ep_remove_file(ep, epi, file);
|
||||
|
||||
- if (__ep_remove_epi(ep, epi))
|
||||
+ if (ep_remove_epi(ep, epi))
|
||||
WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
|
||||
}
|
||||
|
||||
@@ -1146,8 +1146,8 @@ void eventpoll_release_file(struct file *file)
|
||||
ep_unregister_pollwait(ep, epi);
|
||||
|
||||
spin_lock(&file->f_lock);
|
||||
- __ep_remove_file(ep, epi, file);
|
||||
- dispose = __ep_remove_epi(ep, epi);
|
||||
+ ep_remove_file(ep, epi, file);
|
||||
+ dispose = ep_remove_epi(ep, epi);
|
||||
|
||||
mutex_unlock(&ep->mtx);
|
||||
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,104 @@
|
||||
From 5c53e2d149e55d3ee64fb03387d2f81d59477774 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 16:00:59 +0800
|
||||
Subject: [PATCH] eventpoll: fix ep_remove struct eventpoll / struct file UAF
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
CVE: CVE-2026-46242
|
||||
|
||||
commit a6dc643c69311677c574a0f17a3f4d66a5f3744b
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:09 2026 +0200
|
||||
|
||||
eventpoll: fix ep_remove struct eventpoll / struct file UAF
|
||||
|
||||
ep_remove() (via ep_remove_file()) cleared file->f_ep under
|
||||
file->f_lock but then kept using @file inside the critical section
|
||||
(is_file_epoll(), hlist_del_rcu() through the head, spin_unlock).
|
||||
A concurrent __fput() taking the eventpoll_release() fastpath in
|
||||
that window observed the transient NULL, skipped
|
||||
eventpoll_release_file() and ran to f_op->release / file_free().
|
||||
|
||||
For the epoll-watches-epoll case, f_op->release is
|
||||
ep_eventpoll_release() -> ep_clear_and_put() -> ep_free(), which
|
||||
kfree()s the watched struct eventpoll. Its embedded ->refs
|
||||
hlist_head is exactly where epi->fllink.pprev points, so the
|
||||
subsequent hlist_del_rcu()'s "*pprev = next" scribbles into freed
|
||||
kmalloc-192 memory.
|
||||
|
||||
In addition, struct file is SLAB_TYPESAFE_BY_RCU, so the slot
|
||||
backing @file could be recycled by alloc_empty_file() --
|
||||
reinitializing f_lock and f_ep -- while ep_remove() is still
|
||||
nominally inside that lock. The upshot is an attacker-controllable
|
||||
kmem_cache_free() against the wrong slab cache.
|
||||
|
||||
Pin @file via epi_fget() at the top of ep_remove() and gate the
|
||||
critical section on the pin succeeding. With the pin held @file
|
||||
cannot reach refcount zero, which holds __fput() off and
|
||||
transitively keeps the watched struct eventpoll alive across the
|
||||
hlist_del_rcu() and the f_lock use, closing both UAFs.
|
||||
|
||||
If the pin fails @file has already reached refcount zero and its
|
||||
__fput() is in flight. Because we bailed before clearing f_ep,
|
||||
that path takes the eventpoll_release() slow path into
|
||||
eventpoll_release_file() and blocks on ep->mtx until the waiter
|
||||
side's ep_clear_and_put() drops it. The bailed epi's share of
|
||||
ep->refcount stays intact, so the trailing ep_refcount_dec_and_test()
|
||||
in ep_clear_and_put() cannot free the eventpoll out from under
|
||||
eventpoll_release_file(); the orphaned epi is then cleaned up
|
||||
there.
|
||||
|
||||
A successful pin also proves we are not racing
|
||||
eventpoll_release_file() on this epi, so drop the now-redundant
|
||||
re-check of epi->dying under f_lock. The cheap lockless
|
||||
READ_ONCE(epi->dying) fast-path bailout stays.
|
||||
|
||||
Fixes: 58c9b016e128 ("epoll: use refcount to reduce ep_mutex contention")
|
||||
Reported-by: Jaeyoung Chung <jjy600901@snu.ac.kr>
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-6-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 1246c0517aa6..f46906640a9b 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -911,22 +911,26 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
*/
|
||||
static void ep_remove(struct eventpoll *ep, struct epitem *epi)
|
||||
{
|
||||
- struct file *file = epi->ffd.file;
|
||||
+ struct file *file __free(fput) = NULL;
|
||||
|
||||
lockdep_assert_irqs_enabled();
|
||||
lockdep_assert_held(&ep->mtx);
|
||||
|
||||
ep_unregister_pollwait(ep, epi);
|
||||
|
||||
- /* sync with eventpoll_release_file() */
|
||||
+ /* cheap sync with eventpoll_release_file() */
|
||||
if (unlikely(READ_ONCE(epi->dying)))
|
||||
return;
|
||||
|
||||
- spin_lock(&file->f_lock);
|
||||
- if (epi->dying) {
|
||||
- spin_unlock(&file->f_lock);
|
||||
+ /*
|
||||
+ * If we manage to grab a reference it means we're not in
|
||||
+ * eventpoll_release_file() and aren't going to be.
|
||||
+ */
|
||||
+ file = epi_fget(epi);
|
||||
+ if (!file)
|
||||
return;
|
||||
- }
|
||||
+
|
||||
+ spin_lock(&file->f_lock);
|
||||
ep_remove_file(ep, epi, file);
|
||||
|
||||
if (ep_remove_epi(ep, epi))
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,70 @@
|
||||
From e0bf480728b83ec6ceb66975bfbac514195873c8 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 16:01:51 +0800
|
||||
Subject: [PATCH] eventpoll: move f_lock acquisition into ep_remove_file()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit d30deeb8b0cf6259785c1fb79b87905d281b0a5a
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:10 2026 +0200
|
||||
|
||||
eventpoll: move f_lock acquisition into ep_remove_file()
|
||||
|
||||
Let the helper own its critical section end-to-end: take &file->f_lock
|
||||
at the top, read file->f_ep inside the lock, release on exit. Callers
|
||||
(ep_remove() and eventpoll_release_file()) no longer need to wrap the
|
||||
call, and the function-comment lock-handoff contract is gone.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-7-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index f46906640a9b..9798ab5f7663 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -854,18 +854,18 @@ static struct file *epi_fget(const struct epitem *epi)
|
||||
}
|
||||
|
||||
/*
|
||||
- * Called with &file->f_lock held,
|
||||
- * returns with it released
|
||||
+ * Takes &file->f_lock; returns with it released.
|
||||
*/
|
||||
static void ep_remove_file(struct eventpoll *ep, struct epitem *epi,
|
||||
struct file *file)
|
||||
{
|
||||
struct epitems_head *to_free = NULL;
|
||||
- struct hlist_head *head = file->f_ep;
|
||||
+ struct hlist_head *head;
|
||||
|
||||
lockdep_assert_held(&ep->mtx);
|
||||
- lockdep_assert_held(&file->f_lock);
|
||||
|
||||
+ spin_lock(&file->f_lock);
|
||||
+ head = file->f_ep;
|
||||
if (hlist_is_singular_node(&epi->fllink, head)) {
|
||||
/* See eventpoll_release() for details. */
|
||||
WRITE_ONCE(file->f_ep, NULL);
|
||||
@@ -930,7 +930,6 @@ static void ep_remove(struct eventpoll *ep, struct epitem *epi)
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
- spin_lock(&file->f_lock);
|
||||
ep_remove_file(ep, epi, file);
|
||||
|
||||
if (ep_remove_epi(ep, epi))
|
||||
@@ -1149,7 +1148,6 @@ void eventpoll_release_file(struct file *file)
|
||||
|
||||
ep_unregister_pollwait(ep, epi);
|
||||
|
||||
- spin_lock(&file->f_lock);
|
||||
ep_remove_file(ep, epi, file);
|
||||
dispose = ep_remove_epi(ep, epi);
|
||||
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,66 @@
|
||||
From eab8e8be1be2430b6712fc1a6c8925d240a40031 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 16:02:27 +0800
|
||||
Subject: [PATCH] eventpoll: refresh eventpoll_release() fast-path comment
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 33e92e9ecf48c08cb4807e9a36f9eb01619c1a1e
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:11 2026 +0200
|
||||
|
||||
eventpoll: refresh eventpoll_release() fast-path comment
|
||||
|
||||
The old comment justified the lockless READ_ONCE(file->f_ep) check
|
||||
with "False positives simply cannot happen because the file is on
|
||||
the way to be removed and nobody ( but eventpoll ) has still a
|
||||
reference to this file." That reasoning was the root of the UAF
|
||||
fixed in "eventpoll: fix ep_remove struct eventpoll / struct file
|
||||
UAF": __ep_remove() could clear f_ep while another close raced
|
||||
past the fast path and freed the watched eventpoll / recycled the
|
||||
struct file slot.
|
||||
|
||||
With ep_remove() now pinning @file via epi_fget() across the f_ep
|
||||
clear and hlist_del_rcu(), the invariant is re-established for the
|
||||
right reason: anyone who might clear f_ep holds @file alive for
|
||||
the duration, so a NULL observation really does mean no
|
||||
concurrent eventpoll path has work left on this file. Refresh the
|
||||
comment accordingly so the next reader doesn't inherit the broken
|
||||
model.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-8-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
|
||||
index 0c0d00fcd131..be762281355a 100644
|
||||
--- a/include/linux/eventpoll.h
|
||||
+++ b/include/linux/eventpoll.h
|
||||
@@ -35,12 +35,16 @@ static inline void eventpoll_release(struct file *file)
|
||||
{
|
||||
|
||||
/*
|
||||
- * Fast check to avoid the get/release of the semaphore. Since
|
||||
- * we're doing this outside the semaphore lock, it might return
|
||||
- * false negatives, but we don't care. It'll help in 99.99% of cases
|
||||
- * to avoid the semaphore lock. False positives simply cannot happen
|
||||
- * because the file in on the way to be removed and nobody ( but
|
||||
- * eventpoll ) has still a reference to this file.
|
||||
+ * Fast check to skip the slow path in the common case where the
|
||||
+ * file was never attached to an epoll. Safe without file->f_lock
|
||||
+ * because every f_ep writer excludes a concurrent __fput() on
|
||||
+ * @file:
|
||||
+ * - ep_insert() requires the file alive (refcount > 0);
|
||||
+ * - ep_remove() holds @file pinned via epi_fget() across the
|
||||
+ * write;
|
||||
+ * - eventpoll_release_file() runs from __fput() itself.
|
||||
+ * We are in __fput() here, so none of those can race us: a NULL
|
||||
+ * observation truly means no epoll path has work left on @file.
|
||||
*/
|
||||
if (likely(!READ_ONCE(file->f_ep)))
|
||||
return;
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
From 38a78d49b434ce9f29afdfaa870142ecb121800f Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 16:03:04 +0800
|
||||
Subject: [PATCH] eventpoll: drop dead bool return from ep_remove_epi()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 3a4551ea9c042502019b1d8a986e962cb9015366
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:12 2026 +0200
|
||||
|
||||
eventpoll: drop dead bool return from ep_remove_epi()
|
||||
|
||||
ep_remove_epi() always returns true -- the "can be disposed"
|
||||
answer was meaningful back when the dying-check lived inside the
|
||||
pre-split __ep_remove(), but after that check moved to ep_remove()
|
||||
the return value is just noise. Both callers gate on it
|
||||
unconditionally:
|
||||
|
||||
if (ep_remove_epi(ep, epi))
|
||||
WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
|
||||
|
||||
dispose = ep_remove_epi(ep, epi);
|
||||
...
|
||||
if (dispose && ep_refcount_dec_and_test(ep))
|
||||
ep_free(ep);
|
||||
|
||||
Make ep_remove_epi() return void, drop the dispose local in
|
||||
eventpoll_release_file(), and the useless conditionals at both
|
||||
callers. No functional change.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-9-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 9798ab5f7663..761bd85f213e 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -881,7 +881,7 @@ static void ep_remove_file(struct eventpoll *ep, struct epitem *epi,
|
||||
free_ephead(to_free);
|
||||
}
|
||||
|
||||
-static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
+static void ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
{
|
||||
lockdep_assert_held(&ep->mtx);
|
||||
|
||||
@@ -903,7 +903,6 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)
|
||||
kfree_rcu(epi, rcu);
|
||||
|
||||
percpu_counter_dec(&ep->user->epoll_watches);
|
||||
- return true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -931,9 +930,8 @@ static void ep_remove(struct eventpoll *ep, struct epitem *epi)
|
||||
return;
|
||||
|
||||
ep_remove_file(ep, epi, file);
|
||||
-
|
||||
- if (ep_remove_epi(ep, epi))
|
||||
- WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
|
||||
+ ep_remove_epi(ep, epi);
|
||||
+ WARN_ON_ONCE(ep_refcount_dec_and_test(ep));
|
||||
}
|
||||
|
||||
static void ep_clear_and_put(struct eventpoll *ep)
|
||||
@@ -1125,7 +1123,6 @@ void eventpoll_release_file(struct file *file)
|
||||
{
|
||||
struct eventpoll *ep;
|
||||
struct epitem *epi;
|
||||
- bool dispose;
|
||||
|
||||
/*
|
||||
* Use the 'dying' flag to prevent a concurrent ep_clear_and_put() from
|
||||
@@ -1149,11 +1146,11 @@ void eventpoll_release_file(struct file *file)
|
||||
ep_unregister_pollwait(ep, epi);
|
||||
|
||||
ep_remove_file(ep, epi, file);
|
||||
- dispose = ep_remove_epi(ep, epi);
|
||||
+ ep_remove_epi(ep, epi);
|
||||
|
||||
mutex_unlock(&ep->mtx);
|
||||
|
||||
- if (dispose && ep_refcount_dec_and_test(ep))
|
||||
+ if (ep_refcount_dec_and_test(ep))
|
||||
ep_free(ep);
|
||||
goto again;
|
||||
}
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
176
1441-eventpoll-fix-semi-unbounded-recursion.patch
Normal file
176
1441-eventpoll-fix-semi-unbounded-recursion.patch
Normal file
@ -0,0 +1,176 @@
|
||||
From 6ee3e28a7271944ba136a37d07ca35f0f7e3903b Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 16:03:26 +0800
|
||||
Subject: [PATCH] eventpoll: Fix semi-unbounded recursion
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
CVE: CVE-2025-38614
|
||||
|
||||
commit f2e467a48287c868818085aa35389a224d226732
|
||||
Author: Jann Horn <jannh@google.com>
|
||||
Date: Fri Jul 11 18:33:36 2025 +0200
|
||||
|
||||
eventpoll: Fix semi-unbounded recursion
|
||||
|
||||
Ensure that epoll instances can never form a graph deeper than
|
||||
EP_MAX_NESTS+1 links.
|
||||
|
||||
Currently, ep_loop_check_proc() ensures that the graph is loop-free and
|
||||
does some recursion depth checks, but those recursion depth checks don't
|
||||
limit the depth of the resulting tree for two reasons:
|
||||
|
||||
- They don't look upwards in the tree.
|
||||
- If there are multiple downwards paths of different lengths, only one of
|
||||
the paths is actually considered for the depth check since commit
|
||||
28d82dc1c4ed ("epoll: limit paths").
|
||||
|
||||
Essentially, the current recursion depth check in ep_loop_check_proc() just
|
||||
serves to prevent it from recursing too deeply while checking for loops.
|
||||
|
||||
A more thorough check is done in reverse_path_check() after the new graph
|
||||
edge has already been created; this checks, among other things, that no
|
||||
paths going upwards from any non-epoll file with a length of more than 5
|
||||
edges exist. However, this check does not apply to non-epoll files.
|
||||
|
||||
As a result, it is possible to recurse to a depth of at least roughly 500,
|
||||
tested on v6.15. (I am unsure if deeper recursion is possible; and this may
|
||||
have changed with commit 8c44dac8add7 ("eventpoll: Fix priority inversion
|
||||
problem").)
|
||||
|
||||
To fix it:
|
||||
|
||||
1. In ep_loop_check_proc(), note the subtree depth of each visited node,
|
||||
and use subtree depths for the total depth calculation even when a subtree
|
||||
has already been visited.
|
||||
2. Add ep_get_upwards_depth_proc() for similarly determining the maximum
|
||||
depth of an upwards walk.
|
||||
3. In ep_loop_check(), use these values to limit the total path length
|
||||
between epoll nodes to EP_MAX_NESTS edges.
|
||||
|
||||
Fixes: 22bacca48a17 ("epoll: prevent creating circular epoll structures")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jann Horn <jannh@google.com>
|
||||
Link: https://lore.kernel.org/20250711-epoll-recursion-fix-v1-1-fb2457c33292@google.com
|
||||
Signed-off-by: Christian Brauner <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 761bd85f213e..88b501a5e709 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -218,6 +218,7 @@ struct eventpoll {
|
||||
/* used to optimize loop detection check */
|
||||
u64 gen;
|
||||
struct hlist_head refs;
|
||||
+ u8 loop_check_depth;
|
||||
|
||||
/*
|
||||
* usage count, used together with epitem->dying to
|
||||
@@ -2135,23 +2136,24 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
|
||||
}
|
||||
|
||||
/**
|
||||
- * ep_loop_check_proc - verify that adding an epoll file inside another
|
||||
- * epoll structure does not violate the constraints, in
|
||||
- * terms of closed loops, or too deep chains (which can
|
||||
- * result in excessive stack usage).
|
||||
+ * ep_loop_check_proc - verify that adding an epoll file @ep inside another
|
||||
+ * epoll file does not create closed loops, and
|
||||
+ * determine the depth of the subtree starting at @ep
|
||||
*
|
||||
* @ep: the &struct eventpoll to be currently checked.
|
||||
* @depth: Current depth of the path being checked.
|
||||
*
|
||||
- * Return: %zero if adding the epoll @file inside current epoll
|
||||
- * structure @ep does not violate the constraints, or %-1 otherwise.
|
||||
+ * Return: depth of the subtree, or INT_MAX if we found a loop or went too deep.
|
||||
*/
|
||||
static int ep_loop_check_proc(struct eventpoll *ep, int depth)
|
||||
{
|
||||
- int error = 0;
|
||||
+ int result = 0;
|
||||
struct rb_node *rbp;
|
||||
struct epitem *epi;
|
||||
|
||||
+ if (ep->gen == loop_check_gen)
|
||||
+ return ep->loop_check_depth;
|
||||
+
|
||||
mutex_lock_nested(&ep->mtx, depth + 1);
|
||||
ep->gen = loop_check_gen;
|
||||
for (rbp = rb_first_cached(&ep->rbr); rbp; rbp = rb_next(rbp)) {
|
||||
@@ -2159,13 +2161,11 @@ static int ep_loop_check_proc(struct eventpoll *ep, int depth)
|
||||
if (unlikely(is_file_epoll(epi->ffd.file))) {
|
||||
struct eventpoll *ep_tovisit;
|
||||
ep_tovisit = epi->ffd.file->private_data;
|
||||
- if (ep_tovisit->gen == loop_check_gen)
|
||||
- continue;
|
||||
if (ep_tovisit == inserting_into || depth > EP_MAX_NESTS)
|
||||
- error = -1;
|
||||
+ result = INT_MAX;
|
||||
else
|
||||
- error = ep_loop_check_proc(ep_tovisit, depth + 1);
|
||||
- if (error != 0)
|
||||
+ result = max(result, ep_loop_check_proc(ep_tovisit, depth + 1) + 1);
|
||||
+ if (result > EP_MAX_NESTS)
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
@@ -2179,9 +2179,27 @@ static int ep_loop_check_proc(struct eventpoll *ep, int depth)
|
||||
list_file(epi->ffd.file);
|
||||
}
|
||||
}
|
||||
+ ep->loop_check_depth = result;
|
||||
mutex_unlock(&ep->mtx);
|
||||
|
||||
- return error;
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ep_get_upwards_depth_proc - determine depth of @ep when traversed upwards
|
||||
+ */
|
||||
+static int ep_get_upwards_depth_proc(struct eventpoll *ep, int depth)
|
||||
+{
|
||||
+ int result = 0;
|
||||
+ struct epitem *epi;
|
||||
+
|
||||
+ if (ep->gen == loop_check_gen)
|
||||
+ return ep->loop_check_depth;
|
||||
+ hlist_for_each_entry_rcu(epi, &ep->refs, fllink)
|
||||
+ result = max(result, ep_get_upwards_depth_proc(epi->ep, depth + 1) + 1);
|
||||
+ ep->gen = loop_check_gen;
|
||||
+ ep->loop_check_depth = result;
|
||||
+ return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2197,8 +2215,22 @@ static int ep_loop_check_proc(struct eventpoll *ep, int depth)
|
||||
*/
|
||||
static int ep_loop_check(struct eventpoll *ep, struct eventpoll *to)
|
||||
{
|
||||
+ int depth, upwards_depth;
|
||||
+
|
||||
inserting_into = ep;
|
||||
- return ep_loop_check_proc(to, 0);
|
||||
+ /*
|
||||
+ * Check how deep down we can get from @to, and whether it is possible
|
||||
+ * to loop up to @ep.
|
||||
+ */
|
||||
+ depth = ep_loop_check_proc(to, 0);
|
||||
+ if (depth > EP_MAX_NESTS)
|
||||
+ return -1;
|
||||
+ /* Check how far up we can go from @ep. */
|
||||
+ rcu_read_lock();
|
||||
+ upwards_depth = ep_get_upwards_depth_proc(ep, 0);
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ return (depth+1+upwards_depth > EP_MAX_NESTS) ? -1 : 0;
|
||||
}
|
||||
|
||||
static void clear_tfile_check_list(void)
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
110
1442-eventpoll-drop-vestigial-epi-dying-flag.patch
Normal file
110
1442-eventpoll-drop-vestigial-epi-dying-flag.patch
Normal file
@ -0,0 +1,110 @@
|
||||
From 3724dc6414c5da5c393e58e0e5863fdb95166922 Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Tue, 16 Jun 2026 16:03:26 +0800
|
||||
Subject: [PATCH] eventpoll: drop vestigial epi->dying flag
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit 07422c948f4bdf15567a129a0983f7c12e57ba8e
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Thu Apr 23 11:56:13 2026 +0200
|
||||
|
||||
eventpoll: drop vestigial epi->dying flag
|
||||
|
||||
With ep_remove() now pinning @file via epi_fget() across the
|
||||
f_ep clear and hlist_del_rcu(), the dying flag no longer
|
||||
orchestrates anything: it was set in eventpoll_release_file()
|
||||
(which only runs from __fput(), i.e. after @file's refcount has
|
||||
reached zero) and read in __ep_remove() / ep_remove() as a cheap
|
||||
bail before attempting the same synchronization epi_fget() now
|
||||
provides unconditionally.
|
||||
|
||||
The implication is simple: epi->dying == true always coincides
|
||||
with file_ref_get(&file->f_ref) == false, because __fput() is
|
||||
reachable only once the refcount hits zero and the refcount is
|
||||
monotone in that state. The READ_ONCE(epi->dying) in ep_remove()
|
||||
therefore selects exactly the same callers that epi_fget() would
|
||||
reject, just one atomic cheaper. That's not worth a struct
|
||||
field, a second coordination mechanism, and the comments on
|
||||
both.
|
||||
|
||||
Refresh the eventpoll_release_file() comment to describe what
|
||||
actually makes the path race-free now (the pin in ep_remove()).
|
||||
No functional change: the correctness argument is unchanged,
|
||||
only the mechanism is now a single one instead of two.
|
||||
|
||||
Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-10-2470f9eec0f5@kernel.org
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 88b501a5e709..5228ff9c8742 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -148,13 +148,6 @@ struct epitem {
|
||||
/* The file descriptor information this item refers to */
|
||||
struct epoll_filefd ffd;
|
||||
|
||||
- /*
|
||||
- * Protected by file->f_lock, true for to-be-released epitem already
|
||||
- * removed from the "struct file" items list; together with
|
||||
- * eventpoll->refcount orchestrates "struct eventpoll" disposal
|
||||
- */
|
||||
- bool dying;
|
||||
-
|
||||
/* List containing poll wait queues */
|
||||
struct eppoll_entry *pwqlist;
|
||||
|
||||
@@ -220,10 +213,7 @@ struct eventpoll {
|
||||
struct hlist_head refs;
|
||||
u8 loop_check_depth;
|
||||
|
||||
- /*
|
||||
- * usage count, used together with epitem->dying to
|
||||
- * orchestrate the disposal of this struct
|
||||
- */
|
||||
+ /* usage count, orchestrates "struct eventpoll" disposal */
|
||||
refcount_t refcount;
|
||||
|
||||
/* used to defer freeing past ep_get_upwards_depth_proc() RCU walk */
|
||||
@@ -918,13 +908,10 @@ static void ep_remove(struct eventpoll *ep, struct epitem *epi)
|
||||
|
||||
ep_unregister_pollwait(ep, epi);
|
||||
|
||||
- /* cheap sync with eventpoll_release_file() */
|
||||
- if (unlikely(READ_ONCE(epi->dying)))
|
||||
- return;
|
||||
-
|
||||
/*
|
||||
* If we manage to grab a reference it means we're not in
|
||||
- * eventpoll_release_file() and aren't going to be.
|
||||
+ * eventpoll_release_file() and aren't going to be: once @file's
|
||||
+ * refcount has reached zero, file_ref_get() cannot bring it back.
|
||||
*/
|
||||
file = epi_fget(epi);
|
||||
if (!file)
|
||||
@@ -1126,15 +1113,15 @@ void eventpoll_release_file(struct file *file)
|
||||
struct epitem *epi;
|
||||
|
||||
/*
|
||||
- * Use the 'dying' flag to prevent a concurrent ep_clear_and_put() from
|
||||
- * touching the epitems list before eventpoll_release_file() can access
|
||||
- * the ep->mtx.
|
||||
+ * A concurrent ep_remove() cannot outrace us: it pins @file via
|
||||
+ * epi_fget(), which fails once __fput() has dropped the refcount
|
||||
+ * to zero -- the path we're on. So any racing ep_remove() bails
|
||||
+ * and leaves the epi for us to clean up here.
|
||||
*/
|
||||
again:
|
||||
spin_lock(&file->f_lock);
|
||||
if (file->f_ep && file->f_ep->first) {
|
||||
epi = hlist_entry(file->f_ep->first, struct epitem, fllink);
|
||||
- WRITE_ONCE(epi->dying, true);
|
||||
spin_unlock(&file->f_lock);
|
||||
|
||||
/*
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
From 2eb0a1e08ebad5be00433093449abf025450ca6d Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Wed, 17 Jun 2026 12:08:43 +0800
|
||||
Subject: [PATCH] eventpoll: Fix integer overflow in ep_loop_check_proc()
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linus
|
||||
|
||||
commit fdcfce93073d990ed4b71752e31ad1c1d6e9d58b
|
||||
Author: Jann Horn <jannh@google.com>
|
||||
Date: Mon Feb 23 20:59:33 2026 +0100
|
||||
|
||||
eventpoll: Fix integer overflow in ep_loop_check_proc()
|
||||
|
||||
If a recursive call to ep_loop_check_proc() hits the `result = INT_MAX`,
|
||||
an integer overflow will occur in the calling ep_loop_check_proc() at
|
||||
`result = max(result, ep_loop_check_proc(ep_tovisit, depth + 1) + 1)`,
|
||||
breaking the recursion depth check.
|
||||
|
||||
Fix it by using a different placeholder value that can't lead to an
|
||||
overflow.
|
||||
|
||||
Reported-by: Guenter Roeck <linux@roeck-us.net>
|
||||
Fixes: f2e467a48287 ("eventpoll: Fix semi-unbounded recursion")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Jann Horn <jannh@google.com>
|
||||
Link: https://patch.msgid.link/20260223-epoll-int-overflow-v1-1-452f35132224@google.com
|
||||
Signed-off-by: Christian Brauner <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index 5228ff9c8742..cb21dfe9ee0a 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -2130,7 +2130,8 @@ static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
|
||||
* @ep: the &struct eventpoll to be currently checked.
|
||||
* @depth: Current depth of the path being checked.
|
||||
*
|
||||
- * Return: depth of the subtree, or INT_MAX if we found a loop or went too deep.
|
||||
+ * Return: depth of the subtree, or a value bigger than EP_MAX_NESTS if we found
|
||||
+ * a loop or went too deep.
|
||||
*/
|
||||
static int ep_loop_check_proc(struct eventpoll *ep, int depth)
|
||||
{
|
||||
@@ -2149,7 +2150,7 @@ static int ep_loop_check_proc(struct eventpoll *ep, int depth)
|
||||
struct eventpoll *ep_tovisit;
|
||||
ep_tovisit = epi->ffd.file->private_data;
|
||||
if (ep_tovisit == inserting_into || depth > EP_MAX_NESTS)
|
||||
- result = INT_MAX;
|
||||
+ result = EP_MAX_NESTS+1;
|
||||
else
|
||||
result = max(result, ep_loop_check_proc(ep_tovisit, depth + 1) + 1);
|
||||
if (result > EP_MAX_NESTS)
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
101
1444-eventpoll-refresh-epi-fget-ep-remove-file-comments.patch
Normal file
101
1444-eventpoll-refresh-epi-fget-ep-remove-file-comments.patch
Normal file
@ -0,0 +1,101 @@
|
||||
From 39c9ab147e5bc9cf20d146d78c59afc7a0ab488d Mon Sep 17 00:00:00 2001
|
||||
From: Ian Kent <ikent@redhat.com>
|
||||
Date: Thu, 18 Jun 2026 11:30:35 +0800
|
||||
Subject: [PATCH] eventpoll: refresh epi_fget() / ep_remove_file() comments
|
||||
|
||||
JIRA: https://redhat.atlassian.net/browse/RHEL-180777
|
||||
Upstream status: Linux
|
||||
|
||||
commit a573cb40f9819c3fe81a43eb10170f8fc8eddc5e
|
||||
Author: Christian Brauner <brauner@kernel.org>
|
||||
Date: Fri Apr 24 15:46:35 2026 +0200
|
||||
|
||||
eventpoll: refresh epi_fget() / ep_remove_file() comments
|
||||
|
||||
Two comments drifted from the code they sit on.
|
||||
|
||||
epi_fget()'s block comment still referenced atomic_long_inc_not_zero,
|
||||
which has been file_ref_get() for a while, and described only one of
|
||||
the function's two roles: safe dereference of epi->ffd.file under
|
||||
ep->mtx. Since commit a6dc643c6931 ("eventpoll: fix ep_remove struct
|
||||
eventpoll / struct file UAF") the refcount bump also serves as a pin
|
||||
that blocks __fput() from starting, which is what lets ep_remove()
|
||||
touch file->f_lock and file->f_ep without racing
|
||||
eventpoll_release_file(). Update the block to name both roles and the
|
||||
commit that introduced the pin role.
|
||||
|
||||
ep_remove_file()'s one-line "See eventpoll_release() for details"
|
||||
pointed at an inline in include/linux/eventpoll.h but said nothing
|
||||
about what those details were. Replace it with a short explanation:
|
||||
we publish NULL so the eventpoll_release() fastpath can skip the slow
|
||||
path, and this is safe because every f_ep writer either holds a pin
|
||||
via epi_fget() or is __fput() itself.
|
||||
|
||||
Comment-only; no functional change.
|
||||
|
||||
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
|
||||
Link: https://patch.msgid.link/20260424-work-epoll-rework-v1-4-249ed00a20f3@kernel.org
|
||||
Signed-off-by: Christian Brauner <brauner@kernel.org>
|
||||
|
||||
Signed-off-by: Ian Kent <ikent@redhat.com>
|
||||
|
||||
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
|
||||
index cb21dfe9ee0a..9bde520ac74b 100644
|
||||
--- a/fs/eventpoll.c
|
||||
+++ b/fs/eventpoll.c
|
||||
@@ -817,22 +817,23 @@ static void ep_free(struct eventpoll *ep)
|
||||
}
|
||||
|
||||
/*
|
||||
- * The ffd.file pointer may be in the process of being torn down due to
|
||||
- * being closed, but we may not have finished eventpoll_release() yet.
|
||||
+ * Pin @epi->ffd.file for operations that require both safe dereference
|
||||
+ * and exclusion from __fput().
|
||||
*
|
||||
- * Normally, even with the atomic_long_inc_not_zero, the file may have
|
||||
- * been free'd and then gotten re-allocated to something else (since
|
||||
- * files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
|
||||
+ * struct file uses SLAB_TYPESAFE_BY_RCU, so a freed slot can be
|
||||
+ * reassigned at any time. The bare load of epi->ffd.file is safe here
|
||||
+ * because the caller holds ep->mtx and eventpoll_release_file() blocks
|
||||
+ * on that mutex while tearing down the epi, so the backing file
|
||||
+ * allocation cannot be freed and reused under us. An rcu_read_lock()
|
||||
+ * is therefore unnecessary for the load.
|
||||
*
|
||||
- * But for epoll, users hold the ep->mtx mutex, and as such any file in
|
||||
- * the process of being free'd will block in eventpoll_release_file()
|
||||
- * and thus the underlying file allocation will not be free'd, and the
|
||||
- * file re-use cannot happen.
|
||||
- *
|
||||
- * For the same reason we can avoid a rcu_read_lock() around the
|
||||
- * operation - 'ffd.file' cannot go away even if the refcount has
|
||||
- * reached zero (but we must still not call out to ->poll() functions
|
||||
- * etc).
|
||||
+ * A successful file_ref_get() additionally blocks __fput() from
|
||||
+ * starting on this file: once the refcount has reached zero it cannot
|
||||
+ * come back. ep_remove() relies on that to touch file->f_lock and
|
||||
+ * file->f_ep without racing eventpoll_release_file() (see commit
|
||||
+ * a6dc643c6931). A NULL return means __fput() is already in flight;
|
||||
+ * the caller must bail without touching the file, and
|
||||
+ * eventpoll_release_file() will clean the epi up from its side.
|
||||
*/
|
||||
static struct file *epi_fget(const struct epitem *epi)
|
||||
{
|
||||
@@ -858,7 +859,13 @@ static void ep_remove_file(struct eventpoll *ep, struct epitem *epi,
|
||||
spin_lock(&file->f_lock);
|
||||
head = file->f_ep;
|
||||
if (hlist_is_singular_node(&epi->fllink, head)) {
|
||||
- /* See eventpoll_release() for details. */
|
||||
+ /*
|
||||
+ * Last watcher: publish NULL so the eventpoll_release()
|
||||
+ * fastpath in include/linux/eventpoll.h can skip the slow
|
||||
+ * path on a future __fput(). Safe because every f_ep writer
|
||||
+ * either holds a pin on @file via epi_fget() or is __fput()
|
||||
+ * itself -- see the comment in eventpoll_release().
|
||||
+ */
|
||||
WRITE_ONCE(file->f_ep, NULL);
|
||||
if (!is_file_epoll(file)) {
|
||||
struct epitems_head *v;
|
||||
--
|
||||
2.50.1 (Apple Git-155)
|
||||
|
||||
91
kernel.spec
91
kernel.spec
@ -176,13 +176,13 @@ Summary: The Linux kernel
|
||||
%define specrpmversion 6.12.0
|
||||
%define specversion 6.12.0
|
||||
%define patchversion 6.12
|
||||
%define pkgrelease 211.30.4
|
||||
%define pkgrelease 211.31.1
|
||||
%define kversion 6
|
||||
%define tarfile_release 6.12.0-211.7.1.el10_2
|
||||
# This is needed to do merge window version magic
|
||||
%define patchlevel 12
|
||||
# This allows pkg_release to have configurable %%{?dist} tag
|
||||
%define specrelease 211.30.4%{?buildid}%{?dist}
|
||||
%define specrelease 211.31.1%{?buildid}%{?dist}
|
||||
# This defines the kabi tarball version
|
||||
%define kabiversion 6.12.0-211.7.1.el10_2
|
||||
|
||||
@ -1451,9 +1451,30 @@ Patch1413: 1413-arm64-errata-mitigate-tlbi-errata-on-microsoft-azure-cobalt.patc
|
||||
Patch1414: 1414-fs-smb-client-fix-out-of-bounds-read-in-cifs-sanitize-prepa.patch
|
||||
Patch1415: 1415-kvm-x86-fix-shadow-paging-use-after-free-due-to-unexpected-gfn.patch
|
||||
Patch1416: 1416-kvm-x86-fix-shadow-paging-use-after-free-due-to-unexpected-role.patch
|
||||
Patch1417: 1417-eventpoll-fix-ep-remove-struct-eventpoll-struct-file-uaf.patch
|
||||
Patch1418: 1418-rtmutex-use-waiter-task-in-remove-waiter.patch
|
||||
Patch1420: 1420-rtmutex-skip-remove-waiter-when-not-enqueued.patch
|
||||
Patch1421: 1421-net-page-pool-avoid-false-positive-warning-if-napi-was-never.patch
|
||||
Patch1422: 1422-net-mana-fix-double-destroy-workqueue-on-service-rescan-pci.patch
|
||||
Patch1423: 1423-net-mana-null-service-wq-on-setup-error-to-prevent-double-de.patch
|
||||
Patch1424: 1424-net-ipv6-ioam6-prevent-schema-length-wraparound-in-trace-fil.patch
|
||||
Patch1425: 1425-procfs-fix-missing-rcu-protection-when-reading-real-parent-i.patch
|
||||
Patch1426: 1426-tg3-fix-race-for-querying-speed-duplex.patch
|
||||
Patch1427: 1427-smb-client-fix-off-by-8-bounds-check-in-check-wsl-eas.patch
|
||||
Patch1428: 1428-smb-client-fix-out-of-bounds-read-in-smb2-compound-op.patch
|
||||
Patch1429: 1429-epoll-annotate-racy-check.patch
|
||||
Patch1430: 1430-eventpoll-defer-struct-eventpoll-free-to-rcu-grace-period.patch
|
||||
Patch1431: 1431-eventpoll-use-hlist-is-singular-node-in-ep-remove.patch
|
||||
Patch1432: 1432-eventpoll-split-ep-remove.patch
|
||||
Patch1433: 1433-eventpoll-kill-ep-remove.patch
|
||||
Patch1434: 1434-eventpoll-rename-ep-remove-safe-back-to-ep-remove.patch
|
||||
Patch1435: 1435-eventpoll-move-epi-fget-up.patch
|
||||
Patch1436: 1436-eventpoll-drop-vestigial-prefix-from-ep-remove-file-epi.patch
|
||||
Patch1437: 1437-eventpoll-fix-ep-remove-struct-eventpoll-struct-file-uaf.patch
|
||||
Patch1438: 1438-eventpoll-move-f-lock-acquisition-into-ep-remove-file.patch
|
||||
Patch1439: 1439-eventpoll-refresh-eventpoll-release-fast-path-comment.patch
|
||||
Patch1440: 1440-eventpoll-drop-dead-bool-return-from-ep-remove-epi.patch
|
||||
Patch1441: 1441-eventpoll-fix-semi-unbounded-recursion.patch
|
||||
Patch1442: 1442-eventpoll-drop-vestigial-epi-dying-flag.patch
|
||||
Patch1443: 1443-eventpoll-fix-integer-overflow-in-ep-loop-check-proc.patch
|
||||
Patch1444: 1444-eventpoll-refresh-epi-fget-ep-remove-file-comments.patch
|
||||
# END OF PATCH DEFINITIONS
|
||||
|
||||
%description
|
||||
@ -2627,9 +2648,30 @@ ApplyPatch 1413-arm64-errata-mitigate-tlbi-errata-on-microsoft-azure-cobalt.patc
|
||||
ApplyPatch 1414-fs-smb-client-fix-out-of-bounds-read-in-cifs-sanitize-prepa.patch
|
||||
ApplyPatch 1415-kvm-x86-fix-shadow-paging-use-after-free-due-to-unexpected-gfn.patch
|
||||
ApplyPatch 1416-kvm-x86-fix-shadow-paging-use-after-free-due-to-unexpected-role.patch
|
||||
ApplyPatch 1417-eventpoll-fix-ep-remove-struct-eventpoll-struct-file-uaf.patch
|
||||
ApplyPatch 1418-rtmutex-use-waiter-task-in-remove-waiter.patch
|
||||
ApplyPatch 1420-rtmutex-skip-remove-waiter-when-not-enqueued.patch
|
||||
ApplyPatch 1421-net-page-pool-avoid-false-positive-warning-if-napi-was-never.patch
|
||||
ApplyPatch 1422-net-mana-fix-double-destroy-workqueue-on-service-rescan-pci.patch
|
||||
ApplyPatch 1423-net-mana-null-service-wq-on-setup-error-to-prevent-double-de.patch
|
||||
ApplyPatch 1424-net-ipv6-ioam6-prevent-schema-length-wraparound-in-trace-fil.patch
|
||||
ApplyPatch 1425-procfs-fix-missing-rcu-protection-when-reading-real-parent-i.patch
|
||||
ApplyPatch 1426-tg3-fix-race-for-querying-speed-duplex.patch
|
||||
ApplyPatch 1427-smb-client-fix-off-by-8-bounds-check-in-check-wsl-eas.patch
|
||||
ApplyPatch 1428-smb-client-fix-out-of-bounds-read-in-smb2-compound-op.patch
|
||||
ApplyPatch 1429-epoll-annotate-racy-check.patch
|
||||
ApplyPatch 1430-eventpoll-defer-struct-eventpoll-free-to-rcu-grace-period.patch
|
||||
ApplyPatch 1431-eventpoll-use-hlist-is-singular-node-in-ep-remove.patch
|
||||
ApplyPatch 1432-eventpoll-split-ep-remove.patch
|
||||
ApplyPatch 1433-eventpoll-kill-ep-remove.patch
|
||||
ApplyPatch 1434-eventpoll-rename-ep-remove-safe-back-to-ep-remove.patch
|
||||
ApplyPatch 1435-eventpoll-move-epi-fget-up.patch
|
||||
ApplyPatch 1436-eventpoll-drop-vestigial-prefix-from-ep-remove-file-epi.patch
|
||||
ApplyPatch 1437-eventpoll-fix-ep-remove-struct-eventpoll-struct-file-uaf.patch
|
||||
ApplyPatch 1438-eventpoll-move-f-lock-acquisition-into-ep-remove-file.patch
|
||||
ApplyPatch 1439-eventpoll-refresh-eventpoll-release-fast-path-comment.patch
|
||||
ApplyPatch 1440-eventpoll-drop-dead-bool-return-from-ep-remove-epi.patch
|
||||
ApplyPatch 1441-eventpoll-fix-semi-unbounded-recursion.patch
|
||||
ApplyPatch 1442-eventpoll-drop-vestigial-epi-dying-flag.patch
|
||||
ApplyPatch 1443-eventpoll-fix-integer-overflow-in-ep-loop-check-proc.patch
|
||||
ApplyPatch 1444-eventpoll-refresh-epi-fget-ep-remove-file-comments.patch
|
||||
# END OF PATCH APPLICATIONS
|
||||
|
||||
# Any further pre-build tree manipulations happen here.
|
||||
@ -5134,6 +5176,39 @@ fi\
|
||||
#
|
||||
#
|
||||
%changelog
|
||||
* Wed Jul 08 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 6.12.0-211.31.1
|
||||
- Recreate RHEL 6.12.0-211.31.1 from CentOS Stream 10 and upstream stable backports (1421-1444)
|
||||
- The AlmaLinux ahead-of-RHEL eventpoll CVE-2026-46242 fix (1417) is superseded by
|
||||
RHEL's eventpoll series carrying the same fix and is dropped
|
||||
- Temporarily drop the rtmutex remove_waiter() fixes (1418, 1420)
|
||||
- RHEL changelog for 211.31.1 follows:
|
||||
|
||||
* Mon Jul 06 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-211.31.1.el10_2]
|
||||
- eventpoll: refresh epi_fget() / ep_remove_file() comments (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: Fix integer overflow in ep_loop_check_proc() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: drop vestigial epi->dying flag (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: Fix semi-unbounded recursion (Ian Kent) [RHEL-180776] {CVE-2025-38614}
|
||||
- eventpoll: drop dead bool return from ep_remove_epi() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: refresh eventpoll_release() fast-path comment (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: move f_lock acquisition into ep_remove_file() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: fix ep_remove struct eventpoll / struct file UAF (Ian Kent) [RHEL-180776] {CVE-2026-46242}
|
||||
- eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: move epi_fget() up (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: rename ep_remove_safe() back to ep_remove() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: kill __ep_remove() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: split __ep_remove() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: use hlist_is_singular_node() in __ep_remove() (Ian Kent) [RHEL-180776]
|
||||
- eventpoll: defer struct eventpoll free to RCU grace period (Ian Kent) [RHEL-173832] {CVE-2026-43074}
|
||||
- epoll: annotate racy check (Ian Kent) [RHEL-180776]
|
||||
- smb/client: fix out-of-bounds read in smb2_compound_op() (Paulo Alcantara) [RHEL-180048] {CVE-2026-46155}
|
||||
- smb: client: fix off-by-8 bounds check in check_wsl_eas() (Paulo Alcantara) [RHEL-180048]
|
||||
- tg3: Fix race for querying speed/duplex (CKI Backport Bot) [RHEL-182770]
|
||||
- procfs: fix missing RCU protection when reading real_parent in do_task_stat() (CKI Backport Bot) [RHEL-181902] {CVE-2026-46259}
|
||||
- net/ipv6: ioam6: prevent schema length wraparound in trace fill (Antoine Tenart) [RHEL-174786] {CVE-2026-43341}
|
||||
- net/mana: Null service_wq on setup error to prevent double destroy (CKI Backport Bot) [RHEL-180277] {CVE-2026-43276}
|
||||
- net: mana: Fix double destroy_workqueue on service rescan PCI path (CKI Backport Bot) [RHEL-180277] {CVE-2026-43276}
|
||||
- net: page_pool: avoid false positive warning if NAPI was never added (Ivan Vecera) [RHEL-162140]
|
||||
|
||||
* Tue Jul 08 2026 Andrew Lukoshko <alukoshko@almalinux.org> - 6.12.0-211.30.4
|
||||
- Fix rtmutex self-deadlock NULL pointer dereference in remove_waiter() ahead of
|
||||
RHEL, upstream 3bfdc63936dd + 40a25d59e85b (1418, 1420); the futex_requeue guard
|
||||
|
||||
Loading…
Reference in New Issue
Block a user