Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: KVM: one_reg coproc set and get BE fixes

Fix code that handles KVM_SET_ONE_REG, KVM_GET_ONE_REG ioctls to work in BE
image. Before this fix get/set_one_reg functions worked correctly only in
LE case - reg_from_user was taking 'void *' kernel address that actually could
be target/source memory of either 4 bytes size or 8 bytes size, and code copied
from/to user memory that could hold either 4 bytes register, 8 byte register
or pair of 4 bytes registers.

In order to work in endian agnostic way reg_from_user to reg_to_user functions
should copy register value only to kernel variable with size that matches
register size. In few place where size mismatch existed fix issue on macro
caller side.

Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

authored by

Victor Kamensky and committed by
Christoffer Dall
73891f72 27f194fd

+79 -9
+79 -9
arch/arm/kvm/coproc.c
··· 44 44 /* CSSELR values; used to index KVM_REG_ARM_DEMUX_ID_CCSIDR */ 45 45 #define CSSELR_MAX 12 46 46 47 + /* 48 + * kvm_vcpu_arch.cp15 holds cp15 registers as an array of u32, but some 49 + * of cp15 registers can be viewed either as couple of two u32 registers 50 + * or one u64 register. Current u64 register encoding is that least 51 + * significant u32 word is followed by most significant u32 word. 52 + */ 53 + static inline void vcpu_cp15_reg64_set(struct kvm_vcpu *vcpu, 54 + const struct coproc_reg *r, 55 + u64 val) 56 + { 57 + vcpu->arch.cp15[r->reg] = val & 0xffffffff; 58 + vcpu->arch.cp15[r->reg + 1] = val >> 32; 59 + } 60 + 61 + static inline u64 vcpu_cp15_reg64_get(struct kvm_vcpu *vcpu, 62 + const struct coproc_reg *r) 63 + { 64 + u64 val; 65 + 66 + val = vcpu->arch.cp15[r->reg + 1]; 67 + val = val << 32; 68 + val = val | vcpu->arch.cp15[r->reg]; 69 + return val; 70 + } 71 + 47 72 int kvm_handle_cp10_id(struct kvm_vcpu *vcpu, struct kvm_run *run) 48 73 { 49 74 kvm_inject_undefined(vcpu); ··· 707 682 { CRn( 0), CRm( 0), Op1( 1), Op2( 7), is32, NULL, get_AIDR }, 708 683 }; 709 684 685 + /* 686 + * Reads a register value from a userspace address to a kernel 687 + * variable. Make sure that register size matches sizeof(*__val). 688 + */ 710 689 static int reg_from_user(void *val, const void __user *uaddr, u64 id) 711 690 { 712 - /* This Just Works because we are little endian. */ 713 691 if (copy_from_user(val, uaddr, KVM_REG_SIZE(id)) != 0) 714 692 return -EFAULT; 715 693 return 0; 716 694 } 717 695 696 + /* 697 + * Writes a register value to a userspace address from a kernel variable. 698 + * Make sure that register size matches sizeof(*__val). 699 + */ 718 700 static int reg_to_user(void __user *uaddr, const void *val, u64 id) 719 701 { 720 - /* This Just Works because we are little endian. */ 721 702 if (copy_to_user(uaddr, val, KVM_REG_SIZE(id)) != 0) 722 703 return -EFAULT; 723 704 return 0; ··· 733 702 { 734 703 struct coproc_params params; 735 704 const struct coproc_reg *r; 705 + int ret; 736 706 737 707 if (!index_to_params(id, &params)) 738 708 return -ENOENT; ··· 742 710 if (!r) 743 711 return -ENOENT; 744 712 745 - return reg_to_user(uaddr, &r->val, id); 713 + ret = -ENOENT; 714 + if (KVM_REG_SIZE(id) == 4) { 715 + u32 val = r->val; 716 + 717 + ret = reg_to_user(uaddr, &val, id); 718 + } else if (KVM_REG_SIZE(id) == 8) { 719 + ret = reg_to_user(uaddr, &r->val, id); 720 + } 721 + return ret; 746 722 } 747 723 748 724 static int set_invariant_cp15(u64 id, void __user *uaddr) ··· 758 718 struct coproc_params params; 759 719 const struct coproc_reg *r; 760 720 int err; 761 - u64 val = 0; /* Make sure high bits are 0 for 32-bit regs */ 721 + u64 val; 762 722 763 723 if (!index_to_params(id, &params)) 764 724 return -ENOENT; ··· 766 726 if (!r) 767 727 return -ENOENT; 768 728 769 - err = reg_from_user(&val, uaddr, id); 729 + err = -ENOENT; 730 + if (KVM_REG_SIZE(id) == 4) { 731 + u32 val32; 732 + 733 + err = reg_from_user(&val32, uaddr, id); 734 + if (!err) 735 + val = val32; 736 + } else if (KVM_REG_SIZE(id) == 8) { 737 + err = reg_from_user(&val, uaddr, id); 738 + } 770 739 if (err) 771 740 return err; 772 741 ··· 1053 1004 { 1054 1005 const struct coproc_reg *r; 1055 1006 void __user *uaddr = (void __user *)(long)reg->addr; 1007 + int ret; 1056 1008 1057 1009 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) 1058 1010 return demux_c15_get(reg->id, uaddr); ··· 1065 1015 if (!r) 1066 1016 return get_invariant_cp15(reg->id, uaddr); 1067 1017 1068 - /* Note: copies two regs if size is 64 bit. */ 1069 - return reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id); 1018 + ret = -ENOENT; 1019 + if (KVM_REG_SIZE(reg->id) == 8) { 1020 + u64 val; 1021 + 1022 + val = vcpu_cp15_reg64_get(vcpu, r); 1023 + ret = reg_to_user(uaddr, &val, reg->id); 1024 + } else if (KVM_REG_SIZE(reg->id) == 4) { 1025 + ret = reg_to_user(uaddr, &vcpu->arch.cp15[r->reg], reg->id); 1026 + } 1027 + 1028 + return ret; 1070 1029 } 1071 1030 1072 1031 int kvm_arm_coproc_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg) 1073 1032 { 1074 1033 const struct coproc_reg *r; 1075 1034 void __user *uaddr = (void __user *)(long)reg->addr; 1035 + int ret; 1076 1036 1077 1037 if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) 1078 1038 return demux_c15_set(reg->id, uaddr); ··· 1094 1034 if (!r) 1095 1035 return set_invariant_cp15(reg->id, uaddr); 1096 1036 1097 - /* Note: copies two regs if size is 64 bit */ 1098 - return reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id); 1037 + ret = -ENOENT; 1038 + if (KVM_REG_SIZE(reg->id) == 8) { 1039 + u64 val; 1040 + 1041 + ret = reg_from_user(&val, uaddr, reg->id); 1042 + if (!ret) 1043 + vcpu_cp15_reg64_set(vcpu, r, val); 1044 + } else if (KVM_REG_SIZE(reg->id) == 4) { 1045 + ret = reg_from_user(&vcpu->arch.cp15[r->reg], uaddr, reg->id); 1046 + } 1047 + 1048 + return ret; 1099 1049 } 1100 1050 1101 1051 static unsigned int num_demux_regs(void)