Skip to contentSkip to conversation

Fix bound checking in do_mmap_pgoff()

PATCH In review Benjamin Herrenschmidt 2 participants 3 messages Sep 19, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Fix bound checking in do_mmap_pgoff()

Hi !

A small issue has been forever in do_mmap_pgoff() in the boundary checking in the sense that it won't let you mmap with offset+len enclosing the last page of the "address space". For example, an mmap of /dev/mem won't let you map the last page of the physical address space (which I need for a ROM dump tool on pmac). This fixes it:

===== mm/mmap.c 1.144 vs edited =====

mm/mmap.c +1 -1
@@ -801,7 +801,7 @@
 		return -EINVAL;
 
 	/* offset overflow? */
-	if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
+	if ((pgoff + (len >> PAGE_SHIFT) - 1) < pgoff)
 		return -EINVAL;
 
 	/* Too many mappings? */
#1 lore raw

Review

Quoted 8 lines · Benjamin Herrenschmidt

A small issue has been forever in do_mmap_pgoff() in the boundary checking in the sense that it won't let you mmap with offset+len enclosing the last page of the "address space". For example, an mmap of /dev/mem won't let you map the last page of the physical address space (which I need for a ROM dump tool on pmac). This fixes it:

(quoted diff) +1 -1
-	if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
+	if ((pgoff + (len >> PAGE_SHIFT) - 1) < pgoff)

Your physical address space happens to be 16TB? Okay...

I think you need to add in the patch below, to prevent mismerging of vmas. There might be other places which would get confused by an end pgoff of 0.

Hugh

mm/mmap.c +2 -6
@@ -529,10 +529,6 @@ static inline int is_mergeable_anon_vma(
  *
  * We cannot merge two vmas if they have differently assigned (non-NULL)
  * anon_vmas, nor if same anon_vma is assigned but offsets incompatible.
- *
- * We don't check here for the merged mmap wrapping around the end of pagecache
- * indices (16TB on ia32) because do_mmap_pgoff() does not permit mmap's which
- * wrap, nor mmaps which cover the final page at index -1UL.
  */
 static int
 can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
@@ -540,7 +536,7 @@ can_vma_merge_before(struct vm_area_stru
 {
 	if (is_mergeable_vma(vma, file, vm_flags) &&
 	    is_mergeable_anon_vma(anon_vma, vma->anon_vma)) {
-		if (vma->vm_pgoff == vm_pgoff)
+		if (vma->vm_pgoff == vm_pgoff && vm_pgoff != 0)
 			return 1;
 	}
 	return 0;
@@ -561,7 +557,7 @@ can_vma_merge_after(struct vm_area_struc
 	    is_mergeable_anon_vma(anon_vma, vma->anon_vma)) {
 		pgoff_t vm_pglen;
 		vm_pglen = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-		if (vma->vm_pgoff + vm_pglen == vm_pgoff)
+		if (vma->vm_pgoff + vm_pglen == vm_pgoff && vm_pgoff != 0)
 			return 1;
 	}
 	return 0;
#2 lore raw
Quoted 11 lines · Hugh Dickins

Review

Quoted 8 lines · Benjamin Herrenschmidt

A small issue has been forever in do_mmap_pgoff() in the boundary checking in the sense that it won't let you mmap with offset+len enclosing the last page of the "address space". For example, an mmap of /dev/mem won't let you map the last page of the physical address space (which I need for a ROM dump tool on pmac). This fixes it:

(quoted diff) +1 -1
-	if ((pgoff + (len >> PAGE_SHIFT)) < pgoff)
+	if ((pgoff + (len >> PAGE_SHIFT) - 1) < pgoff)

Your physical address space happens to be 16TB? Okay...

hrm... nope... my bad, the problem comes from elsewhere, sorry. I need to look at it again.

Quoted 2 lines

I think you need to add in the patch below, to prevent mismerging of vmas. There might be other places which would get confused by an end pgoff of 0.

Ok, that's becoming more tricky then, Andrew, of course drop the bogus patch for now, I'll look into more details later if I find time. In the meantime, we'll continue use a special kernel module for doing the ROM dump.

Ben.