Stack corruption may occur if too big 'level' or 'xlevel' values passed on command line with KVM enabled, due to limited size of cpuid_data in kvm_arch_init_vcpu().
reproduces with: qemu -enable-kvm -cpu qemu64,level=4294967295 or qemu -enable-kvm -cpu qemu64,xlevel=4294967295 Check if there is space in cpuid_data before passing it to cpu_x86_cpuid() or abort() if there is not space. Signed-off-by: Igor Mammedov <imamm...@redhat.com> --- target-i386/kvm.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 3acff40..8885b22 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -413,10 +413,13 @@ static void cpu_update_state(void *opaque, int running, RunState state) int kvm_arch_init_vcpu(CPUState *cs) { + const int max_cpuid_entries = 100; struct { struct kvm_cpuid2 cpuid; - struct kvm_cpuid_entry2 entries[100]; + struct kvm_cpuid_entry2 entries[max_cpuid_entries]; } QEMU_PACKED cpuid_data; + const struct kvm_cpuid_entry2 *cpuid_last_entry = + &cpuid_data.entries[max_cpuid_entries - 1]; X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; uint32_t limit, i, j, cpuid_i; @@ -503,6 +506,10 @@ int kvm_arch_init_vcpu(CPUState *cs) for (i = 0; i <= limit; i++) { c = &cpuid_data.entries[cpuid_i++]; + if (c > cpuid_last_entry) { + fprintf(stderr, "unsupported level value: 0x%x\n", limit); + abort(); + } switch (i) { case 2: { @@ -517,6 +524,11 @@ int kvm_arch_init_vcpu(CPUState *cs) for (j = 1; j < times; ++j) { c = &cpuid_data.entries[cpuid_i++]; + if (c > cpuid_last_entry) { + fprintf(stderr, "cpuid_data is full, no space for " + "cpuid(eax:2):eax & 0xf = 0x%x\n", times); + abort(); + } c->function = i; c->flags = KVM_CPUID_FLAG_STATEFUL_FUNC; cpu_x86_cpuid(env, i, 0, &c->eax, &c->ebx, &c->ecx, &c->edx); @@ -545,6 +557,11 @@ int kvm_arch_init_vcpu(CPUState *cs) continue; } c = &cpuid_data.entries[cpuid_i++]; + if (c > cpuid_last_entry) { + fprintf(stderr, "cpuid_data is full, no space for " + "cpuid(eax:0x%x,ecx:0x%x)\n", i, j); + abort(); + } } break; default: @@ -558,6 +575,10 @@ int kvm_arch_init_vcpu(CPUState *cs) for (i = 0x80000000; i <= limit; i++) { c = &cpuid_data.entries[cpuid_i++]; + if (c > cpuid_last_entry) { + fprintf(stderr, "unsupported xlevel value: 0x%x\n", limit); + abort(); + } c->function = i; c->flags = 0; @@ -570,6 +591,10 @@ int kvm_arch_init_vcpu(CPUState *cs) for (i = 0xC0000000; i <= limit; i++) { c = &cpuid_data.entries[cpuid_i++]; + if (c > cpuid_last_entry) { + fprintf(stderr, "unsupported xlevel2 value: 0x%x\n", limit); + abort(); + } c->function = i; c->flags = 0; -- 1.7.11.7