mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-31 22:34:33 +01:00
mm/userfaultfd: detect VMA type change after copy retry in mfill_copy_folio_retry()
mfill_copy_folio_retry() drops mmap_lock for the copy_from_user() call.
During this window, the VMA can be replaced with a different type (e.g.
hugetlb), making the caller's ops pointer stale. Subsequent use of the
stale ops would dispatch into the wrong per-vma handlers.
Capture the VMA's ops via vma_uffd_ops() before dropping the lock and
compare against the current vma_uffd_ops() after re-acquiring it.
Return -EAGAIN if they differ so the operation can be retried. This
avoids comparing against the caller's ops which may have been
overridden to anon_uffd_ops for MAP_PRIVATE file-backed mappings.
Link: https://lore.kernel.org/[email protected]
Fixes: 6ab703034f ("userfaultfd: mfill_atomic(): remove retry logic")
Reported-by: Usama Arif <[email protected]>
Closes: https://lore.kernel.org/all/[email protected]/
Signed-off-by: David Carlier <[email protected]>
Acked-by: Mike Rapoport (Microsoft) <[email protected]>
Cc: Jann Horn <[email protected]>
Cc: Liam Howlett <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: Peter Xu <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
This commit is contained in:
1 parent
ba13b28dec
commit
292411fda2
1 file changed
+11
-1
+11
-1
@@ -443,8 +443,10 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio)
|
||||
static int mfill_copy_folio_retry(struct mfill_state *state,
|
||||
struct folio *folio)
|
||||
{
|
||||
const struct vm_uffd_ops *orig_ops = vma_uffd_ops(state->vma);
|
||||
unsigned long src_addr = state->src_addr;
|
||||
void *kaddr;
|
||||
int err;
|
||||
@@ -465,6 +467,14 @@ static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* The VMA type may have changed while the lock was dropped
|
||||
* (e.g. replaced with a hugetlb mapping), making the caller's
|
||||
* ops pointer stale.
|
||||
*/
|
||||
if (vma_uffd_ops(state->vma) != orig_ops)
|
||||
return -EAGAIN;
|
||||
|
||||
err = mfill_establish_pmd(state);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
Reference in new issue
Block a user