lkml.org 
[lkml]   [2019]   [Sep]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 09/59] KVM: coalesced_mmio: add bounds checking
    Date
    From: Matt Delco <delco@chromium.org>

    commit b60fe990c6b07ef6d4df67bc0530c7c90a62623a upstream.

    The first/last indexes are typically shared with a user app.
    The app can change the 'last' index that the kernel uses
    to store the next result. This change sanity checks the index
    before using it for writing to a potentially arbitrary address.

    This fixes CVE-2019-14821.

    Cc: stable@vger.kernel.org
    Fixes: 5f94c1741bdc ("KVM: Add coalesced MMIO support (common part)")
    Signed-off-by: Matt Delco <delco@chromium.org>
    Signed-off-by: Jim Mattson <jmattson@google.com>
    Reported-by: syzbot+983c866c3dd6efa3662a@syzkaller.appspotmail.com
    [Use READ_ONCE. - Paolo]
    Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    virt/kvm/coalesced_mmio.c | 17 ++++++++++-------
    1 file changed, 10 insertions(+), 7 deletions(-)

    --- a/virt/kvm/coalesced_mmio.c
    +++ b/virt/kvm/coalesced_mmio.c
    @@ -40,7 +40,7 @@ static int coalesced_mmio_in_range(struc
    return 1;
    }

    -static int coalesced_mmio_has_room(struct kvm_coalesced_mmio_dev *dev)
    +static int coalesced_mmio_has_room(struct kvm_coalesced_mmio_dev *dev, u32 last)
    {
    struct kvm_coalesced_mmio_ring *ring;
    unsigned avail;
    @@ -52,7 +52,7 @@ static int coalesced_mmio_has_room(struc
    * there is always one unused entry in the buffer
    */
    ring = dev->kvm->coalesced_mmio_ring;
    - avail = (ring->first - ring->last - 1) % KVM_COALESCED_MMIO_MAX;
    + avail = (ring->first - last - 1) % KVM_COALESCED_MMIO_MAX;
    if (avail == 0) {
    /* full */
    return 0;
    @@ -67,24 +67,27 @@ static int coalesced_mmio_write(struct k
    {
    struct kvm_coalesced_mmio_dev *dev = to_mmio(this);
    struct kvm_coalesced_mmio_ring *ring = dev->kvm->coalesced_mmio_ring;
    + __u32 insert;

    if (!coalesced_mmio_in_range(dev, addr, len))
    return -EOPNOTSUPP;

    spin_lock(&dev->kvm->ring_lock);

    - if (!coalesced_mmio_has_room(dev)) {
    + insert = READ_ONCE(ring->last);
    + if (!coalesced_mmio_has_room(dev, insert) ||
    + insert >= KVM_COALESCED_MMIO_MAX) {
    spin_unlock(&dev->kvm->ring_lock);
    return -EOPNOTSUPP;
    }

    /* copy data in first free entry of the ring */

    - ring->coalesced_mmio[ring->last].phys_addr = addr;
    - ring->coalesced_mmio[ring->last].len = len;
    - memcpy(ring->coalesced_mmio[ring->last].data, val, len);
    + ring->coalesced_mmio[insert].phys_addr = addr;
    + ring->coalesced_mmio[insert].len = len;
    + memcpy(ring->coalesced_mmio[insert].data, val, len);
    smp_wmb();
    - ring->last = (ring->last + 1) % KVM_COALESCED_MMIO_MAX;
    + ring->last = (insert + 1) % KVM_COALESCED_MMIO_MAX;
    spin_unlock(&dev->kvm->ring_lock);
    return 0;
    }

    \
     
     \ /
      Last update: 2019-09-20 00:20    [W:4.185 / U:0.068 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site