From: Arjan van de Ven <arjanv@redhat.com>

The patch below adds a few missing put_user()'s to the i810/i830 drm
modules.  Users reported oopses with 4g/4g split in action, and sparse
annotations indeed found the offender in the function in question.  I've
kept the sparse __user annotations since those are generally useful anyway.
 I can't test it myself but a few people reported that the oopses went away
so far.


---

 25-akpm/drivers/char/drm/i810_dma.c |    8 +++--
 25-akpm/drivers/char/drm/i830_dma.c |   49 ++++++++++++++++++------------------
 25-akpm/drivers/char/drm/i830_drm.h |    8 ++---
 25-akpm/drivers/char/drm/i830_drv.h |    2 -
 25-akpm/drivers/char/drm/i830_irq.c |    2 -
 5 files changed, 36 insertions(+), 33 deletions(-)

diff -puN drivers/char/drm/i810_dma.c~drm-put_user-fixes drivers/char/drm/i810_dma.c
--- 25/drivers/char/drm/i810_dma.c~drm-put_user-fixes	2004-04-03 03:00:03.589685840 -0800
+++ 25-akpm/drivers/char/drm/i810_dma.c	2004-04-03 03:00:03.604683560 -0800
@@ -844,11 +844,13 @@ static void i810_dma_dispatch_vertex(drm
 	if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
 		unsigned int prim = (sarea_priv->vertex_prim & PR_MASK);
 
-		*(u32 *)buf_priv->virtual = (GFX_OP_PRIMITIVE | prim | 
-					     ((used/4)-2));
+		put_user((GFX_OP_PRIMITIVE | prim |
+					     ((used/4)-2)),
+		(u32 *)buf_priv->virtual);
 
 		if (used & 4) {
-			*(u32 *)((u32)buf_priv->virtual + used) = 0;
+			put_user(0,
+			(u32 *)((u32)buf_priv->virtual + used));
 			used += 4;
 		}
 
diff -puN drivers/char/drm/i830_dma.c~drm-put_user-fixes drivers/char/drm/i830_dma.c
--- 25/drivers/char/drm/i830_dma.c~drm-put_user-fixes	2004-04-03 03:00:03.592685384 -0800
+++ 25-akpm/drivers/char/drm/i830_dma.c	2004-04-03 03:00:03.608682952 -0800
@@ -39,6 +39,7 @@
 #include <linux/interrupt.h>	/* For task queue support */
 #include <linux/pagemap.h>	/* For FASTCALL on unlock_page() */
 #include <linux/delay.h>
+#include <asm/uaccess.h>
 
 #define I830_BUF_FREE		2
 #define I830_BUF_CLIENT		1
@@ -160,7 +161,7 @@ static int i830_map_buffer(drm_buf_t *bu
 	old_fops = filp->f_op;
 	filp->f_op = &i830_buffer_fops;
 	dev_priv->mmap_buffer = buf;
-	buf_priv->virtual = (void *)do_mmap(filp, 0, buf->total, 
+	buf_priv->virtual = (void __user *)do_mmap(filp, 0, buf->total,
 					    PROT_READ|PROT_WRITE,
 					    MAP_SHARED, 
 					    buf->bus_address);
@@ -462,7 +463,7 @@ static int i830_dma_initialize(drm_devic
 }
 
 int i830_dma_init(struct inode *inode, struct file *filp,
-		  unsigned int cmd, unsigned long arg)
+		  unsigned int cmd, unsigned long __user arg)
 {
    	drm_file_t *priv = filp->private_data;
    	drm_device_t *dev = priv->dev;
@@ -470,7 +471,7 @@ int i830_dma_init(struct inode *inode, s
    	drm_i830_init_t init;
    	int retcode = 0;
 	
-  	if (copy_from_user(&init, (drm_i830_init_t *)arg, sizeof(init)))
+  	if (copy_from_user(&init, (void * __user) arg, sizeof(init)))
 		return -EFAULT;
 	
    	switch(init.func) {
@@ -1164,19 +1165,19 @@ static void i830_dma_dispatch_vertex(drm
    	DRM_DEBUG(  "start + used - 4 : %ld\n", start + used - 4);
 
 	if (buf_priv->currently_mapped == I830_BUF_MAPPED) {
-		u32 *vp = buf_priv->virtual;
+		u32  *vp = buf_priv->virtual;
 
-		vp[0] = (GFX_OP_PRIMITIVE |
+		put_user( (GFX_OP_PRIMITIVE |
 			 sarea_priv->vertex_prim |
-			 ((used/4)-2));
+			  ((used/4)-2)), &vp[0]);
 
 		if (dev_priv->use_mi_batchbuffer_start) {
-			vp[used/4] = MI_BATCH_BUFFER_END; 
+			put_user(MI_BATCH_BUFFER_END, &vp[used/4]);
 			used += 4; 
 		}
 		
 		if (used & 4) {
-			vp[used/4] = 0;
+			put_user(0, &vp[used/4]);
 			used += 4;
 		}
 
@@ -1314,7 +1315,7 @@ void i830_reclaim_buffers( struct file *
 }
 
 int i830_flush_ioctl(struct inode *inode, struct file *filp, 
-		     unsigned int cmd, unsigned long arg)
+		     unsigned int cmd, unsigned long __user arg)
 {
    	drm_file_t	  *priv	  = filp->private_data;
    	drm_device_t	  *dev	  = priv->dev;
@@ -1329,7 +1330,7 @@ int i830_flush_ioctl(struct inode *inode
 }
 
 int i830_dma_vertex(struct inode *inode, struct file *filp,
-	       unsigned int cmd, unsigned long arg)
+	       unsigned int cmd, unsigned long __user arg)
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
@@ -1340,7 +1341,7 @@ int i830_dma_vertex(struct inode *inode,
      					dev_priv->sarea_priv; 
 	drm_i830_vertex_t vertex;
 
-	if (copy_from_user(&vertex, (drm_i830_vertex_t *)arg, sizeof(vertex)))
+	if (copy_from_user(&vertex, (drm_i830_vertex_t __user *)arg, sizeof(vertex)))
 		return -EFAULT;
 
    	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1364,13 +1365,13 @@ int i830_dma_vertex(struct inode *inode,
 }
 
 int i830_clear_bufs(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg)
+		   unsigned int cmd, unsigned long __user arg)
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
 	drm_i830_clear_t clear;
 
-   	if (copy_from_user(&clear, (drm_i830_clear_t *)arg, sizeof(clear)))
+   	if (copy_from_user(&clear, (drm_i830_clear_t __user *)arg, sizeof(clear)))
 		return -EFAULT;
    
    	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1391,7 +1392,7 @@ int i830_clear_bufs(struct inode *inode,
 }
 
 int i830_swap_bufs(struct inode *inode, struct file *filp,
-		  unsigned int cmd, unsigned long arg)
+		  unsigned int cmd, unsigned long __user arg)
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
@@ -1434,7 +1435,7 @@ int i830_do_cleanup_pageflip( drm_device
 }
 
 int i830_flip_bufs(struct inode *inode, struct file *filp,
-		   unsigned int cmd, unsigned long arg)
+		   unsigned int cmd, unsigned long __user arg)
 {
 	drm_file_t *priv = filp->private_data;
 	drm_device_t *dev = priv->dev;
@@ -1455,7 +1456,7 @@ int i830_flip_bufs(struct inode *inode, 
 }
 
 int i830_getage(struct inode *inode, struct file *filp, unsigned int cmd,
-		unsigned long arg)
+		unsigned long __user arg)
 {
    	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;
@@ -1469,7 +1470,7 @@ int i830_getage(struct inode *inode, str
 }
 
 int i830_getbuf(struct inode *inode, struct file *filp, unsigned int cmd,
-		unsigned long arg)
+		unsigned long __user arg)
 {
 	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;
@@ -1481,7 +1482,7 @@ int i830_getbuf(struct inode *inode, str
      					dev_priv->sarea_priv; 
 
 	DRM_DEBUG("getbuf\n");
-   	if (copy_from_user(&d, (drm_i830_dma_t *)arg, sizeof(d)))
+   	if (copy_from_user(&d, (drm_i830_dma_t __user *)arg, sizeof(d)))
 		return -EFAULT;
    
 	if(!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) {
@@ -1496,7 +1497,7 @@ int i830_getbuf(struct inode *inode, str
 	DRM_DEBUG("i830_dma: %d returning %d, granted = %d\n",
 		  current->pid, retcode, d.granted);
 
-	if (copy_to_user((drm_dma_t *)arg, &d, sizeof(d)))
+	if (copy_to_user((drm_dma_t __user *)arg, &d, sizeof(d)))
 		return -EFAULT;
    	sarea_priv->last_dispatch = (int) hw_status[5];
 
@@ -1506,7 +1507,7 @@ int i830_getbuf(struct inode *inode, str
 int i830_copybuf(struct inode *inode,
 		 struct file *filp, 
 		 unsigned int cmd,
-		 unsigned long arg)
+		 unsigned long __user arg)
 {
 	/* Never copy - 2.4.x doesn't need it */
 	return 0;
@@ -1521,7 +1522,7 @@ int i830_docopy(struct inode *inode, str
 
 
 int i830_getparam( struct inode *inode, struct file *filp, unsigned int cmd,
-		      unsigned long arg )
+		      unsigned long __user arg )
 {
 	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;
@@ -1534,7 +1535,7 @@ int i830_getparam( struct inode *inode, 
 		return -EINVAL;
 	}
 
-	if (copy_from_user(&param, (drm_i830_getparam_t *)arg, sizeof(param) ))
+	if (copy_from_user(&param, (drm_i830_getparam_t __user *)arg, sizeof(param) ))
 		return -EFAULT;
 
 	switch( param.param ) {
@@ -1555,7 +1556,7 @@ int i830_getparam( struct inode *inode, 
 
 
 int i830_setparam( struct inode *inode, struct file *filp, unsigned int cmd,
-		   unsigned long arg )
+		   unsigned long __user arg )
 {
 	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;
@@ -1567,7 +1568,7 @@ int i830_setparam( struct inode *inode, 
 		return -EINVAL;
 	}
 
-	if (copy_from_user(&param, (drm_i830_setparam_t *)arg, sizeof(param) ))
+	if (copy_from_user(&param, (drm_i830_setparam_t __user *)arg, sizeof(param) ))
 		return -EFAULT;
 
 	switch( param.param ) {
diff -puN drivers/char/drm/i830_drm.h~drm-put_user-fixes drivers/char/drm/i830_drm.h
--- 25/drivers/char/drm/i830_drm.h~drm-put_user-fixes	2004-04-03 03:00:03.594685080 -0800
+++ 25-akpm/drivers/char/drm/i830_drm.h	2004-04-03 03:00:03.610682648 -0800
@@ -290,11 +290,11 @@ typedef struct _drm_i830_vertex {
 typedef struct _drm_i830_copy_t {
    	int idx;		/* buffer index */
 	int used;		/* nr bytes in use */
-	void *address;		/* Address to copy from */
+	void __user *address;		/* Address to copy from */
 } drm_i830_copy_t;
 
 typedef struct drm_i830_dma {
-	void *virtual;
+	void __user *virtual;
 	int request_idx;
 	int request_size;
 	int granted;
@@ -304,7 +304,7 @@ typedef struct drm_i830_dma {
 /* 1.3: Userspace can request & wait on irq's:
  */
 typedef struct drm_i830_irq_emit {
-	int *irq_seq;
+	int __user *irq_seq;
 } drm_i830_irq_emit_t;
 
 typedef struct drm_i830_irq_wait {
@@ -318,7 +318,7 @@ typedef struct drm_i830_irq_wait {
 
 typedef struct drm_i830_getparam {
 	int param;
-	int *value;
+	int __user *value;
 } drm_i830_getparam_t;
 
 
diff -puN drivers/char/drm/i830_drv.h~drm-put_user-fixes drivers/char/drm/i830_drv.h
--- 25/drivers/char/drm/i830_drv.h~drm-put_user-fixes	2004-04-03 03:00:03.596684776 -0800
+++ 25-akpm/drivers/char/drm/i830_drv.h	2004-04-03 03:00:03.611682496 -0800
@@ -36,7 +36,7 @@ typedef struct drm_i830_buf_priv {
    	u32 *in_use;
    	int my_use_idx;
 	int currently_mapped;
-	void *virtual;
+	void __user *virtual;
 	void *kernel_virtual;
 } drm_i830_buf_priv_t;
 
diff -puN drivers/char/drm/i830_irq.c~drm-put_user-fixes drivers/char/drm/i830_irq.c
--- 25/drivers/char/drm/i830_irq.c~drm-put_user-fixes	2004-04-03 03:00:03.598684472 -0800
+++ 25-akpm/drivers/char/drm/i830_irq.c	2004-04-03 03:00:03.611682496 -0800
@@ -121,7 +121,7 @@ int i830_wait_irq(drm_device_t *dev, int
 /* Needs the lock as it touches the ring.
  */
 int i830_irq_emit( struct inode *inode, struct file *filp, unsigned int cmd,
-		   unsigned long arg )
+		   unsigned long __user arg )
 {
 	drm_file_t	  *priv	    = filp->private_data;
 	drm_device_t	  *dev	    = priv->dev;

_