linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Suren Baghdasaryan <surenb@google.com>
To: Lokesh Gidra <lokeshgidra@google.com>
Cc: Hillf Danton <hdanton@sina.com>,
	akpm@linux-foundation.org, peterx@redhat.com,
	 linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	 syzkaller-bugs@googlegroups.com,
	 syzbot <syzbot+b446dbe27035ef6bd6c2@syzkaller.appspotmail.com>,
	 stable@vger.kernel.org
Subject: Re: [PATCH 1/1] userfaultfd: fix a crash when UFFDIO_MOVE handles a THP hole
Date: Thu, 31 Jul 2025 07:23:54 -0700	[thread overview]
Message-ID: <CAJuCfpGzazWVYzc9XXh+xTP9R7cMffiP2P4G5OJTQ0-Ji4xFEQ@mail.gmail.com> (raw)
In-Reply-To: <CA+EESO4mkiedqVMCV3fEnB-xeBMKyct1_WA=YDFVbqSGU4F+6A@mail.gmail.com>

On Thu, Jul 31, 2025 at 12:35 AM Lokesh Gidra <lokeshgidra@google.com> wrote:
>
> On Wed, Jul 30, 2025 at 6:58 PM Hillf Danton <hdanton@sina.com> wrote:
> >
> > #syz test
> >
> > When UFFDIO_MOVE is used with UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES and it
> > encounters a non-present THP, it fails to properly recognize an unmapped
> > hole and tries to access a non-existent folio, resulting in
> > a crash. Add a check to skip non-present THPs.
> >
> Thanks Suren for promptly addressing this issue.
>
> > Fixes: adef440691ba ("userfaultfd: UFFDIO_MOVE uABI")
> > Reported-by: syzbot+b446dbe27035ef6bd6c2@syzkaller.appspotmail.com
> > Closes: https://lore.kernel.org/all/68794b5c.a70a0220.693ce.0050.GAE@google.com/
> > Signed-off-by: Suren Baghdasaryan <surenb@google.com>
> > Cc: stable@vger.kernel.org
> > ---
> >  mm/userfaultfd.c | 38 +++++++++++++++++++++++---------------
> >  1 file changed, 23 insertions(+), 15 deletions(-)
> >
> > diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> > index cbed91b09640..60be8080ddd0 100644
> > --- a/mm/userfaultfd.c
> > +++ b/mm/userfaultfd.c
> > @@ -1818,27 +1818,35 @@ ssize_t move_pages(struct userfaultfd_ctx *ctx, unsigned long dst_start,
> >
> >                 ptl = pmd_trans_huge_lock(src_pmd, src_vma);
> >                 if (ptl) {
> > -                       /* Check if we can move the pmd without splitting it. */
> > -                       if (move_splits_huge_pmd(dst_addr, src_addr, src_start + len) ||
> > -                           !pmd_none(dst_pmdval)) {
> > -                               struct folio *folio = pmd_folio(*src_pmd);
> > +                       if (pmd_present(*src_pmd) || is_pmd_migration_entry(*src_pmd)) {
> > +                               /* Check if we can move the pmd without splitting it. */
> > +                               if (move_splits_huge_pmd(dst_addr, src_addr, src_start + len) ||
> > +                                   !pmd_none(dst_pmdval)) {
> > +                                       if (pmd_present(*src_pmd)) {
> > +                                               struct folio *folio = pmd_folio(*src_pmd);
> > +
> > +                                               if (!folio || (!is_huge_zero_folio(folio) &&
> > +                                                              !PageAnonExclusive(&folio->page))) {
> > +                                                       spin_unlock(ptl);
> > +                                                       err = -EBUSY;
> > +                                                       break;
> > +                                               }
> > +                                       }
> >
> > -                               if (!folio || (!is_huge_zero_folio(folio) &&
> > -                                              !PageAnonExclusive(&folio->page))) {
> >                                         spin_unlock(ptl);
> > -                                       err = -EBUSY;
> > -                                       break;
> > +                                       split_huge_pmd(src_vma, src_pmd, src_addr);
> > +                                       /* The folio will be split by move_pages_pte() */
> > +                                       continue;
> >                                 }
> >
> > +                               err = move_pages_huge_pmd(mm, dst_pmd, src_pmd,
> > +                                                         dst_pmdval, dst_vma, src_vma,
> > +                                                         dst_addr, src_addr);
> > +                       } else {
> > +                               /* nothing to do to move a hole */
> >                                 spin_unlock(ptl);
> > -                               split_huge_pmd(src_vma, src_pmd, src_addr);
> > -                               /* The folio will be split by move_pages_pte() */
> > -                               continue;
> > +                               err = 0;
> I think we need to act here depending on whether
> UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES is set or not.

Hmm, yes, I think you are right. I thought we would bail out earlier
if !UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES but I think it's possible to get
here if the PMD was established earlier but then unmapped.

>
>            err = (mode & UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES) ? 0 : -ENOENT;
>
> Also, IMO, the step_size in this case should be the minimum of
> remaining length and HPAGE_PMD_SIZE.

Ah, ok. I think it matters only for incrementing "moved" correctly
because otherwise the functionality is the same.

> >                         }
> > -
> > -                       err = move_pages_huge_pmd(mm, dst_pmd, src_pmd,
> > -                                                 dst_pmdval, dst_vma, src_vma,
> > -                                                 dst_addr, src_addr);
> >                         step_size = HPAGE_PMD_SIZE;
> >                 } else {
> >                         if (pmd_none(*src_pmd)) {
> I have a related question/doubt: why do we populate the page-table
> hierarchy on the src side [1] (and then also at line 1857) when a hole
> is found? IMHO, it shouldn't be needed. Depending on whether
> UFFDIO_MOVE_MODE_ALLOW_SRC_HOLES is set or not, it should either
> return -ENOENT, or continue past the hole. Please correct me if I'm
> wrong.

I thought about that too. I think it's done to simplify the logic.
This way we can treat the cases when PMD was never allocated and when
PMD was allocated, mapped and then unmapped the same way.

>
> [1] https://elixir.bootlin.com/linux/v6.16/source/mm/userfaultfd.c#L1797
>
> >
> > base-commit: 01da54f10fddf3b01c5a3b80f6b16bbad390c302
> > --
> > 2.50.1.552.g942d659e1b-goog


  reply	other threads:[~2025-07-31 14:24 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-30 17:07 Suren Baghdasaryan
2025-07-31  1:52 ` Hillf Danton
2025-07-31  2:56   ` [syzbot] [mm?] BUG: unable to handle kernel paging request in move_pages syzbot
2025-07-31  7:35   ` [PATCH 1/1] userfaultfd: fix a crash when UFFDIO_MOVE handles a THP hole Lokesh Gidra
2025-07-31 14:23     ` Suren Baghdasaryan [this message]
2025-07-31 15:08       ` Lokesh Gidra

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAJuCfpGzazWVYzc9XXh+xTP9R7cMffiP2P4G5OJTQ0-Ji4xFEQ@mail.gmail.com \
    --to=surenb@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=hdanton@sina.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=lokeshgidra@google.com \
    --cc=peterx@redhat.com \
    --cc=stable@vger.kernel.org \
    --cc=syzbot+b446dbe27035ef6bd6c2@syzkaller.appspotmail.com \
    --cc=syzkaller-bugs@googlegroups.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox