[PATCH v2 1/4] KVM: arm64: Add assignment-specific sysreg accessor
Miguel Luis
miguel.luis at oracle.com
Wed Jun 4 03:14:50 PDT 2025
Hi Marc,
> On 4 Jun 2025, at 06:52, Marc Zyngier <maz at kernel.org> wrote:
>
> On Tue, 03 Jun 2025 19:01:34 +0100,
> Miguel Luis <miguel.luis at oracle.com> wrote:
>>
>> Hi Marc,
>>
>>> On 3 Jun 2025, at 07:08, Marc Zyngier <maz at kernel.org> wrote:
>>>
>>> Assigning a value to a system register doesn't do what it is
>>> supposed to be doing if that register is one that has RESx bits.
>>>
>>> The main problem is that we use __vcpu_sys_reg(), which can be used
>>> both as a lvalue and rvalue. When used as a lvalue, the bit masking
>>> occurs *before* the new value is assigned, meaning that we (1) do
>>> pointless work on the old cvalue, and (2) potentially assign an
>>> invalid value as we fail to apply the masks to it.
>>>
>>> Fix this by providing a new __vcpu_assign_sys_reg() that does
>>> what it says on the tin, and sanitises the *new* value instead of
>>> the old one. This comes with a significant amount of churn.
>>>
>>> Signed-off-by: Marc Zyngier <maz at kernel.org>
>>> ---
>>> arch/arm64/include/asm/kvm_host.h | 11 ++++++
>>> arch/arm64/kvm/arch_timer.c | 16 ++++----
>>> arch/arm64/kvm/hyp/exception.c | 4 +-
>>> arch/arm64/kvm/hyp/include/hyp/switch.h | 4 +-
>>> arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 6 +--
>>> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 4 +-
>>> arch/arm64/kvm/hyp/vhe/switch.c | 4 +-
>>> arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 44 +++++++++++-----------
>>> arch/arm64/kvm/pmu-emul.c | 14 +++----
>>> arch/arm64/kvm/sys_regs.c | 38 ++++++++++---------
>>> arch/arm64/kvm/sys_regs.h | 4 +-
>>> arch/arm64/kvm/vgic/vgic-v3-nested.c | 10 ++---
>>> 12 files changed, 86 insertions(+), 73 deletions(-)
>>>
>>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>>> index d941abc6b5eef..3b84ad91116b4 100644
>>> --- a/arch/arm64/include/asm/kvm_host.h
>>> +++ b/arch/arm64/include/asm/kvm_host.h
>>> @@ -1107,6 +1107,17 @@ static inline u64 *___ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)
>>> #define ctxt_sys_reg(c,r) (*__ctxt_sys_reg(c,r))
>>>
>>> u64 kvm_vcpu_apply_reg_masks(const struct kvm_vcpu *, enum vcpu_sysreg, u64);
>>> +
>>> +#define __vcpu_assign_sys_reg(v, r, val) \
>>> + do { \
>>> + const struct kvm_cpu_context *ctxt = &(v)->arch.ctxt; \
>>> + u64 __v = (val); \
>>> + if (vcpu_has_nv((v)) && (r) >= __SANITISED_REG_START__) \
>>
>> Would it make sense to make it more strict by testing < NR_SYS_REGS too?
>
> It is important to notice that you don't pass random integers here.
> You pass something that is of an enum type, for which the maximum
> value is NR_SYS_REGS. So as long as you pass a literal value, you're
> 100% safe. If you pass a constant value that goes over the limit, you
> will hit the *existing* BUILD_BUG_ON().
>
That’s correct.
> You could fall into a trap by iterating over a base value and going
> over the limit. But your check will only catch you going over the
> array, and not the state corruption you will have introduced.
>
That’s also correct.
> Finally, this is performance critical code, and I'd rather not add
> extra checks that will only be a burden at runtime.
That's understandable and so far acceptable as we're trusting reg, rd->reg and r->reg
providers' code paths.
> If you want to
> catch these overflows, using KASAN+UBSAN makes a lot more sense.
>
Thanks for your suggestion.
Thanks
Miguel
> M.
>
> --
> Jazz isn't dead. It just smells funny.
More information about the linux-arm-kernel
mailing list