Ralph Campbell
2019-Aug-23 22:17 UTC
[Nouveau] [PATCH 0/2] mm/hmm: two bug fixes for hmm_range_fault()
I have been working on converting Jerome's hmm_dummy driver and self tests into a stand-alone set of tests to be included in tools/testing/selftests/vm and came across these two bug fixes in the process. The tests aren't quite ready to be posted as a patch. I'm posting the fixes now since I thought they shouldn't wait. They should probably have a fixes line but with all the HMM changes, I wasn't sure exactly which commit to use. These are based on top of Jason's latest hmm branch. Ralph Campbell (2): mm/hmm: hmm_range_fault() NULL pointer bug mm/hmm: hmm_range_fault() infinite loop mm/hmm.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) -- 2.20.1
Ralph Campbell
2019-Aug-23 22:17 UTC
[Nouveau] [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 <rcampbell at nvidia.com>
---
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
Ralph Campbell
2019-Aug-23 22:17 UTC
[Nouveau] [PATCH 2/2] mm/hmm: hmm_range_fault() infinite loop
Normally, callers to handle_mm_fault() are supposed to check the
vma->vm_flags first. hmm_range_fault() checks for VM_READ but doesn't
check for VM_WRITE if the caller requests a page to be faulted in
with write permission (via the hmm_range.pfns[] value).
If the vma is write protected, this can result in an infinite loop:
hmm_range_fault()
walk_page_range()
...
hmm_vma_walk_hole()
hmm_vma_walk_hole_()
hmm_vma_do_fault()
handle_mm_fault(FAULT_FLAG_WRITE)
/* returns VM_FAULT_WRITE */
/* returns -EBUSY */
/* returns -EBUSY */
/* returns -EBUSY */
/* loops on -EBUSY and range->valid */
Prevent this by checking for vma->vm_flags & VM_WRITE before calling
handle_mm_fault().
Signed-off-by: Ralph Campbell <rcampbell at nvidia.com>
---
mm/hmm.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mm/hmm.c b/mm/hmm.c
index 29371485fe94..4882b83aeccb 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -292,6 +292,9 @@ static int hmm_vma_walk_hole_(unsigned long addr, unsigned
long end,
hmm_vma_walk->last = addr;
i = (addr - range->start) >> PAGE_SHIFT;
+ if (write_fault && walk->vma && !(walk->vma->vm_flags
& VM_WRITE))
+ return -EPERM;
+
for (; addr < end; addr += PAGE_SIZE, i++) {
pfns[i] = range->values[HMM_PFN_NONE];
if (fault || write_fault) {
--
2.20.1
Christoph Hellwig
2019-Aug-24 22:37 UTC
[Nouveau] [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 <hch at lst.de>
Christoph Hellwig
2019-Aug-24 22:39 UTC
[Nouveau] [PATCH 2/2] mm/hmm: hmm_range_fault() infinite loop
On Fri, Aug 23, 2019 at 03:17:53PM -0700, Ralph Campbell wrote:> Normally, callers to handle_mm_fault() are supposed to check the > vma->vm_flags first. hmm_range_fault() checks for VM_READ but doesn't > check for VM_WRITE if the caller requests a page to be faulted in > with write permission (via the hmm_range.pfns[] value). > If the vma is write protected, this can result in an infinite loop: > hmm_range_fault() > walk_page_range() > ... > hmm_vma_walk_hole() > hmm_vma_walk_hole_() > hmm_vma_do_fault() > handle_mm_fault(FAULT_FLAG_WRITE) > /* returns VM_FAULT_WRITE */ > /* returns -EBUSY */ > /* returns -EBUSY */ > /* returns -EBUSY */ > /* loops on -EBUSY and range->valid */ > Prevent this by checking for vma->vm_flags & VM_WRITE before calling > handle_mm_fault(). > > Signed-off-by: Ralph Campbell <rcampbell at nvidia.com>Looks good, Reviewed-by: Christoph Hellwig <hch at lst.de>
Jason Gunthorpe
2019-Aug-27 18:41 UTC
[Nouveau] [PATCH 2/2] mm/hmm: hmm_range_fault() infinite loop
On Fri, Aug 23, 2019 at 03:17:53PM -0700, Ralph Campbell wrote:> Signed-off-by: Ralph Campbell <rcampbell at nvidia.com> > mm/hmm.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/mm/hmm.c b/mm/hmm.c > index 29371485fe94..4882b83aeccb 100644 > +++ b/mm/hmm.c > @@ -292,6 +292,9 @@ static int hmm_vma_walk_hole_(unsigned long addr, unsigned long end, > hmm_vma_walk->last = addr; > i = (addr - range->start) >> PAGE_SHIFT; > > + if (write_fault && walk->vma && !(walk->vma->vm_flags & VM_WRITE)) > + return -EPERM;Can walk->vma be NULL here? hmm_vma_do_fault() touches it unconditionally. Jason
Jason Gunthorpe
2019-Aug-27 22:48 UTC
[Nouveau] [PATCH 0/2] mm/hmm: two bug fixes for hmm_range_fault()
On Fri, Aug 23, 2019 at 03:17:51PM -0700, Ralph Campbell wrote:> I have been working on converting Jerome's hmm_dummy driver and self > tests into a stand-alone set of tests to be included in > tools/testing/selftests/vm and came across these two bug fixes in the > process. The tests aren't quite ready to be posted as a patch. > I'm posting the fixes now since I thought they shouldn't wait. > They should probably have a fixes line but with all the HMM changes, > I wasn't sure exactly which commit to use. > > These are based on top of Jason's latest hmm branch. > > Ralph Campbell (2): > mm/hmm: hmm_range_fault() NULL pointer bug > mm/hmm: hmm_range_fault() infinite loopApplied to hmm.git Thanks, Jason