From: Marc Zyngier <maz@kernel.org>
To: Will Deacon <will@kernel.org>
Cc: kvm@vger.kernel.org, stable@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, kernel-team@android.com,
kvmarm@lists.cs.columbia.edu
Subject: Re: [PATCH] KVM: arm64: Assume write fault on S1PTW permission fault on instruction fetch
Date: Mon, 14 Sep 2020 10:32:10 +0100 [thread overview]
Message-ID: <edbb56d954913bbe8422c9f32aee9c76@kernel.org> (raw)
In-Reply-To: <20200911155912.GB20527@willie-the-truck>
On 2020-09-11 16:59, Will Deacon wrote:
> On Wed, Sep 09, 2020 at 10:05:27PM +0100, Marc Zyngier wrote:
>> KVM currently assumes that an instruction abort can never be a write.
>> This is in general true, except when the abort is triggered by
>> a S1PTW on instruction fetch that tries to update the S1 page tables
>> (to set AF, for example).
>>
>> This can happen if the page tables have been paged out and brought
>> back in without seeing a direct write to them (they are thus marked
>> read only), and the fault handling code will make the PT executable(!)
>> instead of writable. The guest gets stuck forever.
>>
>> In these conditions, the permission fault must be considered as
>> a write so that the Stage-1 update can take place. This is essentially
>> the I-side equivalent of the problem fixed by 60e21a0ef54c ("arm64:
>> KVM:
>> Take S1 walks into account when determining S2 write faults").
>>
>> Update both kvm_is_write_fault() to return true on IABT+S1PTW, as well
>> as kvm_vcpu_trap_is_iabt() to return false in the same conditions.
>>
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Marc Zyngier <maz@kernel.org>
>> ---
>> This could do with some cleanup (kvm_vcpu_dabt_iss1tw has nothing to
>> do
>> with data aborts), but I've chosen to keep the patch simple in order
>> to
>> ease backporting.
>>
>> arch/arm64/include/asm/kvm_emulate.h | 6 +++++-
>> 1 file changed, 5 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h
>> b/arch/arm64/include/asm/kvm_emulate.h
>> index d21676409a24..33d7e16edaa3 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -480,7 +480,8 @@ static __always_inline u8
>> kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
>>
>> static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
>> {
>> - return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
>> + return (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW &&
>> + !kvm_vcpu_dabt_iss1tw(vcpu));
>> }
>>
>> static __always_inline u8 kvm_vcpu_trap_get_fault(const struct
>> kvm_vcpu *vcpu)
>> @@ -520,6 +521,9 @@ static __always_inline int
>> kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>>
>> static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
>> {
>> + if (kvm_vcpu_dabt_iss1tw(vcpu))
>> + return true;
>> +
>
> Hmm, I'm a bit uneasy about the interaction of this with
> kvm_handle_guest_abort() if we take an S1PTW fault on instruction fetch
> with our page-tables sitting in a read-only memslot. In this case, I
> think we'll end up injecting a data abort into the guest instead of an
> instruction abort. It hurts my brain thinking about it though.
Good point.
>
> Overall, I'd be inclined to:
>
> 1. Rename kvm_vcpu_dabt_iss1tw() to kvm_vcpu_abt_iss1tw()
>
> 2. Introduce something like kvm_is_exec_fault() as:
>
> return kvm_vcpu_trap_is_iabt() && !kvm_vcpu_abt_iss1tw();
>
> 3. Use that new function in user_mem_abort() to assign 'exec_fault'
>
> 4. Hack kvm_is_write_fault() as you have done above.
>
> Which I _think_ should work (famous last words)...
That's what I initially had, but went for ease of backporting instead...
Back to square one.
> The only nasty bit is that we then duplicate the kvm_vcpu_dabt_iss1tw()
> check in both kvm_is_write_fault() and kvm_vcpu_dabt_iswrite(). Perhaps
> we could remove the latter function in favour of the first? Anyway,
> obviously this sort of cleanup isn't for stable.
I've had a look, and I believe this is safe. We always check for S1PTW
*before* using kvm_vcpu_dabt_iswrite() anyway. I'll add that as a second
patch that we can merge later if required.
M.
--
Jazz is not dead. It just smells funny...
_______________________________________________
kvmarm mailing list
kvmarm@lists.cs.columbia.edu
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: Will Deacon <will@kernel.org>
Cc: kvm@vger.kernel.org, Suzuki K Poulose <suzuki.poulose@arm.com>,
stable@vger.kernel.org, James Morse <james.morse@arm.com>,
linux-arm-kernel@lists.infradead.org, kernel-team@android.com,
kvmarm@lists.cs.columbia.edu,
Julien Thierry <julien.thierry.kdev@gmail.com>
Subject: Re: [PATCH] KVM: arm64: Assume write fault on S1PTW permission fault on instruction fetch
Date: Mon, 14 Sep 2020 10:32:10 +0100 [thread overview]
Message-ID: <edbb56d954913bbe8422c9f32aee9c76@kernel.org> (raw)
In-Reply-To: <20200911155912.GB20527@willie-the-truck>
On 2020-09-11 16:59, Will Deacon wrote:
> On Wed, Sep 09, 2020 at 10:05:27PM +0100, Marc Zyngier wrote:
>> KVM currently assumes that an instruction abort can never be a write.
>> This is in general true, except when the abort is triggered by
>> a S1PTW on instruction fetch that tries to update the S1 page tables
>> (to set AF, for example).
>>
>> This can happen if the page tables have been paged out and brought
>> back in without seeing a direct write to them (they are thus marked
>> read only), and the fault handling code will make the PT executable(!)
>> instead of writable. The guest gets stuck forever.
>>
>> In these conditions, the permission fault must be considered as
>> a write so that the Stage-1 update can take place. This is essentially
>> the I-side equivalent of the problem fixed by 60e21a0ef54c ("arm64:
>> KVM:
>> Take S1 walks into account when determining S2 write faults").
>>
>> Update both kvm_is_write_fault() to return true on IABT+S1PTW, as well
>> as kvm_vcpu_trap_is_iabt() to return false in the same conditions.
>>
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Marc Zyngier <maz@kernel.org>
>> ---
>> This could do with some cleanup (kvm_vcpu_dabt_iss1tw has nothing to
>> do
>> with data aborts), but I've chosen to keep the patch simple in order
>> to
>> ease backporting.
>>
>> arch/arm64/include/asm/kvm_emulate.h | 6 +++++-
>> 1 file changed, 5 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h
>> b/arch/arm64/include/asm/kvm_emulate.h
>> index d21676409a24..33d7e16edaa3 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -480,7 +480,8 @@ static __always_inline u8
>> kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
>>
>> static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
>> {
>> - return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
>> + return (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW &&
>> + !kvm_vcpu_dabt_iss1tw(vcpu));
>> }
>>
>> static __always_inline u8 kvm_vcpu_trap_get_fault(const struct
>> kvm_vcpu *vcpu)
>> @@ -520,6 +521,9 @@ static __always_inline int
>> kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>>
>> static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
>> {
>> + if (kvm_vcpu_dabt_iss1tw(vcpu))
>> + return true;
>> +
>
> Hmm, I'm a bit uneasy about the interaction of this with
> kvm_handle_guest_abort() if we take an S1PTW fault on instruction fetch
> with our page-tables sitting in a read-only memslot. In this case, I
> think we'll end up injecting a data abort into the guest instead of an
> instruction abort. It hurts my brain thinking about it though.
Good point.
>
> Overall, I'd be inclined to:
>
> 1. Rename kvm_vcpu_dabt_iss1tw() to kvm_vcpu_abt_iss1tw()
>
> 2. Introduce something like kvm_is_exec_fault() as:
>
> return kvm_vcpu_trap_is_iabt() && !kvm_vcpu_abt_iss1tw();
>
> 3. Use that new function in user_mem_abort() to assign 'exec_fault'
>
> 4. Hack kvm_is_write_fault() as you have done above.
>
> Which I _think_ should work (famous last words)...
That's what I initially had, but went for ease of backporting instead...
Back to square one.
> The only nasty bit is that we then duplicate the kvm_vcpu_dabt_iss1tw()
> check in both kvm_is_write_fault() and kvm_vcpu_dabt_iswrite(). Perhaps
> we could remove the latter function in favour of the first? Anyway,
> obviously this sort of cleanup isn't for stable.
I've had a look, and I believe this is safe. We always check for S1PTW
*before* using kvm_vcpu_dabt_iswrite() anyway. I'll add that as a second
patch that we can merge later if required.
M.
--
Jazz is not dead. It just smells funny...
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: Will Deacon <will@kernel.org>
Cc: kvm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
kvmarm@lists.cs.columbia.edu, James Morse <james.morse@arm.com>,
Julien Thierry <julien.thierry.kdev@gmail.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
kernel-team@android.com, stable@vger.kernel.org
Subject: Re: [PATCH] KVM: arm64: Assume write fault on S1PTW permission fault on instruction fetch
Date: Mon, 14 Sep 2020 10:32:10 +0100 [thread overview]
Message-ID: <edbb56d954913bbe8422c9f32aee9c76@kernel.org> (raw)
In-Reply-To: <20200911155912.GB20527@willie-the-truck>
On 2020-09-11 16:59, Will Deacon wrote:
> On Wed, Sep 09, 2020 at 10:05:27PM +0100, Marc Zyngier wrote:
>> KVM currently assumes that an instruction abort can never be a write.
>> This is in general true, except when the abort is triggered by
>> a S1PTW on instruction fetch that tries to update the S1 page tables
>> (to set AF, for example).
>>
>> This can happen if the page tables have been paged out and brought
>> back in without seeing a direct write to them (they are thus marked
>> read only), and the fault handling code will make the PT executable(!)
>> instead of writable. The guest gets stuck forever.
>>
>> In these conditions, the permission fault must be considered as
>> a write so that the Stage-1 update can take place. This is essentially
>> the I-side equivalent of the problem fixed by 60e21a0ef54c ("arm64:
>> KVM:
>> Take S1 walks into account when determining S2 write faults").
>>
>> Update both kvm_is_write_fault() to return true on IABT+S1PTW, as well
>> as kvm_vcpu_trap_is_iabt() to return false in the same conditions.
>>
>> Cc: stable@vger.kernel.org
>> Signed-off-by: Marc Zyngier <maz@kernel.org>
>> ---
>> This could do with some cleanup (kvm_vcpu_dabt_iss1tw has nothing to
>> do
>> with data aborts), but I've chosen to keep the patch simple in order
>> to
>> ease backporting.
>>
>> arch/arm64/include/asm/kvm_emulate.h | 6 +++++-
>> 1 file changed, 5 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h
>> b/arch/arm64/include/asm/kvm_emulate.h
>> index d21676409a24..33d7e16edaa3 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -480,7 +480,8 @@ static __always_inline u8
>> kvm_vcpu_trap_get_class(const struct kvm_vcpu *vcpu)
>>
>> static inline bool kvm_vcpu_trap_is_iabt(const struct kvm_vcpu *vcpu)
>> {
>> - return kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW;
>> + return (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_IABT_LOW &&
>> + !kvm_vcpu_dabt_iss1tw(vcpu));
>> }
>>
>> static __always_inline u8 kvm_vcpu_trap_get_fault(const struct
>> kvm_vcpu *vcpu)
>> @@ -520,6 +521,9 @@ static __always_inline int
>> kvm_vcpu_sys_get_rt(struct kvm_vcpu *vcpu)
>>
>> static inline bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
>> {
>> + if (kvm_vcpu_dabt_iss1tw(vcpu))
>> + return true;
>> +
>
> Hmm, I'm a bit uneasy about the interaction of this with
> kvm_handle_guest_abort() if we take an S1PTW fault on instruction fetch
> with our page-tables sitting in a read-only memslot. In this case, I
> think we'll end up injecting a data abort into the guest instead of an
> instruction abort. It hurts my brain thinking about it though.
Good point.
>
> Overall, I'd be inclined to:
>
> 1. Rename kvm_vcpu_dabt_iss1tw() to kvm_vcpu_abt_iss1tw()
>
> 2. Introduce something like kvm_is_exec_fault() as:
>
> return kvm_vcpu_trap_is_iabt() && !kvm_vcpu_abt_iss1tw();
>
> 3. Use that new function in user_mem_abort() to assign 'exec_fault'
>
> 4. Hack kvm_is_write_fault() as you have done above.
>
> Which I _think_ should work (famous last words)...
That's what I initially had, but went for ease of backporting instead...
Back to square one.
> The only nasty bit is that we then duplicate the kvm_vcpu_dabt_iss1tw()
> check in both kvm_is_write_fault() and kvm_vcpu_dabt_iswrite(). Perhaps
> we could remove the latter function in favour of the first? Anyway,
> obviously this sort of cleanup isn't for stable.
I've had a look, and I believe this is safe. We always check for S1PTW
*before* using kvm_vcpu_dabt_iswrite() anyway. I'll add that as a second
patch that we can merge later if required.
M.
--
Jazz is not dead. It just smells funny...
next prev parent reply other threads:[~2020-09-14 9:32 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-09 21:05 [PATCH] KVM: arm64: Assume write fault on S1PTW permission fault on instruction fetch Marc Zyngier
2020-09-09 21:05 ` Marc Zyngier
2020-09-09 21:05 ` Marc Zyngier
2020-09-10 16:34 ` Sasha Levin
2020-09-10 16:34 ` Sasha Levin
2020-09-11 15:59 ` Will Deacon
2020-09-11 15:59 ` Will Deacon
2020-09-11 15:59 ` Will Deacon
2020-09-14 9:32 ` Marc Zyngier [this message]
2020-09-14 9:32 ` Marc Zyngier
2020-09-14 9:32 ` Marc Zyngier
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=edbb56d954913bbe8422c9f32aee9c76@kernel.org \
--to=maz@kernel.org \
--cc=kernel-team@android.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.cs.columbia.edu \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=stable@vger.kernel.org \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.