|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2] x86/shadow: Correct guest behaviour when creating PTEs above maxphysaddr
On 14/02/17 17:45, Andrew Cooper wrote:
> On 14/02/17 17:42, George Dunlap wrote:
>> On 13/02/17 11:00, Andrew Cooper wrote:
>>> XSA-173 (c/s 8b1764833) introduces gfn_bits, and an upper limit which might
>>> be
>>> lower than the real maxphysaddr, to avoid overflowing the superpage shadow
>>> backpointer.
>>>
>>> However, plenty of hardware has a physical address width less that 44 bits,
>>> and the code added in shadow_domain_init() is a straight assignment. This
>>> causes gfn_bits to be increased beyond the physical address width on most
>>> Intel consumer hardware (typically a width of 39, which is the number
>>> reported
>>> to the guest via CPUID).
>>>
>>> If the guest intentionally creates a PTE referencing a physical address
>>> between 39 and 44 bits, the result should be #PF[RSVD] for using the virtual
>>> address. However, the shadow code accepts the PTE, shadows it, and the
>>> virtual address works normally.
>>>
>>> Introduce paging_max_paddr_bits() to calculate the largest guest physical
>>> address supportable by the paging infrastructure, and update
>>> recalculate_cpuid_policy() to take this into account when clamping the
>>> guests
>>> cpuid_policy to reality. Remove gfn_bits and rework its users in terms of a
>>> guests maxphysaddr.
>>>
>>> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
>>> ---
>>> CC: Jan Beulich <JBeulich@xxxxxxxx>
>>> CC: Tim Deegan <tim@xxxxxxx>
>>> CC: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
>>> CC: Jun Nakajima <jun.nakajima@xxxxxxxxx>
>>> CC: Kevin Tian <kevin.tian@xxxxxxxxx>
>>>
>>> v2:
>>> * Introduce paging_max_paddr_bits() rather than moving paging logic into
>>> recalculate_cpuid_policy().
>>> * Rewrite half of the commit message.
>>> ---
>>> xen/arch/x86/cpuid.c | 7 +++----
>>> xen/arch/x86/hvm/vmx/vvmx.c | 2 +-
>>> xen/arch/x86/mm/guest_walk.c | 3 ++-
>>> xen/arch/x86/mm/hap/hap.c | 2 --
>>> xen/arch/x86/mm/p2m.c | 3 ++-
>>> xen/arch/x86/mm/shadow/common.c | 10 ----------
>>> xen/arch/x86/mm/shadow/multi.c | 3 ++-
>>> xen/include/asm-x86/domain.h | 3 ---
>>> xen/include/asm-x86/paging.h | 16 ++++++++++++++++
>>> 9 files changed, 26 insertions(+), 23 deletions(-)
>>>
>>> diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c
>>> index e0a387e..3378f7a 100644
>>> --- a/xen/arch/x86/cpuid.c
>>> +++ b/xen/arch/x86/cpuid.c
>>> @@ -6,6 +6,7 @@
>>> #include <asm/hvm/nestedhvm.h>
>>> #include <asm/hvm/svm/svm.h>
>>> #include <asm/hvm/vmx/vmcs.h>
>>> +#include <asm/paging.h>
>>> #include <asm/processor.h>
>>> #include <asm/xstate.h>
>>>
>>> @@ -502,11 +503,9 @@ void recalculate_cpuid_policy(struct domain *d)
>>>
>>> cpuid_featureset_to_policy(fs, p);
>>>
>>> - p->extd.maxphysaddr = min(p->extd.maxphysaddr, max->extd.maxphysaddr);
>>> p->extd.maxphysaddr = min_t(uint8_t, p->extd.maxphysaddr,
>>> - d->arch.paging.gfn_bits + PAGE_SHIFT);
>>> - p->extd.maxphysaddr = max_t(uint8_t, p->extd.maxphysaddr,
>>> - (p->basic.pae || p->basic.pse36) ? 36 :
>>> 32);
>>> + paging_max_paddr_bits(d));
>>> + p->extd.maxphysaddr = max_t(uint8_t, p->extd.maxphysaddr, 32);
>>>
>>> p->extd.maxlinaddr = p->extd.lm ? 48 : 32;
>>>
>>> diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c
>>> index 9c61b5b..774a11f 100644
>>> --- a/xen/arch/x86/hvm/vmx/vvmx.c
>>> +++ b/xen/arch/x86/hvm/vmx/vvmx.c
>>> @@ -1381,7 +1381,7 @@ int nvmx_handle_vmxon(struct cpu_user_regs *regs)
>>> }
>>>
>>> if ( (gpa & ~PAGE_MASK) ||
>>> - (gpa >> (v->domain->arch.paging.gfn_bits + PAGE_SHIFT)) )
>>> + (gpa >> v->domain->arch.cpuid->extd.maxphysaddr) )
>>> {
>>> vmfail_invalid(regs);
>>> return X86EMUL_OKAY;
>>> diff --git a/xen/arch/x86/mm/guest_walk.c b/xen/arch/x86/mm/guest_walk.c
>>> index a67fd5a..5ad8cf6 100644
>>> --- a/xen/arch/x86/mm/guest_walk.c
>>> +++ b/xen/arch/x86/mm/guest_walk.c
>>> @@ -435,7 +435,8 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain
>>> *p2m,
>>> /* If this guest has a restricted physical address space then the
>>> * target GFN must fit within it. */
>>> if ( !(rc & _PAGE_PRESENT)
>>> - && gfn_x(guest_l1e_get_gfn(gw->l1e)) >> d->arch.paging.gfn_bits )
>>> + && gfn_x(guest_l1e_get_gfn(gw->l1e)) >>
>>> + (d->arch.cpuid->extd.maxphysaddr - PAGE_SHIFT) )
>> This pattern, of taking a gfn and shifting it by
>> (cpuid->ectd.maxphysaddr-PAGE_SHIFT) to see if it's valid happens
>> several times; it seems like for both clarity and avoiding mistakes, it
>> would be better if it were put into a macro.
>>
>> Everything else looks good to me. (No opinion on the other questions
>> raised so far.)
>
> static inline unsigned int gfn_bits(const struct domain *d)
> {
> return d->arch.cpuid->extd.maxphysaddr - PAGE_SHIFT;
> }
>
> ?
>
> I do like that idea. It would certainly make all of the callsites more
> readable.
>
> I can happily fold that change in if others agree.
I was thinking of going further:
static inline bool guest_gfn_valid(domain *d, gfn_t gfn)
{
return !!(gfn_x(gfn) >> (d->arch.cpuid...) )
}
("Valid" might be a bit ambiguous, but I can't think of a better
description off the top of my head.)
-George
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |