Import of kernel-4.18.0-553.141.2.el8_10
This commit is contained in:
parent
cfa947f880
commit
68a5b68746
@ -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);
|
||||
@ -5999,13 +6043,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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
|
||||
kernel.centos,1,Red Hat,kernel-core,4.18.0-553.141.1.el8.x86_64,mailto:secalert@redhat.com
|
||||
kernel.centos,1,Red Hat,kernel-core,4.18.0-553.141.2.el8.x86_64,mailto:secalert@redhat.com
|
||||
|
||||
@ -1501,20 +1501,26 @@ 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);
|
||||
if (!waiter_task) /* never enqueued */
|
||||
return;
|
||||
|
||||
raw_spin_lock(&waiter_task->pi_lock);
|
||||
rt_mutex_dequeue(lock, waiter);
|
||||
current->pi_blocked_on = NULL;
|
||||
raw_spin_unlock(¤t->pi_lock);
|
||||
waiter_task->pi_blocked_on = NULL;
|
||||
raw_spin_unlock(&waiter_task->pi_lock);
|
||||
|
||||
/*
|
||||
* Only update priority if the waiter was the highest priority
|
||||
@ -1550,7 +1556,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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user