题目类似实现了一个共享页面管理器,在简单逆向后可以发现,题目的d3kshrm_vm_ops回调仅实现了d3kshrm_vm_close与d3kshrm_vm_fault,而并未实现vm_open的相关操作。
在d3kshrm_vm_close中,销毁一个vma会对total_ref进行—操作,由于题目并未实现vma_open,我们实际可以通过mremap与munmap提前多次触发d3kshrm_vm_close,在仍有vma对kshrm_slot有索引的情况下提前满足release条件,达成vma对kshrm_slot的uaf。


但此时kshrm_slot->pages已被释放,在kmalloc-192中难以找到可以堆喷类似page** 的结构体,继续分析逻辑可以找到fault与free逻辑中存在race。
d3kshrm_vm_fault操作逻辑中只持slot锁

而ioctl中release逻辑在完全free pages之前就释放了slot锁

从而我们可以想到以下利用方式
1.再次申请slot,populate此时vma索引的slot,page的ref为1
2.利用free_pages到cache_free之间的time window,此时page已被释放回buddy system,但是并未被pages数组clear,slot此时也能访问到pages数组,从而可以fault一个位于free area的页,拿到page-uaf
| thread1 | therad2 |
|---|---|
| free_page | |
| fault | |
| free_pages |
笔者在成功fault一个位于free area的页后,在赛中并未成功通过堆喷重新将该页申请出来,后续赛中利用使用了漏洞2
注意到d3kshrm_vm_fault逻辑实际存在一个off_by_one,允许我们越界fault一个页。
虽然在d3kshrm_mmap的处理逻辑中限制了映射长度,但我们可以通过mremap bypass 限制。
