2019-08-23 23:39:19

by Ralph Campbell

[permalink] [raw]
Subject: [PATCH 1/2] mm/hmm: hmm_range_fault() NULL pointer bug

Although hmm_range_fault() calls find_vma() to make sure that a vma exists
before calling walk_page_range(), hmm_vma_walk_hole() can still be called
with walk->vma == NULL if the start and end address are not contained
within the vma range.

hmm_range_fault() /* calls find_vma() but no range check */
walk_page_range() /* calls find_vma(), sets walk->vma = NULL */
__walk_page_range()
walk_pgd_range()
walk_p4d_range()
walk_pud_range()
hmm_vma_walk_hole()
hmm_vma_walk_hole_()
hmm_vma_do_fault()
handle_mm_fault(vma=0)

Signed-off-by: Ralph Campbell <[email protected]>
---
mm/hmm.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/mm/hmm.c b/mm/hmm.c
index fc05c8fe78b4..29371485fe94 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -229,6 +229,9 @@ static int hmm_vma_do_fault(struct mm_walk *walk, unsigned long addr,
struct vm_area_struct *vma = walk->vma;
vm_fault_t ret;

+ if (!vma)
+ goto err;
+
if (hmm_vma_walk->flags & HMM_FAULT_ALLOW_RETRY)
flags |= FAULT_FLAG_ALLOW_RETRY;
if (write_fault)
@@ -239,12 +242,14 @@ static int hmm_vma_do_fault(struct mm_walk *walk, unsigned long addr,
/* Note, handle_mm_fault did up_read(&mm->mmap_sem)) */
return -EAGAIN;
}
- if (ret & VM_FAULT_ERROR) {
- *pfn = range->values[HMM_PFN_ERROR];
- return -EFAULT;
- }
+ if (ret & VM_FAULT_ERROR)
+ goto err;

return -EBUSY;
+
+err:
+ *pfn = range->values[HMM_PFN_ERROR];
+ return -EFAULT;
}

static int hmm_pfns_bad(unsigned long addr,
--
2.20.1


2019-08-24 22:39:36

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH 1/2] mm/hmm: hmm_range_fault() NULL pointer bug

On Fri, Aug 23, 2019 at 03:17:52PM -0700, Ralph Campbell wrote:
> Although hmm_range_fault() calls find_vma() to make sure that a vma exists
> before calling walk_page_range(), hmm_vma_walk_hole() can still be called
> with walk->vma == NULL if the start and end address are not contained
> within the vma range.

Should we convert to walk_vma_range instead? Or keep walk_page_range
but drop searching the vma ourselves?

Except for that the patch looks good to me:

Reviewed-by: Christoph Hellwig <[email protected]>

2019-08-26 19:02:11

by Jason Gunthorpe

[permalink] [raw]
Subject: Re: [PATCH 1/2] mm/hmm: hmm_range_fault() NULL pointer bug

On Mon, Aug 26, 2019 at 11:02:12AM -0700, Ralph Campbell wrote:
>
> On 8/24/19 3:37 PM, Christoph Hellwig wrote:
> > On Fri, Aug 23, 2019 at 03:17:52PM -0700, Ralph Campbell wrote:
> > > Although hmm_range_fault() calls find_vma() to make sure that a vma exists
> > > before calling walk_page_range(), hmm_vma_walk_hole() can still be called
> > > with walk->vma == NULL if the start and end address are not contained
> > > within the vma range.
> >
> > Should we convert to walk_vma_range instead? Or keep walk_page_range
> > but drop searching the vma ourselves?
> >
> > Except for that the patch looks good to me:
> >
> > Reviewed-by: Christoph Hellwig <[email protected]>
> >
>
> I think keeping the call to walk_page_range() makes sense.
> Jason is hoping to be able to snapshot a range with & without vmas
> and have the pfns[] filled with empty/valid entries as appropriate.
>
> I plan to repost my patch changing hmm_range_fault() to use
> walk.test_walk which will remove the call to find_vma().
> Jason had some concerns about testing it so that's why I have
> been working on some HMM self tests before resending it.

I'm really excited to see tests for hmm_range_fault()!

Did you find this bug with the tests??

Jason

2019-08-26 19:04:37

by Ralph Campbell

[permalink] [raw]
Subject: Re: [PATCH 1/2] mm/hmm: hmm_range_fault() NULL pointer bug


On 8/26/19 11:09 AM, Jason Gunthorpe wrote:
> On Mon, Aug 26, 2019 at 11:02:12AM -0700, Ralph Campbell wrote:
>>
>> On 8/24/19 3:37 PM, Christoph Hellwig wrote:
>>> On Fri, Aug 23, 2019 at 03:17:52PM -0700, Ralph Campbell wrote:
>>>> Although hmm_range_fault() calls find_vma() to make sure that a vma exists
>>>> before calling walk_page_range(), hmm_vma_walk_hole() can still be called
>>>> with walk->vma == NULL if the start and end address are not contained
>>>> within the vma range.
>>>
>>> Should we convert to walk_vma_range instead? Or keep walk_page_range
>>> but drop searching the vma ourselves?
>>>
>>> Except for that the patch looks good to me:
>>>
>>> Reviewed-by: Christoph Hellwig <[email protected]>
>>>
>>
>> I think keeping the call to walk_page_range() makes sense.
>> Jason is hoping to be able to snapshot a range with & without vmas
>> and have the pfns[] filled with empty/valid entries as appropriate.
>>
>> I plan to repost my patch changing hmm_range_fault() to use
>> walk.test_walk which will remove the call to find_vma().
>> Jason had some concerns about testing it so that's why I have
>> been working on some HMM self tests before resending it.
>
> I'm really excited to see tests for hmm_range_fault()!
>
> Did you find this bug with the tests??
>
> Jason
>

Yes, I found both bugs with the tests.
I started with Jerome's hmm_dummy driver and user level test code.
Hopefully I can send it out this week.

2019-08-26 20:02:57

by Ralph Campbell

[permalink] [raw]
Subject: Re: [PATCH 1/2] mm/hmm: hmm_range_fault() NULL pointer bug


On 8/24/19 3:37 PM, Christoph Hellwig wrote:
> On Fri, Aug 23, 2019 at 03:17:52PM -0700, Ralph Campbell wrote:
>> Although hmm_range_fault() calls find_vma() to make sure that a vma exists
>> before calling walk_page_range(), hmm_vma_walk_hole() can still be called
>> with walk->vma == NULL if the start and end address are not contained
>> within the vma range.
>
> Should we convert to walk_vma_range instead? Or keep walk_page_range
> but drop searching the vma ourselves?
>
> Except for that the patch looks good to me:
>
> Reviewed-by: Christoph Hellwig <[email protected]>
>

I think keeping the call to walk_page_range() makes sense.
Jason is hoping to be able to snapshot a range with & without vmas
and have the pfns[] filled with empty/valid entries as appropriate.

I plan to repost my patch changing hmm_range_fault() to use
walk.test_walk which will remove the call to find_vma().
Jason had some concerns about testing it so that's why I have
been working on some HMM self tests before resending it.