Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b4d5b8b authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

[PATCH] NOMMU: Check VMA protections



Check the VMA protections in get_user_pages() against what's being asked.

This checks to see that we don't accidentally write on a non-writable VMA or
permit an I/O mapping VMA to be accessed (which may lack page structs).

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 910e46da
Loading
Loading
Loading
Loading
+25 −5
Original line number Original line Diff line number Diff line
@@ -122,19 +122,35 @@ unsigned int kobjsize(const void *objp)
}
}


/*
/*
 * The nommu dodgy version :-)
 * get a list of pages in an address range belonging to the specified process
 * and indicate the VMA that covers each page
 * - this is potentially dodgy as we may end incrementing the page count of a
 *   slab page or a secondary page from a compound page
 * - don't permit access to VMAs that don't support it, such as I/O mappings
 */
 */
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
	unsigned long start, int len, int write, int force,
	unsigned long start, int len, int write, int force,
	struct page **pages, struct vm_area_struct **vmas)
	struct page **pages, struct vm_area_struct **vmas)
{
{
	int i;
	struct vm_area_struct *vma;
	struct vm_area_struct *vma;
	unsigned long vm_flags;
	int i;

	/* calculate required read or write permissions.
	 * - if 'force' is set, we only require the "MAY" flags.
	 */
	vm_flags  = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
	vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);


	for (i = 0; i < len; i++) {
	for (i = 0; i < len; i++) {
		vma = find_vma(mm, start);
		vma = find_vma(mm, start);
		if (!vma)
		if (!vma)
			return i ? : -EFAULT;
			goto finish_or_fault;

		/* protect what we can, including chardevs */
		if (vma->vm_flags & (VM_IO | VM_PFNMAP) ||
		    !(vm_flags & vma->vm_flags))
			goto finish_or_fault;


		if (pages) {
		if (pages) {
			pages[i] = virt_to_page(start);
			pages[i] = virt_to_page(start);
@@ -145,7 +161,11 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
			vmas[i] = vma;
			vmas[i] = vma;
		start += PAGE_SIZE;
		start += PAGE_SIZE;
	}
	}
	return(i);

	return i;

finish_or_fault:
	return i ? : -EFAULT;
}
}


EXPORT_SYMBOL(get_user_pages);
EXPORT_SYMBOL(get_user_pages);