Re: [PATCH] ocfs2: fix use-after-free in ocfs2_fault() when VM_FAULT_RETRY
From: Joseph Qi
Date: Tue Mar 31 2026 - 05:59:22 EST
On 3/31/26 2:20 PM, tejas bharambe wrote:
> filemap_fault() may drop the mmap_lock before returning VM_FAULT_RETRY,
> as documented in mm/filemap.c:
>
> "If our return value has VM_FAULT_RETRY set, it's because the mmap_lock
> may be dropped before doing I/O or by lock_folio_maybe_drop_mmap()."
>
> When this happens, a concurrent munmap() can call remove_vma() and free
> the vm_area_struct via RCU. The saved 'vma' pointer in ocfs2_fault() then
> becomes a dangling pointer, and the subsequent trace_ocfs2_fault() call
> dereferences it -- a use-after-free.
>
> Fix this by returning early when VM_FAULT_RETRY is set, skipping the
> trace that dereferences the potentially freed vma.
>
> Reported-by: syzbot+a49010a0e8fcdeea075f@xxxxxxxxxxxxxxxxxxxxxxxxx
> Closes: https://syzkaller.appspot.com/bug?extid=a49010a0e8fcdeea075f
> Signed-off-by: Tejas Bharambe <tejas.bharambe@xxxxxxxxxxx>
> ---
> fs/ocfs2/mmap.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c
> index 50e2faf64c..adf6423ae9 100644
> --- a/fs/ocfs2/mmap.c
> +++ b/fs/ocfs2/mmap.c
> @@ -38,6 +38,14 @@ static vm_fault_t ocfs2_fault(struct vm_fault *vmf)
> ret = filemap_fault(vmf);
> ocfs2_unblock_signals(&oldset);
>
> + /*
> + * filemap_fault() may drop the mmap_lock and return VM_FAULT_RETRY.
> + * In that case the vma may have been freed by a concurrent munmap(),
> + * so we must not dereference it.
> + */
> + if (ret & VM_FAULT_RETRY)
> + return ret;
> +
How about change it like this:
Remove vma from ocfs2_fault trace event. Then
struct inode *inode = file_inode(vmf->vma->vm_file);
...
ret = filemap_fault(vmf);
...
trace_ocfs2_fault(OCFS2_I(inode)->ip_blkno, vmf->page, vmf->pgoff);
This can keep trace event in all cases.
Thanks,
Joseph
> trace_ocfs2_fault(OCFS2_I(vma->vm_file->f_mapping->host)->ip_blkno,
> vma, vmf->page, vmf->pgoff);
> return ret;