• huangjie.albert's avatar
    virtio_ring : keep used_wrap_counter in vq->last_used_idx · a7722890
    huangjie.albert authored
    the used_wrap_counter and the vq->last_used_idx may get
    out of sync if they are separate assignment,and interrupt
    might use an incorrect value to check for the used index.
    
    for example:OOB access
    ksoftirqd may consume the packet and it will call:
    virtnet_poll
    	-->virtnet_receive
    		-->virtqueue_get_buf_ctx
    			-->virtqueue_get_buf_ctx_packed
    and in virtqueue_get_buf_ctx_packed:
    
    vq->last_used_idx += vq->packed.desc_state[id].num;
    if (unlikely(vq->last_used_idx >= vq->packed.vring.num)) {
             vq->last_used_idx -= vq->packed.vring.num;
             vq->packed.used_wrap_counter ^= 1;
    }
    
    if at the same time, there comes a vring interrupt,in vring_interrupt:
    we will call:
    vring_interrupt
    	-->more_used
    		-->more_used_packed
    			-->is_used_desc_packed
    in is_used_desc_packed, the last_used_idx maybe >= vq->packed.vring.num.
    so this could case a memory out of bounds bug.
    
    this patch is to keep the used_wrap_counter in vq->last_used_idx
    so we can get the correct value to check for used index in interrupt.
    
    v3->v4:
    - use READ_ONCE/WRITE_ONCE to get/set vq->last_used_idx
    
    v2->v3:
    - add inline function to get used_wrap_counter and last_used
    - when use vq->last_used_idx, only read once
      if vq->last_used_idx is read twice, the values can be inconsistent.
    - use last_used_idx & ~(-(1 << VRING_PACKED_EVENT_F_WRAP_CTR))
      to get the all bits below VRING_PACKED_EVENT_F_WRAP_CTR
    
    v1->v2:
    - reuse the VRING_PACKED_EVENT_F_WRAP_CTR
    - Remove parameter judgment in is_used_desc_packed,
    because it can't be illegal
    Signed-off-by: default avatarhuangjie.albert <huangjie.albert@bytedance.com>
    Message-Id: <20220617020411.80367-1-huangjie.albert@bytedance.com>
    Signed-off-by: default avatarMichael S. Tsirkin <mst@redhat.com>
    a7722890
virtio_ring.c 64.3 KB