On 12/12/2018 20:17, Dave Martin wrote:
> Since commit d26c25a9d19b ("arm64: KVM: Tighten guest core register
> access from userspace"), KVM_{GET,SET}_ONE_REG rejects register IDs
> that do not correspond to a single underlying architectural register.
>
> KVM_GET_REG_LIST was not changed to match however: instead, it
> simply yields a list of 32-bit register IDs that together cover the
> whole kvm_regs struct. This means that if userspace tries to use
> the resulting list of IDs directly to drive calls to KVM_*_ONE_REG,
> some of those calls will now fail.
>
> This was not the intention. Instead, iterating KVM_*_ONE_REG over
> the list of IDs returned by KVM_GET_REG_LIST should be guaranteed
> to work.
>
> This patch fixes the problem by splitting validate_core_reg_id()
> into a backend core_reg_size_from_offset() which does all of the
> work except for checking that the size field in the register ID
> matches, and kvm_arm_copy_reg_indices() and num_core_regs() are
> converted to use this to enumerate the valid offsets.
>
> kvm_arm_copy_reg_indices() now also sets the register ID size field
> appropriately based on the value returned, so the register ID
> supplied to userspace is fully qualified for use with the register
> access ioctls.
>
> Cc: [email protected]
> Fixes: d26c25a9d19b ("arm64: KVM: Tighten guest core register access from
> userspace")
> Signed-off-by: Dave Martin <[email protected]>
> ---
> arch/arm64/kvm/guest.c | 61
> ++++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 54 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
> index dd436a5..cbe423b 100644
> --- a/arch/arm64/kvm/guest.c
> +++ b/arch/arm64/kvm/guest.c
> @@ -57,9 +57,8 @@ static u64 core_reg_offset_from_id(u64 id)
> return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
> }
>
> -static int validate_core_offset(const struct kvm_one_reg *reg)
> +static int core_reg_size_from_offset(u64 off)
> {
> - u64 off = core_reg_offset_from_id(reg->id);
> int size;
>
> switch (off) {
> @@ -89,8 +88,21 @@ static int validate_core_offset(const struct kvm_one_reg
> *reg)
> return -EINVAL;
> }
>
> - if (KVM_REG_SIZE(reg->id) == size &&
> - IS_ALIGNED(off, size / sizeof(__u32)))
> + if (IS_ALIGNED(off, size / sizeof(__u32)))
> + return size;
> +
> + return -EINVAL;
> +}
> +
> +static int validate_core_offset(const struct kvm_one_reg *reg)
> +{
> + u64 off = core_reg_offset_from_id(reg->id);
> + int size = core_reg_size_from_offset(off);
> +
> + if (size < 0)
> + return -EINVAL;
> +
> + if (KVM_REG_SIZE(reg->id) == size)
> return 0;
>
> return -EINVAL;
> @@ -195,7 +207,19 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu,
> struct kvm_regs *regs)
>
> static unsigned long num_core_regs(void)
> {
> - return sizeof(struct kvm_regs) / sizeof(__u32);
> + unsigned int i;
> + int n = 0;
> +
> + for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> + int size = core_reg_size_from_offset(i);
> +
> + if (size < 0)
> + continue;
> +
> + n++;
> + }
> +
> + return n;
> }
>
> /**
> @@ -270,11 +294,34 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu)
> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
> {
> unsigned int i;
> - const u64 core_reg = KVM_REG_ARM64 | KVM_REG_SIZE_U64 |
> KVM_REG_ARM_CORE;
> int ret;
>
> for (i = 0; i < sizeof(struct kvm_regs) / sizeof(__u32); i++) {
> - if (put_user(core_reg | i, uindices))
> + u64 reg = KVM_REG_ARM64 | KVM_REG_ARM_CORE | i;
> + int size = core_reg_size_from_offset(i);
> +
> + if (size < 0)
> + continue;
> +
> + switch (size) {
> + case sizeof(__u32):
> + reg |= KVM_REG_SIZE_U32;
> + break;
> +
> + case sizeof(__u64):
> + reg |= KVM_REG_SIZE_U64;
> + break;
> +
> + case sizeof(__uint128_t):
> + reg |= KVM_REG_SIZE_U128;
> + break;
> +
> + default:
> + WARN_ON(1);
> + continue;
> + }
> +
> + if (put_user(reg, uindices))
> return -EFAULT;
> uindices++;
> }
>
I'm quite keen on queuing this for 4.21, but I'd like Peter's seal of
approval on it.
Peter?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm