mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
ANDROID: KVM: arm64: Strictly check page type in MEM_RELINQUISH hypercall
The VM should only relinquish "normal" pages. For a protected VM, this means PAGE_OWNED; For a normal VM, this means PAGE_SHARED_BORROWED. All other page types are rejected and failure is reported to the caller. Bug: 259217067 Change-Id: Icff3474dc2c975a6c5befe546c5521a05b3bd575 Signed-off-by: Keir Fraser <keirf@google.com>
This commit is contained in:
@@ -265,7 +265,6 @@ static int reclaim_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
|
||||
{
|
||||
kvm_pte_t pte = *ptep;
|
||||
struct hyp_page *page;
|
||||
u64 *pa = arg;
|
||||
|
||||
if (!kvm_pte_valid(pte))
|
||||
return 0;
|
||||
@@ -277,8 +276,6 @@ static int reclaim_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
|
||||
fallthrough;
|
||||
case PKVM_PAGE_SHARED_BORROWED:
|
||||
case PKVM_PAGE_SHARED_OWNED:
|
||||
if (pa)
|
||||
*pa = kvm_pte_to_phys(pte);
|
||||
page->flags |= HOST_PAGE_PENDING_RECLAIM;
|
||||
break;
|
||||
default:
|
||||
@@ -318,13 +315,44 @@ void reclaim_guest_pages(struct pkvm_hyp_vm *vm, struct kvm_hyp_memcache *mc)
|
||||
}
|
||||
}
|
||||
|
||||
struct relinquish_data {
|
||||
enum pkvm_page_state expected_state;
|
||||
u64 pa;
|
||||
};
|
||||
|
||||
static int relinquish_walker(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
|
||||
enum kvm_pgtable_walk_flags flag, void * const arg)
|
||||
{
|
||||
kvm_pte_t pte = *ptep;
|
||||
struct hyp_page *page;
|
||||
struct relinquish_data *data = arg;
|
||||
enum pkvm_page_state state;
|
||||
|
||||
if (!kvm_pte_valid(pte))
|
||||
return 0;
|
||||
|
||||
state = pkvm_getstate(kvm_pgtable_stage2_pte_prot(pte));
|
||||
if (state != data->expected_state)
|
||||
return -EPERM;
|
||||
|
||||
page = hyp_phys_to_page(kvm_pte_to_phys(pte));
|
||||
if (state == PKVM_PAGE_OWNED)
|
||||
page->flags |= HOST_PAGE_NEED_POISONING;
|
||||
page->flags |= HOST_PAGE_PENDING_RECLAIM;
|
||||
|
||||
data->pa = kvm_pte_to_phys(pte);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __pkvm_guest_relinquish_to_host(struct pkvm_hyp_vcpu *vcpu,
|
||||
u64 ipa, u64 *ppa)
|
||||
{
|
||||
struct relinquish_data data;
|
||||
struct kvm_pgtable_walker walker = {
|
||||
.cb = reclaim_walker,
|
||||
.arg = ppa,
|
||||
.flags = KVM_PGTABLE_WALK_LEAF
|
||||
.cb = relinquish_walker,
|
||||
.flags = KVM_PGTABLE_WALK_LEAF,
|
||||
.arg = &data,
|
||||
};
|
||||
struct pkvm_hyp_vm *vm = pkvm_hyp_vcpu_to_hyp_vm(vcpu);
|
||||
int ret;
|
||||
@@ -332,8 +360,13 @@ int __pkvm_guest_relinquish_to_host(struct pkvm_hyp_vcpu *vcpu,
|
||||
host_lock_component();
|
||||
guest_lock_component(vm);
|
||||
|
||||
/* Expected page state depends on VM type. */
|
||||
data.expected_state = pkvm_hyp_vcpu_is_protected(vcpu) ?
|
||||
PKVM_PAGE_OWNED :
|
||||
PKVM_PAGE_SHARED_BORROWED;
|
||||
|
||||
/* Set default pa value to "not found". */
|
||||
*ppa = 0;
|
||||
data.pa = 0;
|
||||
|
||||
/* If ipa is mapped: sets page flags, and gets the pa. */
|
||||
ret = kvm_pgtable_walk(&vm->pgt, ipa, PAGE_SIZE, &walker);
|
||||
@@ -345,6 +378,7 @@ int __pkvm_guest_relinquish_to_host(struct pkvm_hyp_vcpu *vcpu,
|
||||
guest_unlock_component(vm);
|
||||
host_unlock_component();
|
||||
|
||||
*ppa = data.pa;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user