Commit e39d200f authored by Wanpeng Li's avatar Wanpeng Li Committed by Paolo Bonzini

KVM: Fix stack-out-of-bounds read in write_mmio

Reported by syzkaller:

  BUG: KASAN: stack-out-of-bounds in write_mmio+0x11e/0x270 [kvm]
  Read of size 8 at addr ffff8803259df7f8 by task syz-executor/32298

  CPU: 6 PID: 32298 Comm: syz-executor Tainted: G           OE    4.15.0-rc2+ #18
  Hardware name: LENOVO ThinkCentre M8500t-N000/SHARKBAY, BIOS FBKTC1AUS 02/16/2016
  Call Trace:
   dump_stack+0xab/0xe1
   print_address_description+0x6b/0x290
   kasan_report+0x28a/0x370
   write_mmio+0x11e/0x270 [kvm]
   emulator_read_write_onepage+0x311/0x600 [kvm]
   emulator_read_write+0xef/0x240 [kvm]
   emulator_fix_hypercall+0x105/0x150 [kvm]
   em_hypercall+0x2b/0x80 [kvm]
   x86_emulate_insn+0x2b1/0x1640 [kvm]
   x86_emulate_instruction+0x39a/0xb90 [kvm]
   handle_exception+0x1b4/0x4d0 [kvm_intel]
   vcpu_enter_guest+0x15a0/0x2640 [kvm]
   kvm_arch_vcpu_ioctl_run+0x549/0x7d0 [kvm]
   kvm_vcpu_ioctl+0x479/0x880 [kvm]
   do_vfs_ioctl+0x142/0x9a0
   SyS_ioctl+0x74/0x80
   entry_SYSCALL_64_fastpath+0x23/0x9a

The path of patched vmmcall will patch 3 bytes opcode 0F 01 C1(vmcall)
to the guest memory, however, write_mmio tracepoint always prints 8 bytes
through *(u64 *)val since kvm splits the mmio access into 8 bytes. This
leaks 5 bytes from the kernel stack (CVE-2017-17741).  This patch fixes
it by just accessing the bytes which we operate on.

Before patch:

syz-executor-5567  [007] .... 51370.561696: kvm_mmio: mmio write len 3 gpa 0x10 val 0x1ffff10077c1010f

After patch:

syz-executor-13416 [002] .... 51302.299573: kvm_mmio: mmio write len 3 gpa 0x10 val 0xc1010f
Reported-by: default avatarDmitry Vyukov <dvyukov@google.com>
Reviewed-by: default avatarDarren Kenny <darren.kenny@oracle.com>
Reviewed-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Tested-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: default avatarWanpeng Li <wanpeng.li@hotmail.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent f2981033
...@@ -4384,7 +4384,7 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v) ...@@ -4384,7 +4384,7 @@ static int vcpu_mmio_read(struct kvm_vcpu *vcpu, gpa_t addr, int len, void *v)
addr, n, v)) addr, n, v))
&& kvm_io_bus_read(vcpu, KVM_MMIO_BUS, addr, n, v)) && kvm_io_bus_read(vcpu, KVM_MMIO_BUS, addr, n, v))
break; break;
trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, *(u64 *)v); trace_kvm_mmio(KVM_TRACE_MMIO_READ, n, addr, v);
handled += n; handled += n;
addr += n; addr += n;
len -= n; len -= n;
...@@ -4643,7 +4643,7 @@ static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes) ...@@ -4643,7 +4643,7 @@ static int read_prepare(struct kvm_vcpu *vcpu, void *val, int bytes)
{ {
if (vcpu->mmio_read_completed) { if (vcpu->mmio_read_completed) {
trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes, trace_kvm_mmio(KVM_TRACE_MMIO_READ, bytes,
vcpu->mmio_fragments[0].gpa, *(u64 *)val); vcpu->mmio_fragments[0].gpa, val);
vcpu->mmio_read_completed = 0; vcpu->mmio_read_completed = 0;
return 1; return 1;
} }
...@@ -4665,14 +4665,14 @@ static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa, ...@@ -4665,14 +4665,14 @@ static int write_emulate(struct kvm_vcpu *vcpu, gpa_t gpa,
static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val) static int write_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, int bytes, void *val)
{ {
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, *(u64 *)val); trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, bytes, gpa, val);
return vcpu_mmio_write(vcpu, gpa, bytes, val); return vcpu_mmio_write(vcpu, gpa, bytes, val);
} }
static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa, static int read_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
void *val, int bytes) void *val, int bytes)
{ {
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, 0); trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, bytes, gpa, NULL);
return X86EMUL_IO_NEEDED; return X86EMUL_IO_NEEDED;
} }
......
...@@ -211,7 +211,7 @@ TRACE_EVENT(kvm_ack_irq, ...@@ -211,7 +211,7 @@ TRACE_EVENT(kvm_ack_irq,
{ KVM_TRACE_MMIO_WRITE, "write" } { KVM_TRACE_MMIO_WRITE, "write" }
TRACE_EVENT(kvm_mmio, TRACE_EVENT(kvm_mmio,
TP_PROTO(int type, int len, u64 gpa, u64 val), TP_PROTO(int type, int len, u64 gpa, void *val),
TP_ARGS(type, len, gpa, val), TP_ARGS(type, len, gpa, val),
TP_STRUCT__entry( TP_STRUCT__entry(
...@@ -225,7 +225,10 @@ TRACE_EVENT(kvm_mmio, ...@@ -225,7 +225,10 @@ TRACE_EVENT(kvm_mmio,
__entry->type = type; __entry->type = type;
__entry->len = len; __entry->len = len;
__entry->gpa = gpa; __entry->gpa = gpa;
__entry->val = val; __entry->val = 0;
if (val)
memcpy(&__entry->val, val,
min_t(u32, sizeof(__entry->val), len));
), ),
TP_printk("mmio %s len %u gpa 0x%llx val 0x%llx", TP_printk("mmio %s len %u gpa 0x%llx val 0x%llx",
......
...@@ -112,7 +112,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) ...@@ -112,7 +112,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
} }
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr, trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
data); &data);
data = vcpu_data_host_to_guest(vcpu, data, len); data = vcpu_data_host_to_guest(vcpu, data, len);
vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data); vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
} }
...@@ -182,14 +182,14 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run, ...@@ -182,14 +182,14 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt), data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
len); len);
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data); trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, &data);
kvm_mmio_write_buf(data_buf, len, data); kvm_mmio_write_buf(data_buf, len, data);
ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len, ret = kvm_io_bus_write(vcpu, KVM_MMIO_BUS, fault_ipa, len,
data_buf); data_buf);
} else { } else {
trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len, trace_kvm_mmio(KVM_TRACE_MMIO_READ_UNSATISFIED, len,
fault_ipa, 0); fault_ipa, NULL);
ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len, ret = kvm_io_bus_read(vcpu, KVM_MMIO_BUS, fault_ipa, len,
data_buf); data_buf);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment