Re: CVE-2021-4095: kernel: KVM: NULL pointer dereference in kvm_dirty_ring_get() in virt/kvm/dirty_ring.c

Related Vulnerabilities: CVE-2021-4095  
                							

                <!--X-Body-Begin-->
<!--X-User-Header-->

oss-sec
mailing list archives
<!--X-User-Header-End-->
<!--X-TopPNI-->

By Date

By Thread

</form>

<!--X-TopPNI-End-->
<!--X-MsgBody-->
<!--X-Subject-Header-Begin-->
Re: CVE-2021-4095: kernel: KVM: NULL pointer dereference in kvm_dirty_ring_get() in virt/kvm/dirty_ring.c

<!--X-Subject-Header-End-->
<!--X-Head-of-Message-->

From: butt3rflyh4ck &lt;butterflyhuangxx () gmail com&gt;

Date: Mon, 17 Jan 2022 12:33:54 +0800

<!--X-Head-of-Message-End-->
<!--X-Head-Body-Sep-Begin-->

<!--X-Head-Body-Sep-End-->
<!--X-Body-of-Message-->
The patch for this issue is available upstream now.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=55749769fe608fa3f4a075e42e89d237c8e37637

Regards,
 butt3rflyh4ck.

On Tue, Dec 14, 2021 at 11:26 PM butt3rflyh4ck
&lt;butterflyhuangxx () gmail com&gt; wrote:

Hi, there was a null-ptr-deref bug in kvm_dirty_ring_get in
virt/kvm/dirty_ring.c and I reproduced it on 5.15.0-rc5+.

#Root Cause
When dirty ring logging is enabled, any dirty logging without an active
vCPU context will cause a kernel oops via a KVM KVM_XEN_HVM_SET_ATTR ioctl.

we can call KVM_XEN_HVM_SET_ATTR ioctl and it would invoke
kvm_xen_hvm_set_attr(), it would call mark_page_dirty_in_slot().
Call chains is like this:
KVM_XEN_HVM_SET_ATTR ioctl
  ---&gt;kvm_xen_hvm_set_attr
      ---&gt;kvm_write_wall_clock
         ---&gt;kvm_write_guest
            --&gt;__kvm_write_guest_page
               ---&gt;mark_page_dirty_in_slot
mark_page_dirty_in_slot().
if kvm-&gt;dirty_ring_size is sat.
```
void mark_page_dirty_in_slot(struct kvm *kvm,
     struct kvm_memory_slot *memslot,
     gfn_t gfn)
{
if (memslot &amp;&amp; kvm_slot_dirty_track_enabled(memslot)) {
unsigned long rel_gfn = gfn - memslot-&gt;base_gfn;
u32 slot = (memslot-&gt;as_id &lt;&lt; 16) | memslot-&gt;id;

if (kvm-&gt;dirty_ring_size)
kvm_dirty_ring_push(kvm_dirty_ring_get(kvm),
    slot, rel_gfn);
else
set_bit_le(rel_gfn, memslot-&gt;dirty_bitmap);
}
}
```
mark_page_dirty_in_slot() would call kvm_dirty_ring_push() to push a
dirty-page to dirty ring
then kvm_dirty_ring_get() would get vcpu-&gt;dirty_ring.

kvm_dirty_ring_get()
```
struct kvm_dirty_ring *kvm_dirty_ring_get(struct kvm *kvm)
{
struct kvm_vcpu *vcpu = kvm_get_running_vcpu();  //-------&gt; invoke
kvm_get_running_vcpu() to get a vcpu.

WARN_ON_ONCE(vcpu-&gt;kvm != kvm); [1]

return &amp;vcpu-&gt;dirty_ring;
}
```
If vCPU stat did not work, kvm_get_running_vcpu() would get a NULL
vcpu pointer .

#Details
Analyze and some discussion on this issue.
https://lore.kernel.org/kvm/CAFcO6XOmoS7EacN_n6v4Txk7xL7iqRa2gABg3F7E3Naf5uG94g () mail gmail com/

#Fix
The patch for this issue, not available upstream now.
https://patchwork.kernel.org/project/kvm/patch/20211121125451.9489-12-dwmw2 () infradead org/

#CVE
Red Hat has assigned CVE-2021-4095 to this issue.
https://access.redhat.com/security/cve/CVE-2021-4095
https://bugzilla.redhat.com/show_bug.cgi?id=2031194

#Cedit
Active Defense Lab of Venustech.

Regards,
 butt3rflyh4ck.
--
Active Defense Lab of Venustech

-- 
Active Defense Lab of Venustech

<!--X-Body-of-Message-End-->
<!--X-MsgBody-End-->
<!--X-Follow-Ups-->

<!--X-Follow-Ups-End-->
<!--X-References-->
<!--X-References-End-->
<!--X-BotPNI-->

By Date

By Thread

Current thread:

Re: CVE-2021-4095: kernel: KVM: NULL pointer dereference in kvm_dirty_ring_get() in virt/kvm/dirty_ring.c butt3rflyh4ck (Jan 16)

<!--X-BotPNI-End-->
<!--X-User-Footer-->
<!--X-User-Footer-End-->