Skip to content

Commit d26c25a

Browse files
Dave Martinwildea01
Dave Martin
authored andcommitted
arm64: KVM: Tighten guest core register access from userspace
We currently allow userspace to access the core register file in about any possible way, including straddling multiple registers and doing unaligned accesses. This is not the expected use of the ABI, and nobody is actually using it that way. Let's tighten it by explicitly checking the size and alignment for each field of the register file. Cc: <stable@vger.kernel.org> Fixes: 2f4a07c ("arm64: KVM: guest one-reg interface") Reviewed-by: Christoffer Dall <christoffer.dall@arm.com> Reviewed-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Dave Martin <Dave.Martin@arm.com> [maz: rewrote Dave's initial patch to be more easily backported] Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
1 parent 031e6e6 commit d26c25a

File tree

1 file changed

+45
-0
lines changed

1 file changed

+45
-0
lines changed

Diff for: arch/arm64/kvm/guest.c

+45
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,45 @@ static u64 core_reg_offset_from_id(u64 id)
5757
return id & ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_ARM_CORE);
5858
}
5959

60+
static int validate_core_offset(const struct kvm_one_reg *reg)
61+
{
62+
u64 off = core_reg_offset_from_id(reg->id);
63+
int size;
64+
65+
switch (off) {
66+
case KVM_REG_ARM_CORE_REG(regs.regs[0]) ...
67+
KVM_REG_ARM_CORE_REG(regs.regs[30]):
68+
case KVM_REG_ARM_CORE_REG(regs.sp):
69+
case KVM_REG_ARM_CORE_REG(regs.pc):
70+
case KVM_REG_ARM_CORE_REG(regs.pstate):
71+
case KVM_REG_ARM_CORE_REG(sp_el1):
72+
case KVM_REG_ARM_CORE_REG(elr_el1):
73+
case KVM_REG_ARM_CORE_REG(spsr[0]) ...
74+
KVM_REG_ARM_CORE_REG(spsr[KVM_NR_SPSR - 1]):
75+
size = sizeof(__u64);
76+
break;
77+
78+
case KVM_REG_ARM_CORE_REG(fp_regs.vregs[0]) ...
79+
KVM_REG_ARM_CORE_REG(fp_regs.vregs[31]):
80+
size = sizeof(__uint128_t);
81+
break;
82+
83+
case KVM_REG_ARM_CORE_REG(fp_regs.fpsr):
84+
case KVM_REG_ARM_CORE_REG(fp_regs.fpcr):
85+
size = sizeof(__u32);
86+
break;
87+
88+
default:
89+
return -EINVAL;
90+
}
91+
92+
if (KVM_REG_SIZE(reg->id) == size &&
93+
IS_ALIGNED(off, size / sizeof(__u32)))
94+
return 0;
95+
96+
return -EINVAL;
97+
}
98+
6099
static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
61100
{
62101
/*
@@ -76,6 +115,9 @@ static int get_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
76115
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
77116
return -ENOENT;
78117

118+
if (validate_core_offset(reg))
119+
return -EINVAL;
120+
79121
if (copy_to_user(uaddr, ((u32 *)regs) + off, KVM_REG_SIZE(reg->id)))
80122
return -EFAULT;
81123

@@ -98,6 +140,9 @@ static int set_core_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
98140
(off + (KVM_REG_SIZE(reg->id) / sizeof(__u32))) >= nr_regs)
99141
return -ENOENT;
100142

143+
if (validate_core_offset(reg))
144+
return -EINVAL;
145+
101146
if (KVM_REG_SIZE(reg->id) > sizeof(tmp))
102147
return -EINVAL;
103148

0 commit comments

Comments
 (0)