[Cbe-oss-dev] Hard crash on fb write past 17MB
Geert Uytterhoeven
Geert.Uytterhoeven at sonycom.com
Thu Jan 18 04:13:13 EST 2007
Here's a patch for 2.6.16.
A fix for 2.6.20 will be released through Geoff's GIT repositories.
Subject: [PATCH] ps3fb: temporary fix for out-of-bounds frame buffer access
From: Geert Uytterhoeven <Geert.Uytterhoeven at sonycom.com>
For both fb_info.screen_base and ps3fb_mmap(), an offset
(FB_OFF(i) + VP_OFF(i)) is added to the start address of the virtual frame
buffer. This offset is always a non-zero multiple of 64 kiB.
As both fb_write() and ps3fb_mmap() assume a buffer limit based on the actual
frame buffer size, and don't take into account the additional offset, they
allow to write a few multiples of 64 kiB beyond the end of the 18 MiB buffer.
This will overwrite innocent kernel memory, and may cause a crash.
As a temporary fix, this patch prevents out-of-bounds accesses by subtracting
the offset from the exported frame buffer size.
The right solution is to get rid of the offsets completely: as the frame buffer
is virtual, there's no reason it doesn't simply start at the beginning of the
block of allocated memory.
Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven at sonycom.com>
---
drivers/video/ps3fb.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
--- ps3-linux-src-2.6.16.orig/drivers/video/ps3fb.c
+++ ps3-linux-src-2.6.16/drivers/video/ps3fb.c
@@ -500,6 +500,8 @@ static int ps3fb_check_var(struct fb_var
static int ps3fb_set_par(struct fb_info *info)
{
int i;
+ unsigned long offset;
+
DPRINTK("xres:%d xv:%d yres:%d yv:%d clock:%d\n",
info->var.xres, info->var.xres_virtual,
info->var.yres, info->var.yres_virtual, info->var.pixclock);
@@ -508,8 +510,10 @@ static int ps3fb_set_par(struct fb_info
info->var.bits_per_pixel);
i = get_res_table(info->var.xres, info->var.yres);
ps3fb.res_index = i;
- info->screen_base = (char __iomem *)ps3fb.xdr_ea + FB_OFF(i) + VP_OFF(i);
- memset((void *)ps3fb.xdr_ea, 0, ps3fb.videomemorysize);
+ offset = FB_OFF(i) + VP_OFF(i);
+ info->fix.smem_len = ps3fb.videomemorysize-offset;
+ info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
+ memset(ps3fb.xdr_ea, 0, ps3fb.videomemorysize);
return 0;
}
@@ -644,7 +648,7 @@ static int ps3fb_mmap(struct fb_info *in
i = get_res_table(info->var.xres, info->var.yres);
if (i == -1) return -EINVAL;
- if (offset + size > ps3fb.videomemorysize)
+ if (offset + size > info->fix.smem_len)
return -EINVAL;
offset += ps3fb.videomemory_phys + FB_OFF(i) + VP_OFF(i);
if (remap_pfn_range(vma, vma->vm_start, offset >> PAGE_SHIFT,
@@ -1036,6 +1040,7 @@ static int __init ps3fb_probe(struct pla
uint64_t lpar_reports_size =0;
uint64_t xdr_lpar;
uint64_t status;
+ unsigned long offset;
/* get gpu context handle */
status = lv1_gpu_memory_allocate(
@@ -1089,13 +1094,13 @@ static int __init ps3fb_probe(struct pla
ps3fb_fb_var_default();
- info->screen_base = (char __iomem *)ps3fb.xdr_ea +
- FB_OFF(ps3fb.res_index) + VP_OFF(ps3fb.res_index);
+ offset = FB_OFF(ps3fb.res_index) + VP_OFF(ps3fb.res_index);
+ info->screen_base = (char __iomem *)ps3fb.xdr_ea + offset;
info->fbops = &ps3fb_ops;
info->var = ps3fb_default;
info->fix = ps3fb_fix;
- info->fix.smem_len = ps3fb.videomemorysize;
+ info->fix.smem_len = ps3fb.videomemorysize-offset;
info->pseudo_palette = info->par;
info->par = NULL;
info->flags = FBINFO_FLAG_DEFAULT;
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- Sony Network and Software Technology Center Europe (NSCE)
Geert.Uytterhoeven at sonycom.com ------- The Corporate Village, Da Vincilaan 7-D1
Voice +32-2-7008453 Fax +32-2-7008622 ---------------- B-1935 Zaventem, Belgium
More information about the cbe-oss-dev
mailing list