Re: [RFC PATCH 4/6] mm: vm_unmapped_area() lookup function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 10/31/2012 06:33 AM, Michel Lespinasse wrote:

+/*
+ * Search for an unmapped address range.
+ *
+ * We are looking for a range that:
+ * - does not intersect with any VMA;
+ * - is contained within the [low_limit, high_limit[ interval;
                                                      ^
bracket is the wrong way around :)

+ * - is at least the desired size.
+ * - satisfies (begin_addr & align_mask) == (align_offset & align_mask)
+ */
+static inline unsigned long
+vm_unmapped_area(struct vm_unmapped_area_info *info)
+{
+	if (!(info->flags & VM_UNMAPPED_AREA_TOPDOWN))
+		return unmapped_area(info);
+	else
+		return unmapped_area_topdown(info);
+}

I like how you pass all the info in the struct. That solves
some of the problems I was trying to deal with when I implemented
something similar.

--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1494,6 +1494,206 @@ unacct_error:
  	return error;
  }

+unsigned long unmapped_area(struct vm_unmapped_area_info *info)
+{
+	/*
+	 * We implement the search by looking for an rbtree node that
+	 * immediately follows a suitable gap. That is,
+	 * - gap_start = vma->vm_prev->vm_end <= info->high_limit - length;
+	 * - gap_end   = vma->vm_start        >= info->low_limit  + length;
+	 * - gap_end - gap_start >= length
+	 */
+
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+	unsigned long length, low_limit, high_limit, gap_start, gap_end;
+
+	/* Adjust search length to account for worst case alignment overhead */
+	length = info->length + info->align_mask;
+	if (length < info->length)
+		return -ENOMEM;

If we unmap a VMA that is size N and correctly aligned, then
we may leave a gap of size N.

A subsequent call to mmap should be able to find that gap,
and use it.

It may make sense to not add the align_mask the first time
around, and see if the gap that we find already has the
correct alignment.

If it does not, we can always add the align_mask, and do
a second search for a hole of N + align_mask:

if (hole not aligned) {
    length += info->align_mask;
    goto again;
}

@@ -1603,53 +1777,12 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
  			return addr;
  	}

...

+	info.flags = VM_UNMAPPED_AREA_TOPDOWN;
+	info.length = len;
+	info.low_limit = 0;
+	info.high_limit = mm->mmap_base;
+	info.align_mask = 0;
+	addr = vm_unmapped_area(&info);

I believe it would be better to set low_limit to PAGE_SIZE.

Otherwise we can return 0, which is indistinguishable from a null
pointer.  Keeping address 0 unmapped provides the security benefit
that code that can be made to address null pointers causes a crash,
instead of a potential privilege escalation.

The rest of the patch looks good.

--
All rights reversed

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@xxxxxxxxx.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@xxxxxxxxx";> email@xxxxxxxxx </a>


[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]