From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Antonino A. Daplas" Subject: [PATCH][FBDEV] Fix copy_to/from_user in fbmem.c:fb_read/write Date: Mon, 30 Aug 2004 10:47:28 +0800 Sender: linux-fbdev-devel-admin@lists.sourceforge.net Message-ID: <200408301047.28117.adaplas@hotpop.com> Reply-To: linux-fbdev-devel@lists.sourceforge.net Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Return-path: Received: from sc8-sf-mx1-b.sourceforge.net ([10.3.1.11] helo=sc8-sf-mx1.sourceforge.net) by sc8-sf-list1.sourceforge.net with esmtp (Exim 4.30) id 1C1cCY-0003NT-GS for linux-fbdev-devel@lists.sourceforge.net; Sun, 29 Aug 2004 19:47:22 -0700 Received: from smtp-out.hotpop.com ([38.113.3.71]) by sc8-sf-mx1.sourceforge.net with esmtp (Exim 4.34) id 1C1cCW-0007rB-KL for linux-fbdev-devel@lists.sourceforge.net; Sun, 29 Aug 2004 19:47:21 -0700 Received: from hotpop.com (kubrick.hotpop.com [38.113.3.103]) by smtp-out.hotpop.com (Postfix) with SMTP id 3CEF210B1074 for ; Mon, 30 Aug 2004 02:47:12 +0000 (UTC) Content-Disposition: inline Errors-To: linux-fbdev-devel-admin@lists.sourceforge.net List-Unsubscribe: , List-Id: List-Post: List-Help: List-Subscribe: , List-Archive: Content-Type: text/plain; charset="us-ascii" To: Andrew Morton Cc: Linux Fbdev development list , "David S.Miller" Hi, This patch fixes a prblem reported by David S. Miller "I just noticed that fb_{read,write}() uses copy_*_user() with the kernel buffer being the frame buffer. It needs to use the proper device address accessor functions." Tony Signed-off-by: Antonino Daplas --- diff -uprN linux-2.6.9-rc1-mm1-orig/drivers/video/fbmem.c linux-2.6.9-rc1-mm1/drivers/video/fbmem.c --- linux-2.6.9-rc1-mm1-orig/drivers/video/fbmem.c 2004-08-27 05:24:32.000000000 +0800 +++ linux-2.6.9-rc1-mm1/drivers/video/fbmem.c 2004-08-27 05:25:02.200341392 +0800 @@ -878,6 +878,8 @@ fb_read(struct file *file, char __user * struct inode *inode = file->f_dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; + u32 *buffer, *dst, *src; + int c, i, cnt = 0, err = 0; if (!info || ! info->screen_base) return -ENODEV; @@ -894,18 +896,40 @@ fb_read(struct file *file, char __user * count = info->fix.smem_len; if (count + p > info->fix.smem_len) count = info->fix.smem_len - p; + + cnt = 0; + buffer = kmalloc((count > 64 * 1024) ? 64 * 1024 : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + src = (u32 *) (info->screen_base + p); + if (info->fbops->fb_sync) info->fbops->fb_sync(info); - if (count) { - char *base_addr; - - base_addr = info->screen_base; - count -= copy_to_user(buf, base_addr+p, count); - if (!count) - return -EFAULT; - *ppos += count; + + while (count) { + c = (count > 64 * 1024) ? 64 * 1024 : count; + dst = buffer; + for (i = c >> 2; i--; ) + *dst++ = fb_readl(src++); + if (c & 3) { + for (i = c & 3; i--;) + *((u8 *)dst++) = fb_readb((u8 *) src++); + } + + if (copy_to_user(buf, buffer, c)) { + err = -EFAULT; + break; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; } - return count; + + kfree(buffer); + return (err) ? err : cnt; } static ssize_t @@ -915,7 +939,8 @@ fb_write(struct file *file, const char _ struct inode *inode = file->f_dentry->d_inode; int fbidx = iminor(inode); struct fb_info *info = registered_fb[fbidx]; - int err; + u32 *buffer, *dst, *src; + int c, i, cnt = 0, err; if (!info || !info->screen_base) return -ENODEV; @@ -935,19 +960,38 @@ fb_write(struct file *file, const char _ count = info->fix.smem_len - p; err = -ENOSPC; } + cnt = 0; + buffer = kmalloc((count > 64 * 1024) ? 64 * 1024 : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u32 *) (info->screen_base + p); + if (info->fbops->fb_sync) info->fbops->fb_sync(info); - if (count) { - char *base_addr; - base_addr = info->screen_base; - count -= copy_from_user(base_addr+p, buf, count); - *ppos += count; - err = -EFAULT; + while (count) { + c = (count > 64 * 1024) ? 64 * 1024 : count; + src = buffer; + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + for (i = c >> 2; i--; ) + fb_writel(*src++, dst++); + if (c & 3) { + for (i = c & 3; i--; ) + fb_writeb(*(u8 *)src++, (u8 *)dst++); + } + *ppos += c; + buf += c; + cnt += c; + count -= c; } - if (count) - return count; - return err; + kfree(buffer); + + return (err) ? err : cnt; } #ifdef CONFIG_KMOD ------------------------------------------------------- This SF.Net email is sponsored by BEA Weblogic Workshop FREE Java Enterprise J2EE developer tools! Get your free copy of BEA WebLogic Workshop 8.1 today. http://ads.osdn.com/?ad_id=5047&alloc_id=10808&op=click