This patch removes the need for root to run DRM. It is attached too in
case gmail destroys the formatting.

Major highlights:
1) removal of the general root check on the IOCTLs, added root check in AddMap
1) permanent SAREA map
2) user space can AddMap AGP maps, AGP maps are restricted to creation
in AGP space.
3) Deprecation of some radeon variables now calculated by the driver

I haven't converted PCI GART support. You still need to be root for it to work.

Please look it over and tell me if I have created any security holes.

-- 
Jon Smirl
[EMAIL PROTECTED]


diff --git a/linux-core/drmP.h b/linux-core/drmP.h
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -280,7 +280,7 @@ typedef int drm_ioctl_compat_t(struct fi
  typedef struct drm_ioctl_desc {
        drm_ioctl_t *func;
        int auth_needed;
-       int root_only;
+       int master;
 } drm_ioctl_desc_t;
 
  typedef struct drm_devstate {
@@ -375,6 +375,7 @@ typedef struct drm_buf_entry {
 /** File private data */
  typedef struct drm_file {
        int authenticated;
+       int master;
        int minor;
        pid_t pid;
        uid_t uid;
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -56,7 +56,8 @@ static drm_local_map_t *drm_find_matchin
        list_for_each(list, &dev->maplist->head) {
                drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
                if (entry->map && map->type == entry->map->type &&
-                   entry->map->offset == map->offset) {
+                   ((entry->map->offset == map->offset) ||
+                    (map->type == _DRM_SHM))) {
                        return entry->map;
                }
        }
@@ -163,6 +164,19 @@ int drm_addmap(drm_device_t * dev, unsig
                        map->handle = drm_ioremap(map->offset, map->size, dev);
                break;
        case _DRM_SHM:
+               found_map = drm_find_matching_map(dev, map);
+               if (found_map != NULL) {
+                       if (found_map->size != map->size) {
+                               DRM_DEBUG("Matching maps of type %d with "
+                                  "mismatched sizes, (%ld vs %ld)\n",
+                                   map->type, map->size, found_map->size);
+                               found_map->size = map->size;
+                       }
+
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       *map_ptr = found_map;
+                       return 0;
+               }
                map->handle = vmalloc_32(map->size);
                DRM_DEBUG("%lu %d %p\n",
                          map->size, drm_order(map->size), map->handle);
@@ -181,15 +195,34 @@ int drm_addmap(drm_device_t * dev, unsig
                        dev->sigdata.lock = dev->lock.hw_lock = map->handle;    
/* Pointer to lock */
                }
                break;
-       case _DRM_AGP:
-               if (drm_core_has_AGP(dev)) {
+       case _DRM_AGP: {
+               drm_agp_mem_t *entry;
+               int valid = 0;
+
+               if (!drm_core_has_AGP(dev)) {
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       return -EINVAL;
+               }
  #ifdef __alpha__
-                       map->offset += dev->hose->mem_space->start;
+               map->offset += dev->hose->mem_space->start;
  #endif
-                       map->offset += dev->agp->base;
-                       map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+               map->offset += dev->agp->base;
+               map->mtrr = dev->agp->agp_mtrr; /* for getmap */
+
+               for (entry = dev->agp->memory; entry; entry = entry->next) {
+                       if ((map->offset >= entry->bound) &&
+                           (map->offset + map->offset <= entry->bound + 
entry->pages *
PAGE_SIZE)) {
+                               valid = 1;
+                               break;
+                       }
+               }
+               if (!valid) {
+                       drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+                       return -EPERM;
                }
+               DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", 
map->offset, map->size);
                break;
+       }
        case _DRM_SCATTER_GATHER:
                if (!dev->sg) {
                        drm_free(map, sizeof(*map), DRM_MEM_MAPS);
@@ -258,6 +291,9 @@ int drm_addmap_ioctl(struct inode *inode
                return -EFAULT;
        }
 
+       if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP))
+               return -EPERM;
+
        err = drm_addmap( dev, map.offset, map.size, map.type, map.flags,
                          & map_ptr );
 
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -545,13 +545,14 @@ int drm_ioctl(struct inode *inode, struc
        if (!func) {
                DRM_DEBUG("no function\n");
                retcode = -EINVAL;
-       } else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) ||
-                  (ioctl->auth_needed && !priv->authenticated)) {
+       } else if (((ioctl->master && !priv->master) ||
+                  (ioctl->auth_needed && !priv->authenticated)) &&
+                  (!capable(CAP_SYS_ADMIN))) {
                retcode = -EACCES;
        } else {
                retcode = func(inode, filp, cmd, arg);
        }
-      err_i1:
+err_i1:
        atomic_dec(&dev->ioctl_count);
        if (retcode)
                DRM_DEBUG("ret = %x\n", retcode);
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c
--- a/linux-core/drm_fops.c
+++ b/linux-core/drm_fops.c
@@ -34,18 +34,26 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
  #include <linux/poll.h>
 
+#include "drmP.h"
+#include "drm_sarea.h"
+
  static int drm_open_helper(struct inode *inode, struct file *filp,
drm_device_t * dev);
 
  static int drm_setup(drm_device_t * dev)
 {
+       drm_local_map_t *map;
        int i;
 
        if (dev->driver->presetup)
                dev->driver->presetup(dev);
 
+       /* prebuild the SAREA */
+       i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
+       if (i != 0)
+               return i;
+
        atomic_set(&dev->ioctl_count, 0);
        atomic_set(&dev->vma_count, 0);
        dev->buf_use = 0;
@@ -244,6 +252,7 @@ static int drm_open_helper(struct inode 
        priv->minor = minor;
        priv->head = drm_heads[minor];
        priv->ioctl_count = 0;
+       /* for compatibility root is always authenticated */
        priv->authenticated = capable(CAP_SYS_ADMIN);
        priv->lock_count = 0;
 
@@ -259,6 +268,9 @@ static int drm_open_helper(struct inode 
                priv->prev = NULL;
                dev->file_first = priv;
                dev->file_last = priv;
+               /* first opener automatically becomes master and authenticated 
*/
+               priv->master = 1;
+               priv->authenticated = 1;
        } else {
                priv->next = NULL;
                priv->prev = dev->file_last;
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
diff --git a/shared-core/drm.h b/shared-core/drm.h
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -62,6 +62,12 @@
 #define __user
  #endif
 
+#ifdef __GNUC__
+# define DEPRECATED  __attribute__ ((deprecated))
+#else
+# define DEPRECATED
+#endif
+
 #if defined(__linux__)
 #if defined(__KERNEL__)
  #include <linux/config.h>
diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c
--- a/shared-core/radeon_cp.c
+++ b/shared-core/radeon_cp.c
@@ -1245,7 +1245,7 @@ static void radeon_set_pciegart(drm_rade
        u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
        if (on) {
 
-               DRM_DEBUG("programming pcie %08X %08lX %08X\n",
dev_priv->gart_vm_start, dev_priv->bus_pci_gart,dev_priv->gart_size);
+               DRM_DEBUG("programming pcie %08X %08X %08X\n",
dev_priv->gart_vm_start, dev_priv->bus_pci_gart,dev_priv->gart_size);
                RADEON_WRITE_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO,
dev_priv->gart_vm_start);
                RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_BASE, 
dev_priv->bus_pci_gart);
                RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_START_LO, 
dev_priv->gart_vm_start);
@@ -1398,8 +1398,6 @@ static int radeon_do_init_cp(drm_device_
 
        DRM_GETSAREA();
 
-       dev_priv->fb_offset = init->fb_offset;
-       dev_priv->mmio_offset = init->mmio_offset;
        dev_priv->ring_offset = init->ring_offset;
        dev_priv->ring_rptr_offset = init->ring_rptr_offset;
        dev_priv->buffers_offset = init->buffers_offset;
@@ -1411,12 +1409,6 @@ static int radeon_do_init_cp(drm_device_
                return DRM_ERR(EINVAL);
        }
 
-       dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
-       if (!dev_priv->mmio) {
-               DRM_ERROR("could not find mmio region!\n");
-               radeon_do_cleanup_cp(dev);
-               return DRM_ERR(EINVAL);
-       }
        dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
        if (!dev_priv->cp_ring) {
                DRM_ERROR("could not find cp ring region!\n");
diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h
--- a/shared-core/radeon_drm.h
+++ b/shared-core/radeon_drm.h
@@ -492,7 +492,7 @@ typedef struct drm_radeon_init {
                RADEON_INIT_R300_CP = 0x04
        } func;
        unsigned long sarea_priv_offset;
-       int is_pci;             /* not used, driver asks hardware */
+       int is_pci DEPRECATED;                  /* deprecated, driver asks 
hardware */
        int cp_mode;
        int gart_size;
        int ring_size;
@@ -504,8 +504,8 @@ typedef struct drm_radeon_init {
        unsigned int depth_bpp;
        unsigned int depth_offset, depth_pitch;
 
-       unsigned long fb_offset;
-       unsigned long mmio_offset;
+       unsigned long fb_offset DEPRECATED;     /* deprecated, driver asks 
hardware */
+       unsigned long mmio_offset DEPRECATED;   /* deprecated, driver asks 
hardware */
        unsigned long ring_offset;
        unsigned long ring_rptr_offset;
        unsigned long buffers_offset;
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -242,8 +242,6 @@ typedef struct drm_radeon_private {
 
        drm_radeon_depth_clear_t depth_clear;
 
-       unsigned long fb_offset;
-       unsigned long mmio_offset;
        unsigned long ring_offset;
        unsigned long ring_rptr_offset;
        unsigned long buffers_offset;
diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -2917,7 +2917,7 @@ static int radeon_cp_getparam(DRM_IOCTL_
                value = dev_priv->gart_vm_start;
                break;
        case RADEON_PARAM_REGISTER_HANDLE:
-               value = dev_priv->mmio_offset;
+               value = dev_priv->mmio->offset;
                break;
        case RADEON_PARAM_STATUS_HANDLE:
                value = dev_priv->ring_rptr_offset;
diff --git a/linux-core/drmP.h b/linux-core/drmP.h
--- a/linux-core/drmP.h
+++ b/linux-core/drmP.h
@@ -280,7 +280,7 @@ typedef int drm_ioctl_compat_t(struct fi
 typedef struct drm_ioctl_desc {
 	drm_ioctl_t *func;
 	int auth_needed;
-	int root_only;
+	int master;
 } drm_ioctl_desc_t;
 
 typedef struct drm_devstate {
@@ -375,6 +375,7 @@ typedef struct drm_buf_entry {
 /** File private data */
 typedef struct drm_file {
 	int authenticated;
+	int master;
 	int minor;
 	pid_t pid;
 	uid_t uid;
diff --git a/linux-core/drm_bufs.c b/linux-core/drm_bufs.c
--- a/linux-core/drm_bufs.c
+++ b/linux-core/drm_bufs.c
@@ -56,7 +56,8 @@ static drm_local_map_t *drm_find_matchin
 	list_for_each(list, &dev->maplist->head) {
 		drm_map_list_t *entry = list_entry(list, drm_map_list_t, head);
 		if (entry->map && map->type == entry->map->type &&
-		    entry->map->offset == map->offset) {
+		    ((entry->map->offset == map->offset) ||
+		     (map->type == _DRM_SHM))) {
 			return entry->map;
 		}
 	}
@@ -163,6 +164,19 @@ int drm_addmap(drm_device_t * dev, unsig
 			map->handle = drm_ioremap(map->offset, map->size, dev);
 		break;
 	case _DRM_SHM:
+		found_map = drm_find_matching_map(dev, map);
+		if (found_map != NULL) {
+			if (found_map->size != map->size) {
+				DRM_DEBUG("Matching maps of type %d with "
+				   "mismatched sizes, (%ld vs %ld)\n",
+				    map->type, map->size, found_map->size);
+				found_map->size = map->size;
+			}
+
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			*map_ptr = found_map;
+			return 0;
+		}
 		map->handle = vmalloc_32(map->size);
 		DRM_DEBUG("%lu %d %p\n",
 			  map->size, drm_order(map->size), map->handle);
@@ -181,15 +195,34 @@ int drm_addmap(drm_device_t * dev, unsig
 			dev->sigdata.lock = dev->lock.hw_lock = map->handle;	/* Pointer to lock */
 		}
 		break;
-	case _DRM_AGP:
-		if (drm_core_has_AGP(dev)) {
+	case _DRM_AGP: {
+		drm_agp_mem_t *entry;
+		int valid = 0;
+
+		if (!drm_core_has_AGP(dev)) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -EINVAL;
+		}
 #ifdef __alpha__
-			map->offset += dev->hose->mem_space->start;
+		map->offset += dev->hose->mem_space->start;
 #endif
-			map->offset += dev->agp->base;
-			map->mtrr = dev->agp->agp_mtrr;	/* for getmap */
+		map->offset += dev->agp->base;
+		map->mtrr = dev->agp->agp_mtrr;	/* for getmap */
+
+		for (entry = dev->agp->memory; entry; entry = entry->next) {
+			if ((map->offset >= entry->bound) &&
+			    (map->offset + map->offset <= entry->bound + entry->pages * PAGE_SIZE)) {
+				valid = 1;
+				break;
+			}
+		}
+		if (!valid) {
+			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+			return -EPERM;
 		}
+		DRM_DEBUG("AGP offset = 0x%08lx, size = 0x%08lx\n", map->offset, map->size);
 		break;
+	}
 	case _DRM_SCATTER_GATHER:
 		if (!dev->sg) {
 			drm_free(map, sizeof(*map), DRM_MEM_MAPS);
@@ -258,6 +291,9 @@ int drm_addmap_ioctl(struct inode *inode
 		return -EFAULT;
 	}
 
+	if (!(capable(CAP_SYS_ADMIN) || map.type == _DRM_AGP))
+		return -EPERM;
+
 	err = drm_addmap( dev, map.offset, map.size, map.type, map.flags,
 			  & map_ptr );
 
diff --git a/linux-core/drm_drv.c b/linux-core/drm_drv.c
--- a/linux-core/drm_drv.c
+++ b/linux-core/drm_drv.c
@@ -545,13 +545,14 @@ int drm_ioctl(struct inode *inode, struc
 	if (!func) {
 		DRM_DEBUG("no function\n");
 		retcode = -EINVAL;
-	} else if ((ioctl->root_only && !capable(CAP_SYS_ADMIN)) ||
-		   (ioctl->auth_needed && !priv->authenticated)) {
+	} else if (((ioctl->master && !priv->master) ||
+		   (ioctl->auth_needed && !priv->authenticated)) &&
+		   (!capable(CAP_SYS_ADMIN))) {
 		retcode = -EACCES;
 	} else {
 		retcode = func(inode, filp, cmd, arg);
 	}
-      err_i1:
+err_i1:
 	atomic_dec(&dev->ioctl_count);
 	if (retcode)
 		DRM_DEBUG("ret = %x\n", retcode);
diff --git a/linux-core/drm_fops.c b/linux-core/drm_fops.c
--- a/linux-core/drm_fops.c
+++ b/linux-core/drm_fops.c
@@ -34,18 +34,26 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#include "drmP.h"
 #include <linux/poll.h>
 
+#include "drmP.h"
+#include "drm_sarea.h"
+
 static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t * dev);
 
 static int drm_setup(drm_device_t * dev)
 {
+	drm_local_map_t *map;
 	int i;
 
 	if (dev->driver->presetup)
 		dev->driver->presetup(dev);
 
+	/* prebuild the SAREA */
+	i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
+	if (i != 0)
+		return i;
+
 	atomic_set(&dev->ioctl_count, 0);
 	atomic_set(&dev->vma_count, 0);
 	dev->buf_use = 0;
@@ -244,6 +252,7 @@ static int drm_open_helper(struct inode 
 	priv->minor = minor;
 	priv->head = drm_heads[minor];
 	priv->ioctl_count = 0;
+	/* for compatibility root is always authenticated */
 	priv->authenticated = capable(CAP_SYS_ADMIN);
 	priv->lock_count = 0;
 
@@ -259,6 +268,9 @@ static int drm_open_helper(struct inode 
 		priv->prev = NULL;
 		dev->file_first = priv;
 		dev->file_last = priv;
+		/* first opener automatically becomes master and authenticated */
+		priv->master = 1;
+		priv->authenticated = 1;
 	} else {
 		priv->next = NULL;
 		priv->prev = dev->file_last;
diff --git a/linux-core/drm_stub.c b/linux-core/drm_stub.c
diff --git a/shared-core/drm.h b/shared-core/drm.h
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -62,6 +62,12 @@
 #define __user
 #endif
 
+#ifdef __GNUC__
+# define DEPRECATED  __attribute__ ((deprecated))
+#else
+# define DEPRECATED
+#endif
+
 #if defined(__linux__)
 #if defined(__KERNEL__)
 #include <linux/config.h>
diff --git a/shared-core/radeon_cp.c b/shared-core/radeon_cp.c
--- a/shared-core/radeon_cp.c
+++ b/shared-core/radeon_cp.c
@@ -1245,7 +1245,7 @@ static void radeon_set_pciegart(drm_rade
 	u32 tmp = RADEON_READ_PCIE(dev_priv, RADEON_PCIE_TX_GART_CNTL);
 	if (on) {
 
-		DRM_DEBUG("programming pcie %08X %08lX %08X\n", dev_priv->gart_vm_start, dev_priv->bus_pci_gart,dev_priv->gart_size);
+		DRM_DEBUG("programming pcie %08X %08X %08X\n", dev_priv->gart_vm_start, dev_priv->bus_pci_gart,dev_priv->gart_size);
 		RADEON_WRITE_PCIE(RADEON_PCIE_TX_DISCARD_RD_ADDR_LO, dev_priv->gart_vm_start);
 		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_BASE, dev_priv->bus_pci_gart);
 		RADEON_WRITE_PCIE(RADEON_PCIE_TX_GART_START_LO, dev_priv->gart_vm_start);
@@ -1398,8 +1398,6 @@ static int radeon_do_init_cp(drm_device_
 
 	DRM_GETSAREA();
 
-	dev_priv->fb_offset = init->fb_offset;
-	dev_priv->mmio_offset = init->mmio_offset;
 	dev_priv->ring_offset = init->ring_offset;
 	dev_priv->ring_rptr_offset = init->ring_rptr_offset;
 	dev_priv->buffers_offset = init->buffers_offset;
@@ -1411,12 +1409,6 @@ static int radeon_do_init_cp(drm_device_
 		return DRM_ERR(EINVAL);
 	}
 
-	dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
-	if (!dev_priv->mmio) {
-		DRM_ERROR("could not find mmio region!\n");
-		radeon_do_cleanup_cp(dev);
-		return DRM_ERR(EINVAL);
-	}
 	dev_priv->cp_ring = drm_core_findmap(dev, init->ring_offset);
 	if (!dev_priv->cp_ring) {
 		DRM_ERROR("could not find cp ring region!\n");
diff --git a/shared-core/radeon_drm.h b/shared-core/radeon_drm.h
--- a/shared-core/radeon_drm.h
+++ b/shared-core/radeon_drm.h
@@ -492,7 +492,7 @@ typedef struct drm_radeon_init {
 		RADEON_INIT_R300_CP = 0x04
 	} func;
 	unsigned long sarea_priv_offset;
-	int is_pci;		/* not used, driver asks hardware */
+	int is_pci DEPRECATED;			/* deprecated, driver asks hardware */
 	int cp_mode;
 	int gart_size;
 	int ring_size;
@@ -504,8 +504,8 @@ typedef struct drm_radeon_init {
 	unsigned int depth_bpp;
 	unsigned int depth_offset, depth_pitch;
 
-	unsigned long fb_offset;
-	unsigned long mmio_offset;
+	unsigned long fb_offset DEPRECATED;	/* deprecated, driver asks hardware */
+	unsigned long mmio_offset DEPRECATED;	/* deprecated, driver asks hardware */
 	unsigned long ring_offset;
 	unsigned long ring_rptr_offset;
 	unsigned long buffers_offset;
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -242,8 +242,6 @@ typedef struct drm_radeon_private {
 
 	drm_radeon_depth_clear_t depth_clear;
 
-	unsigned long fb_offset;
-	unsigned long mmio_offset;
 	unsigned long ring_offset;
 	unsigned long ring_rptr_offset;
 	unsigned long buffers_offset;
diff --git a/shared-core/radeon_state.c b/shared-core/radeon_state.c
--- a/shared-core/radeon_state.c
+++ b/shared-core/radeon_state.c
@@ -2917,7 +2917,7 @@ static int radeon_cp_getparam(DRM_IOCTL_
 		value = dev_priv->gart_vm_start;
 		break;
 	case RADEON_PARAM_REGISTER_HANDLE:
-		value = dev_priv->mmio_offset;
+		value = dev_priv->mmio->offset;
 		break;
 	case RADEON_PARAM_STATUS_HANDLE:
 		value = dev_priv->ring_rptr_offset;

Reply via email to