From 4daa3c254ea757fcbb47fe73164041868b9f7f0f Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Wed, 8 Jun 2022 08:41:36 -0700 Subject: [PATCH] ANDROID: add vma->file_ref_count to synchronize vma->vm_file destruction In order to prevent destruction of vma->vm_file while it's being used during speculative page fault handling, introduce an atomic refcounter. Bug: 234527424 Signed-off-by: Suren Baghdasaryan Change-Id: I0e971156f3e76feb45136bac1582a7eaab8c75df --- include/linux/mm.h | 15 +++++++++++++++ include/linux/mm_types.h | 3 +++ kernel/fork.c | 7 +++++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 9224af942ea2..b036d67ace0f 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -679,6 +679,9 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm) memset(vma, 0, sizeof(*vma)); vma->vm_mm = mm; vma->vm_ops = &dummy_vm_ops; +#ifdef CONFIG_SPECULATIVE_PAGE_FAULT + atomic_set(&vma->file_ref_count, 1); +#endif INIT_LIST_HEAD(&vma->anon_vma_chain); } @@ -3377,6 +3380,18 @@ static inline bool pte_spinlock(struct vm_fault *vmf) return __pte_map_lock(vmf); } +static inline bool vma_get_file_ref(struct vm_area_struct *vma) +{ + return atomic_inc_not_zero(&vma->file_ref_count); +} + +extern void fput(struct file *); +static inline void vma_put_file_ref(struct vm_area_struct *vma) +{ + if (vma && atomic_dec_and_test(&vma->file_ref_count)) + fput(vma->vm_file); +} + #else /* !CONFIG_SPECULATIVE_PAGE_FAULT */ #define pte_map_lock(___vmf) \ diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 07f25e502078..98fd18dcfb59 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -417,6 +417,9 @@ struct vm_area_struct { struct mempolicy *vm_policy; /* NUMA policy for the VMA */ #endif struct vm_userfaultfd_ctx vm_userfaultfd_ctx; +#ifdef CONFIG_SPECULATIVE_PAGE_FAULT + atomic_t file_ref_count; +#endif } __randomize_layout; struct core_thread { diff --git a/kernel/fork.c b/kernel/fork.c index 014a813f221b..3ac5b59ead7f 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -383,8 +383,6 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig) static inline void ____vm_area_free(struct vm_area_struct *vma) { - if (vma->vm_file) - fput(vma->vm_file); kmem_cache_free(vm_area_cachep, vma); } @@ -402,10 +400,15 @@ void vm_area_free(struct vm_area_struct *vma) free_anon_vma_name(vma); #ifdef CONFIG_SPECULATIVE_PAGE_FAULT if (atomic_read(&vma->vm_mm->mm_users) > 1) { + if (vma->vm_file) + vma_put_file_ref(vma); + call_rcu(&vma->vm_rcu, __vm_area_free); return; } #endif + if (vma->vm_file) + fput(vma->vm_file); ____vm_area_free(vma); }