ANDROID: KVM: arm64: Fix UAF in pkvm_unmap_range
pkvm_unmap_range uses for_ppage_node_in_range to iterate over pinned
pages, then it erases the pin page with rb_erase.
However, for_ppage_node_in_range will use this pointer to get the
next node after the current node was freed.
This makes kfence screams on pVM teardown:
[ 123.716319][ T192] BUG: KFENCE: use-after-free read in rb_next+0x0/0x50
[ 123.716319][ T192]
[ 123.717897][ T192] Use-after-free read at 0x00000000aa928570 (in kfence-#52):
[ 123.718885][ T192] rb_next+0x0/0x50
[ 123.719585][ T192] kvm_arch_flush_shadow_all+0x44/0x60
[ 123.720428][ T192] kvm_mmu_notifier_release+0x34/0x70
[ 123.721333][ T192] __mmu_notifier_release+0x80/0x1ec
[ 123.722219][ T192] exit_mmap+0x39c/0x3c0
[ 123.722978][ T192] __mmput+0x34/0x17c
[ 123.723693][ T192] mmput+0x54/0x64
[ 123.724328][ T192] do_exit+0x2c0/0xa54
[ 123.725000][ T192] do_group_exit+0x38/0x94
[ 123.726027][ T192] get_signal+0x9bc/0x9cc
[ 123.726730][ T192] do_notify_resume+0x1c0/0xa00
[ 123.727479][ T192] el0_svc+0x11c/0x120
[ 123.728141][ T192] el0t_64_sync_handler+0x128/0x134
[ 123.728898][ T192] el0t_64_sync+0x1a8/0x1ac
[ 123.730018][ T192]
[ 123.730436][ T192] kfence-#52: 0x00000000aa928570-0x00000000aedc398c, size=40, cache=kmalloc-cg-64
[ 123.730436][ T192]
[ 123.731795][ T192] allocated by task 202 on cpu 0 at 51.087078s:
[ 123.732971][ T192] __kmem_cache_alloc_node+0x1f0/0x2bc
[ 123.734008][ T192] kmalloc_trace+0x44/0x138
[ 123.734695][ T192] kvm_handle_guest_abort+0x3fc/0x106c
[ 123.735484][ T192] handle_exit+0xa8/0x2c4
[ 123.736158][ T192] kvm_arch_vcpu_ioctl_run+0x204/0x8c8
[ 123.736934][ T192] kvm_vcpu_ioctl+0x1c4/0x760
[ 123.737989][ T192] __arm64_sys_ioctl+0xb4/0xfc
[ 123.738705][ T192] invoke_syscall+0x4c/0x11c
[ 123.739409][ T192] el0_svc_common.constprop.0+0x44/0xec
[ 123.740189][ T192] do_el0_svc+0x20/0x30
[ 123.740843][ T192] el0_svc+0x44/0x120
[ 123.741726][ T192] el0t_64_sync_handler+0x128/0x134
[ 123.742479][ T192] el0t_64_sync+0x1a8/0x1ac
[ 123.743174][ T192]
[ 123.743609][ T192] freed by task 192 on cpu 3 at 123.714463s:
[ 123.744558][ T192] __unmap_stage2_range.isra.0+0x1b0/0x1ec
[ 123.745736][ T192] kvm_arch_flush_shadow_all+0x44/0x60
[ 123.746520][ T192] kvm_mmu_notifier_release+0x34/0x70
[ 123.747303][ T192] __mmu_notifier_release+0x80/0x1ec
[ 123.748068][ T192] exit_mmap+0x39c/0x3c0
[ 123.748727][ T192] __mmput+0x34/0x17c
[ 123.749637][ T192] mmput+0x54/0x64
[ 123.750246][ T192] do_exit+0x2c0/0xa54
[ 123.750887][ T192] do_group_exit+0x38/0x94
[ 123.751572][ T192] get_signal+0x9bc/0x9cc
[ 123.752233][ T192] do_notify_resume+0x1c0/0xa00
[ 123.752946][ T192] el0_svc+0x11c/0x120
[ 123.753852][ T192] el0t_64_sync_handler+0x128/0x134
[ 123.754609][ T192] el0t_64_sync+0x1a8/0x1ac
[ 123.755303][ T192]
[ 123.755717][ T192] CPU: 3 PID: 192 Comm: ioeventfd-worke Tainted: G B 6.6.17mostafa+ #12
[ 123.756957][ T192] Hardware name: linux,dummy-virt (DT)
[ 123.758007][ T192] ==================================================================
To fix that, we use a temp variable to hold the next entry before
getting into the loop.
Bug: 278749606
Change-Id: Ibb7907c3bbe53a4643ad5f945888529938bd063d
Signed-off-by:
Mostafa Saleh <smostafa@google.com>
Loading