[PATCH] drm/gma500: bound the fbdev fault loop to the framebuffer

Baul Lee <[email protected]>
Newsgroups org.freedesktop.lists.dri-devel,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
psb_fbdev_vm_fault() maps as many frames as the caller asked for:

	unsigned long pfn = info->fix.smem_start >> PAGE_SHIFT;
	unsigned long page_num = vma_pages(vma);

	for (i = 0; i < page_num; ++i) {
		err = vmf_insert_mixed(vma, address, pfn);
		...
		address += PAGE_SIZE;
		++pfn;
	}

The trip count is the VMA length and the pfn walks up from the
framebuffer base.  info->fix.smem_len, the extent of the framebuffer, is
not read anywhere in the handler, so a mapping longer than the
framebuffer installs present PTEs for the physical frames above it.

Nothing else on the path bounds the length.  psb_fbdev_fb_mmap() only
requires vm_pgoff to be zero, and fb_mmap() passes the length through.

On x86_64 an unprivileged process in group video mapped 4800 pages of a
600-page framebuffer; every page was present and writable, and the 4200
past the object were the frames above it in physical memory.  Nothing is
logged: the kernel installs valid PTEs and every access through them
comes from userspace.

Reject a fault whose page offset is already past the framebuffer and
clamp the loop to the frames the framebuffer owns.

Discovered by XBOW, triaged by Baul Lee <[email protected]>

Fixes: 0867b42113ec ("staging: gma500: Intel GMA500 staging driver")
Cc: [email protected]
Signed-off-by: Baul Lee <[email protected]>
---
 drivers/gpu/drm/gma500/fbdev.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/gma500/fbdev.c b/drivers/gpu/drm/gma500/fbdev.c
index d1e93588234f..393a939a0c37 100644
--- a/drivers/gpu/drm/gma500/fbdev.c
+++ b/drivers/gpu/drm/gma500/fbdev.c
@@ -26,9 +26,15 @@ static vm_fault_t psb_fbdev_vm_fault(struct vm_fault *vmf)
 	unsigned long address = vmf->address - (vmf->pgoff << PAGE_SHIFT);
 	unsigned long pfn = info->fix.smem_start >> PAGE_SHIFT;
 	vm_fault_t err = VM_FAULT_SIGBUS;
+	unsigned long obj_pages = info->fix.smem_len >> PAGE_SHIFT;
 	unsigned long page_num = vma_pages(vma);
 	unsigned long i;
 
+	if (vmf->pgoff >= obj_pages)
+		return VM_FAULT_SIGBUS;
+	if (page_num > obj_pages)
+		page_num = obj_pages;
+
 	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
 
 	for (i = 0; i < page_num; ++i) {
-- 
2.50.1 (Apple Git-155)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.