On Thu, Sep 07, 2023 at 08:53:14AM +0200, Vlastimil Babka wrote:
Hi,
On 9/4/23 20:08, Joel Fernandes (Google) wrote:
It is unsafe to dump vmalloc area information when trying to do so from some contexts. Add a safer trylock version of the same function to do a best-effort VMA finding and use it from vmalloc_dump_obj().
I was a bit confused by the subject which suggests a new function is added, but it seems open-coded in its only caller. I assume it's due to evolution of the series. Something like:
mm/vmalloc: use trylock for vmap_area_lock in vmalloc_dump_obj()
?
I also notice it's trying hard to copy everything from "vm" to temporary variables before unlocking, presumably to prevent use-after-free, so should that be also mentioned in the changelog?
Apologies for the less-than-ideal changelog. Andrew would you mind replacing the merged patch with the below one instead? It just contains non-functional changes to change log and an additional code comment/print. Thanks!
---8<-----------------------
From: "Joel Fernandes (Google)" joel@joelfernandes.org Subject: [PATCH v3.1] mm/vmalloc: Add a safer inlined version of find_vm_area() for debug
It is unsafe to dump vmalloc area information when trying to do so from some contexts such as PREEMPT_RT or from an IRQ handler that interrupted a vmap_area_lock-held region. Add a safer and inlined trylock version of find_vm_area() to do a best-effort VMA finding and use it from vmalloc_dump_obj().
While the vmap_area_lock is held, copy interesting attributes from the vm_struct before unlocking.
[applied test robot feedback on unused function fix.] [applied Uladzislau feedback on locking.] [applied Vlastimil and Lorenzo feedback on changelog, comment and print improvements]
Reported-by: Zhen Lei thunder.leizhen@huaweicloud.com Cc: Paul E. McKenney paulmck@kernel.org Cc: rcu@vger.kernel.org Cc: Zqiang qiang.zhang1211@gmail.com Reviewed-by: Uladzislau Rezki (Sony) urezki@gmail.com Fixes: 98f180837a89 ("mm: Make mem_dump_obj() handle vmalloc() memory") Cc: stable@vger.kernel.org Signed-off-by: Joel Fernandes (Google) joel@joelfernandes.org --- mm/vmalloc.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 93cf99aba335..990a0d5efba8 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -4274,14 +4274,40 @@ void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms) #ifdef CONFIG_PRINTK bool vmalloc_dump_obj(void *object) { - struct vm_struct *vm; void *objp = (void *)PAGE_ALIGN((unsigned long)object); + const void *caller; + struct vm_struct *vm; + struct vmap_area *va; + unsigned long addr; + unsigned int nr_pages; + + /* + * Use trylock as we don't want to contend since this is debug code and + * we might run this code in contexts like PREEMPT_RT where spinlock + * contention may result in sleeping, or from an IRQ handler which + * might interrupt a vmap_area_lock-held critical section. + */ + if (!spin_trylock(&vmap_area_lock)) { + pr_cont(" [couldn't acquire vmap_area_lock]\n"); + return false; + } + va = __find_vmap_area((unsigned long)objp, &vmap_area_root); + if (!va) { + spin_unlock(&vmap_area_lock); + return false; + }
- vm = find_vm_area(objp); - if (!vm) + vm = va->vm; + if (!vm) { + spin_unlock(&vmap_area_lock); return false; + } + addr = (unsigned long)vm->addr; + caller = vm->caller; + nr_pages = vm->nr_pages; + spin_unlock(&vmap_area_lock); pr_cont(" %u-page vmalloc region starting at %#lx allocated at %pS\n", - vm->nr_pages, (unsigned long)vm->addr, vm->caller); + nr_pages, addr, caller); return true; } #endif