Re-add AlmaLinux ahead-of-RHEL security fixes (CVE-2026-46113 KVM + rtmutex) on 553.141.1; bump to 553.141.2

This commit is contained in:
Andrew Lukoshko 2026-07-08 13:58:53 +00:00
parent 2fb771f048
commit 55597d84e3
5 changed files with 564 additions and 6 deletions

View File

@ -0,0 +1,253 @@
kpatch-cve: CVE-2026-46113
kpatch-cve-url: https://access.redhat.com/security/cve/CVE-2026-46113
kpatch-cvss: 8.8
kpatch-description: KVM: x86: Fix shadow paging use-after-free due to unexpected GFN/role
kpatch-kernel: 4.18.0-553.139.1.el8_10
kpatch-patch-url: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=0cb2af2ea66ad8ff195c156ea690f11216285bdf
From: KernelCare Security Team
Subject: [PATCH] KVM: x86: Fix shadow paging use-after-free due to unexpected GFN/role
CVE: CVE-2026-46113
Upstream Status: manually adapted, not a literal cherry-pick. This
combines the effect of two upstream fixes:
- commit 0cb2af2ea66a ("KVM: x86: Fix shadow paging use-after-free
due to unexpected GFN"), which is the fix CVE-2026-46113 refers to
- commit 81ccda30b4e8 ("KVM: x86: Fix shadow paging use-after-free
due to unexpected role"), a follow-up closing a second, related
hole in the same code path (found while hardening it after the
first fix)
Neither commit applies to this kernel: both are written against
upstream's post-refactor MMU (kvm_mmu_get_child_sp()/
kvm_mmu_get_shadow_page()/__link_shadow_page(), introduced by a large
prerequisite series -- e.g. "KVM: x86/mmu: Derive shadow MMU page role
from parent" and "KVM: x86/mmu: pull call to drop_large_spte() into
__link_shadow_page()" -- that this 4.18-based kernel does not carry).
This kernel still uses the older, pre-refactor shape: each of the
three "walk into an existing non-leaf SPTE or install a new one" call
sites (kvm_mmu_get_page()+link_shadow_page() in __direct_map() and in
both loops of FNAME(fetch)) independently does:
drop_large_spte(vcpu, it.sptep);
if (!is_shadow_present_pte(*it.sptep)) {
sp = kvm_mmu_get_page(...);
link_shadow_page(vcpu, it.sptep, sp);
}
i.e. if *it.sptep is already present (and not a large leaf,
already handled by drop_large_spte()), the walk just continues into
whatever child it already points to, without checking that the child
actually matches the gfn/role being walked to. This is exactly the
root cause both upstream commits describe: if the guest's page tables
are modified between VM entries (shadow paging) such that a PDE now
resolves to a different gfn, or to a translation requiring a
differently-shaped shadow page (e.g. a 2MB direct-mapped leaf split
into a 4KB indirect page table), the stale child is reused as-is.
When that stale child is later zapped, kvm_mmu_page_get_gfn() derives
the wrong gfn for its rmap entries (sp->gfn + index, or sp->gfn
itself, instead of the actual mapped gfn), so rmap_remove() cannot
find and remove them. If the memslot backing the old translation is
then dropped, the shadow page is freed while the stale rmap entry
survives; any later rmap walk over that gfn (dirty logging, MMU
notifier invalidation such as MADV_DONTNEED, ...) dereferences freed
memory.
Fix this at each of the three call sites by validating, before
falling through to "reuse the existing child", that the present
non-large SPTE actually points to a child with the expected gfn *and*
role (mirroring 81ccda30b4e8's role check on top of 0cb2af2ea66a's gfn
check). If it doesn't, the stale SPTE (and its subtree) is torn down
via mmu_page_zap_pte() + kvm_mmu_remote_flush_or_zap() -- the same
primitives upstream's __link_shadow_page() now uses -- before
installing the correct child. This preserves the existing fast path
(no hash-table lookup) for the common case where the already-linked
child is correct.
The role/gfn comparison itself is factored into two small helpers,
kvm_mmu_child_role() (the role computation already done at the top of
kvm_mmu_get_page(), extracted unchanged so both functions share it)
and shadow_page_role_matches().
Note on kernel commit a955cad84cda ("KVM: x86/mmu: Retry page fault if
root is invalidated by memslot update"): during upstream's stable
backport of 0cb2af2ea66a to 5.10.y/5.15.y, this turned out to be a
required prerequisite -- without it, testers hit WARN_ON regressions
in kvm_mmu_zap_all_fast()/kvm_mmu_zap_all() (see the "stable backports
for ..." thread on kvm@vger.kernel.org, message
20260630223723.83727-1-zcgao@amazon.com). This kernel already has the
equivalent logic (is_page_fault_stale()/is_obsolete_sp(), used in both
direct_page_fault() and FNAME(page_fault)), confirmed present before
writing this patch, so no separate prerequisite patch is needed here.
Reported-by: Hyunwoo Kim <imv4bel@gmail.com>
Reported-by: Alexander Bulekov <bkov@amazon.com>
Reported-by: Fred Griffoul <fgriffo@amazon.co.uk>
---
arch/x86/kvm/mmu/mmu.c | 72 ++++++++++++++++++++++++++++++++++-------
arch/x86/kvm/mmu/paging_tmpl.h | 40 ++++++++++++++++++++--
2 files changed, 96 insertions(+), 16 deletions(-)
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index c4854dc02..696c3b4c6 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -2002,21 +2002,13 @@ static void clear_sp_write_flooding_count(u64 *spte)
__clear_sp_write_flooding_count(sptep_to_sp(spte));
}
-static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
- gfn_t gfn,
- gva_t gaddr,
- unsigned level,
- int direct,
- unsigned int access)
+static union kvm_mmu_page_role kvm_mmu_child_role(struct kvm_vcpu *vcpu,
+ gva_t gaddr, unsigned level,
+ int direct,
+ unsigned int access)
{
- bool direct_mmu = vcpu->arch.mmu->direct_map;
union kvm_mmu_page_role role;
- struct hlist_head *sp_list;
unsigned quadrant;
- struct kvm_mmu_page *sp;
- int ret;
- int collisions = 0;
- LIST_HEAD(invalid_list);
role = vcpu->arch.mmu->mmu_role.base;
role.level = level;
@@ -2028,6 +2020,46 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
role.quadrant = quadrant;
}
+ return role;
+}
+
+/*
+ * Returns true if @sptep already links to a present, non-large shadow page
+ * that matches @gfn and @role, i.e. it is safe to keep walking through the
+ * existing child instead of replacing it. The gfn of a direct shadow page
+ * only tracks its *first* mapping, so an intervening guest PTE change can
+ * leave a present SPTE pointing at a child that was allocated for a
+ * different gfn and/or role; blindly reusing it leads to a stale rmap entry
+ * (and eventually a use-after-free) once the mismatched child is zapped.
+ */
+static bool shadow_page_role_matches(u64 *sptep, gfn_t gfn,
+ union kvm_mmu_page_role role)
+{
+ struct kvm_mmu_page *child;
+
+ if (!is_shadow_present_pte(*sptep) || is_large_pte(*sptep))
+ return false;
+
+ child = to_shadow_page(*sptep & PT64_BASE_ADDR_MASK);
+ return child->gfn == gfn && child->role.word == role.word;
+}
+
+static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
+ gfn_t gfn,
+ gva_t gaddr,
+ unsigned level,
+ int direct,
+ unsigned int access)
+{
+ bool direct_mmu = vcpu->arch.mmu->direct_map;
+ union kvm_mmu_page_role role = kvm_mmu_child_role(vcpu, gaddr, level,
+ direct, access);
+ struct hlist_head *sp_list;
+ struct kvm_mmu_page *sp;
+ int ret;
+ int collisions = 0;
+ LIST_HEAD(invalid_list);
+
sp_list = &vcpu->kvm->arch.mmu_page_hash[kvm_page_table_hashfn(gfn)];
for_each_valid_sp(vcpu->kvm, sp, sp_list) {
if (sp->gfn != gfn) {
@@ -2946,8 +2978,20 @@ static int __direct_map(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault)
break;
drop_large_spte(vcpu, it.sptep);
- if (is_shadow_present_pte(*it.sptep))
- continue;
+ if (is_shadow_present_pte(*it.sptep)) {
+ union kvm_mmu_page_role role;
+ LIST_HEAD(invalid_list);
+
+ role = kvm_mmu_child_role(vcpu, it.addr, it.level - 1,
+ true, ACC_ALL);
+ if (shadow_page_role_matches(it.sptep, base_gfn, role))
+ continue;
+
+ mmu_page_zap_pte(vcpu->kvm, sptep_to_sp(it.sptep),
+ it.sptep, &invalid_list);
+ kvm_mmu_remote_flush_or_zap(vcpu->kvm, &invalid_list,
+ true);
+ }
sp = kvm_mmu_get_page(vcpu, base_gfn, it.addr,
it.level - 1, true, ACC_ALL);
diff --git a/arch/x86/kvm/mmu/paging_tmpl.h b/arch/x86/kvm/mmu/paging_tmpl.h
index 3b825e60a..911dbe698 100644
--- a/arch/x86/kvm/mmu/paging_tmpl.h
+++ b/arch/x86/kvm/mmu/paging_tmpl.h
@@ -676,10 +676,28 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
clear_sp_write_flooding_count(it.sptep);
drop_large_spte(vcpu, it.sptep);
+ table_gfn = gw->table_gfn[it.level - 2];
+ access = gw->pt_access[it.level - 2];
+
+ if (is_shadow_present_pte(*it.sptep)) {
+ union kvm_mmu_page_role role;
+ LIST_HEAD(invalid_list);
+
+ role = kvm_mmu_child_role(vcpu, fault->addr,
+ it.level - 1, false, access);
+ if (!shadow_page_role_matches(it.sptep, table_gfn,
+ role)) {
+ mmu_page_zap_pte(vcpu->kvm,
+ sptep_to_sp(it.sptep),
+ it.sptep, &invalid_list);
+ kvm_mmu_remote_flush_or_zap(vcpu->kvm,
+ &invalid_list,
+ true);
+ }
+ }
+
sp = NULL;
if (!is_shadow_present_pte(*it.sptep)) {
- table_gfn = gw->table_gfn[it.level - 2];
- access = gw->pt_access[it.level - 2];
sp = kvm_mmu_get_page(vcpu, table_gfn, fault->addr,
it.level-1, false, access);
/*
@@ -736,6 +754,24 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault,
drop_large_spte(vcpu, it.sptep);
+ if (is_shadow_present_pte(*it.sptep)) {
+ union kvm_mmu_page_role role;
+ LIST_HEAD(invalid_list);
+
+ role = kvm_mmu_child_role(vcpu, fault->addr,
+ it.level - 1, true,
+ direct_access);
+ if (!shadow_page_role_matches(it.sptep, base_gfn,
+ role)) {
+ mmu_page_zap_pte(vcpu->kvm,
+ sptep_to_sp(it.sptep),
+ it.sptep, &invalid_list);
+ kvm_mmu_remote_flush_or_zap(vcpu->kvm,
+ &invalid_list,
+ true);
+ }
+ }
+
if (!is_shadow_present_pte(*it.sptep)) {
sp = kvm_mmu_get_page(vcpu, base_gfn, fault->addr,
it.level - 1, true, direct_access);
--
2.39.2

View File

@ -0,0 +1,134 @@
From: Paolo Bonzini <pbonzini@redhat.com>
Date: Fri, 26 Jun 2026 19:46:19 +0200
Subject: KVM: x86/mmu: Ensure hugepage is in by slot before checking max mapping level
From: Sean Christopherson <seanjc@google.com>
commit ef057cbf825e03b63f6edf5980f96abf3c53089d upstream.
When recovering hugepages in the shadow MMU, verify that the base gfn of
the shadow page is actually contained within the target memslot, *before*
querying the max mapping level given the shadow page's gfn. Failure to
pre-check the validity of the gfn can lead to an out-of-bounds access to
the slot's lpage_info (which typically manifests as a host #PF because the
lpage_info is vmalloc'd) if the guest creates a hugepage mapping (in its
PTEs) that extends "below" the bounds of a memslot.
When faulting in memory for a guest, and the size of the guest mapping is
greater than KVM's (current) max mapping, then KVM will create a "direct"
shadow page (direct in that there are no gPTEs to shadow, and so the target
gfn is a direct calculation given the base gfn of the shadow page). The
hugepage recovery flow looks for such direct shadow pages, as forcing 4KiB
mappings when dirty logging generates the guest > host mapping size case.
When the 4KiB restriction is lifted, then KVM can replace the shadow page
with a hugepage.
But if KVM originally used a smaller mapping than the guest because the
range of memory covered by the guest hugepage exceeds the bounds of a
memslot, then KVM will link a direct shadow page with a gfn that is outside
the bounds of the memslot being used to fault in memory. The rmap entry
added for the leaf mapping is correct and within bounds, but the gfn of the
leaf SPTE's parent shadow page will be out of bounds.
BUG: unable to handle page fault for address: ffffc90000806ffc
#PF: supervisor read access in kernel mode
#PF: error_code(0x0000) - not-present page
PGD 100000067 P4D 100000067 PUD 1002a7067 PMD 10612f067 PTE 0
Oops: Oops: 0000 [#1] SMP
CPU: 13 UID: 1000 PID: 757 Comm: mmu_stress_test Not tainted 7.1.0-rc1-48ce1e26eace-x86_pir_to_irr_comments-vm #341 PREEMPT
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
RIP: 0010:kvm_mmu_max_mapping_level+0x79/0x2b0 [kvm]
Call Trace:
<TASK>
kvm_mmu_recover_huge_pages+0x21b/0x320 [kvm]
kvm_set_memslot+0x1ee/0x590 [kvm]
kvm_set_memory_region.part.0+0x3a1/0x4d0 [kvm]
kvm_vm_ioctl+0x9bf/0x15d0 [kvm]
__x64_sys_ioctl+0x8a/0xd0
do_syscall_64+0xb7/0xbb0
entry_SYSCALL_64_after_hwframe+0x4b/0x53
RIP: 0033:0x7f21c0f1a9bf
</TASK>
Don't bother pre-checking the bounds of the potential hugepage, i.e. don't
check that e.g. sp->gfn + KVM_PAGES_PER_HPAGE(sp->role.level + 1) is also
within the memslot, as the checks performed by kvm_mmu_max_mapping_level()
are a superset of the basic bounds checks. I.e. pre-checking the full
range would be a dubious micro-optimization.
Fixes: 9eba50f8d7fc ("KVM: x86/mmu: Consult max mapping level when zapping collapsible SPTEs")
Cc: stable@vger.kernel.org
Cc: David Matlack <dmatlack@google.com>
Cc: James Houghton <jthoughton@google.com>
Cc: Alexander Bulekov <bkov@amazon.com>
Cc: Fred Griffoul <fgriffo@amazon.co.uk>
Cc: Alexander Graf <graf@amazon.de>
Cc: David Woodhouse <dwmw@amazon.co.uk>
Cc: Filippo Sironi <sironi@amazon.de>
Cc: Ivan Orlov <iorlov@amazon.co.uk>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
arch/x86/kvm/mmu/mmu.c | 19 +++++++++++++------
include/linux/kvm_host.h | 7 ++++++-
2 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 9597112..12d3e1f 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -6045,13 +6045,20 @@ restart:
pfn = spte_to_pfn(*sptep);
/*
- * We cannot do huge page mapping for indirect shadow pages,
- * which are found on the last rmap (level = 1) when not using
- * tdp; such shadow pages are synced with the page table in
- * the guest, and the guest page table is using 4K page size
- * mapping if the indirect sp has level = 1.
+ * Direct shadow page can be replaced by a hugepage if the host
+ * mapping level allows it and the memslot maps all of the host
+ * hugepage. Note! If the memslot maps only part of the
+ * hugepage, sp->gfn may be below slot->base_gfn, and querying
+ * the max mapping level would cause an out-of-bounds lpage_info
+ * access. So the gfn bounds check *must* be done first.
+ *
+ * Indirect shadow pages are created when the guest page tables
+ * are using 4K pages. Since the host mapping is always
+ * constrained by the page size in the guest, indirect shadow
+ * pages are never collapsible.
*/
- if (sp->role.direct && !kvm_is_reserved_pfn(pfn) &&
+ if (sp->role.direct && is_gfn_in_memslot(slot, sp->gfn) &&
+ !kvm_is_reserved_pfn(pfn) &&
sp->role.level < kvm_mmu_max_mapping_level(kvm, slot, sp->gfn,
pfn, PG_LEVEL_NUM)) {
pte_list_remove(kvm, rmap_head, sptep);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index eaebea6..c37570a 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1378,6 +1378,11 @@ static inline struct rcuwait *kvm_arch_vcpu_get_wait(struct kvm_vcpu *vcpu)
#endif
}
+static inline bool is_gfn_in_memslot(const struct kvm_memory_slot *slot, gfn_t gfn)
+{
+ return gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages;
+}
+
/*
* Wake a vCPU if necessary, but don't do any stats/metadata updates. Returns
* true if the vCPU was blocking and was awakened, false otherwise.
@@ -1464,7 +1469,7 @@ try_get_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
if (!slot)
return NULL;
- if (gfn >= slot->base_gfn && gfn < slot->base_gfn + slot->npages)
+ if (is_gfn_in_memslot(slot, gfn))
return slot;
else
return NULL;
--
2.43.0

View File

@ -0,0 +1,86 @@
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
[ AlmaLinux 8 (4.18.0-553): backport of upstream 3bfdc63936dd. This el8
tree already carries the modern rtmutex rework (struct rt_mutex_base).
The kernel is built with -std=gnu89, so the upstream scoped_guard(
raw_spinlock, ...) form does not compile (C99 for-init decl); the plain
raw_spin_lock()/raw_spin_unlock() pair on waiter_task->pi_lock is used
instead, achieving the same end state. ]
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index 95db3bb..cb855e3 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -1501,20 +1501,23 @@ static bool rtmutex_spin_on_owner(struct rt_mutex_base *lock,
*
* Must be called with lock->wait_lock held and interrupts disabled. It must
* have just failed to try_to_take_rt_mutex().
+ *
+ * When invoked from rt_mutex_start_proxy_lock() waiter::task != current !
*/
static void __sched remove_waiter(struct rt_mutex_base *lock,
struct rt_mutex_waiter *waiter)
{
bool is_top_waiter = (waiter == rt_mutex_top_waiter(lock));
struct task_struct *owner = rt_mutex_owner(lock);
+ struct task_struct *waiter_task = waiter->task;
struct rt_mutex_base *next_lock;
lockdep_assert_held(&lock->wait_lock);
- raw_spin_lock(&current->pi_lock);
+ raw_spin_lock(&waiter_task->pi_lock);
rt_mutex_dequeue(lock, waiter);
- current->pi_blocked_on = NULL;
- raw_spin_unlock(&current->pi_lock);
+ waiter_task->pi_blocked_on = NULL;
+ raw_spin_unlock(&waiter_task->pi_lock);
/*
* Only update priority if the waiter was the highest priority
@@ -1550,7 +1553,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

View File

@ -0,0 +1,71 @@
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
[ AlmaLinux 8 (4.18.0-553): backport of upstream 40a25d59e85b. rt_mutex_
start_proxy_lock() lives in kernel/locking/rtmutex_api.c on el8 (same as
upstream); the ret<0 fix applies there. This tree already carries
1a1fb985f2e2 - __rt_mutex_start_proxy_lock() returns 1 on
try_to_take_rt_mutex() success, so the old 'if (unlikely(ret))' wrongly
called remove_waiter() on success; the ret<0 tightening is required. The
local __rt_mutex_start_proxy_lock() call takes 3 args (no &wake_q). ]
diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
index cb855e3..469d43d 100644
--- a/kernel/locking/rtmutex.c
+++ b/kernel/locking/rtmutex.c
@@ -1514,6 +1514,9 @@ static void __sched remove_waiter(struct rt_mutex_base *lock,
lockdep_assert_held(&lock->wait_lock);
+ if (!waiter_task) /* never enqueued */
+ return;
+
raw_spin_lock(&waiter_task->pi_lock);
rt_mutex_dequeue(lock, waiter);
waiter_task->pi_blocked_on = NULL;
diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
index 56d1938..c4e1913 100644
--- a/kernel/locking/rtmutex_api.c
+++ b/kernel/locking/rtmutex_api.c
@@ -322,7 +322,7 @@ int __sched rt_mutex_start_proxy_lock(struct rt_mutex_base *lock,
raw_spin_lock_irq(&lock->wait_lock);
ret = __rt_mutex_start_proxy_lock(lock, waiter, task);
- if (unlikely(ret))
+ if (unlikely(ret < 0))
remove_waiter(lock, waiter);
raw_spin_unlock_irq(&lock->wait_lock);
--
2.50.1

View File

@ -49,10 +49,11 @@
# define buildid .local
%define specversion 4.18.0
%define pkgrelease 553.141.1.el8_10
%define pkgrelease 553.141.2.el8_10
%define tarfile_release 553.141.1.el8_10
# allow pkg_release to have configurable %%{?dist} tag
%define specrelease 553.141.1%{?dist}
%define specrelease 553.141.2%{?dist}
%define pkg_release %{specrelease}%{?buildid}
@ -446,7 +447,7 @@ BuildRequires: xmlto
BuildRequires: asciidoc
%endif
Source0: linux-%{specversion}-%{pkgrelease}.tar.xz
Source0: linux-%{specversion}-%{tarfile_release}.tar.xz
Source9: x509.genkey
@ -550,6 +551,10 @@ Patch2005: 0005-Bring-back-deprecated-pci-ids-to-qla2xxx-driver.patch
Patch2006: 0006-Bring-back-deprecated-pci-ids-to-lpfc-driver.patch
Patch2007: 0007-Bring-back-deprecated-pci-ids-to-qla4xxx-driver.patch
Patch2008: 0008-Bring-back-deprecated-pci-ids-to-be2iscsi-driver.patch
Patch1100: 1100-kvm-x86-fix-shadow-paging-use-after-free.patch
Patch1101: 1101-kvm-x86-mmu-ensure-hugepage-is-in-by-slot.patch
Patch1102: 1102-rtmutex-use-waiter-task-in-remove-waiter.patch
Patch1104: 1104-rtmutex-skip-remove-waiter-when-not-enqueued.patch
# END OF PATCH DEFINITIONS
@ -1108,9 +1113,9 @@ ApplyOptionalPatch()
fi
}
%setup -q -n %{name}-%{specversion}-%{pkgrelease} -c
cp -v %{SOURCE9000} linux-%{specversion}-%{pkgrelease}/certs/rhel.pem
mv linux-%{specversion}-%{pkgrelease} linux-%{KVERREL}
%setup -q -n %{name}-%{specversion}-%{tarfile_release} -c
cp -v %{SOURCE9000} linux-%{specversion}-%{tarfile_release}/certs/rhel.pem
mv linux-%{specversion}-%{tarfile_release} linux-%{KVERREL}
cd linux-%{KVERREL}
@ -1127,6 +1132,10 @@ ApplyPatch 0005-Bring-back-deprecated-pci-ids-to-qla2xxx-driver.patch
ApplyPatch 0006-Bring-back-deprecated-pci-ids-to-lpfc-driver.patch
ApplyPatch 0007-Bring-back-deprecated-pci-ids-to-qla4xxx-driver.patch
ApplyPatch 0008-Bring-back-deprecated-pci-ids-to-be2iscsi-driver.patch
ApplyPatch 1100-kvm-x86-fix-shadow-paging-use-after-free.patch
ApplyPatch 1101-kvm-x86-mmu-ensure-hugepage-is-in-by-slot.patch
ApplyPatch 1102-rtmutex-use-waiter-task-in-remove-waiter.patch
ApplyPatch 1104-rtmutex-skip-remove-waiter-when-not-enqueued.patch
# END OF PATCH APPLICATIONS
@ -2729,6 +2738,11 @@ fi
#
#
%changelog
* Wed Jul 08 2026 Andrei Lukoshko <alukoshko@almalinux.org> - 4.18.0-553.141.2
- Re-add AlmaLinux ahead-of-RHEL security fixes dropped by the 553.141.1 re-import:
KVM x86 shadow-paging use-after-free CVE-2026-46113 (1100-1101), and rtmutex
self-deadlock NULL deref in remove_waiter() upstream 3bfdc63936dd + 40a25d59e85b (1102, 1104)
* Tue Jul 07 2026 Andrei Lukoshko <alukoshko@almalinux.org> - 4.18.0-553.141.1
- hpsa: bring back deprecated PCI ids #CFHack #CFHack2024
- mptsas: bring back deprecated PCI ids #CFHack #CFHack2024