summaryrefslogtreecommitdiff
path: root/shared-core/radeon_drv.h
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2005-02-08 04:17:14 +0000
committerEric Anholt <anholt@freebsd.org>2005-02-08 04:17:14 +0000
commit81459d6e50a02b87ed95073659536eefa1e09fdf (patch)
tree92d9d61123ff5f3da299af3cc6a4b7bbd45bcd96 /shared-core/radeon_drv.h
parentdc4defe742387dc3081557111b67a1ab99455dbb (diff)
Close a race which could allow for privilege escalation by users with DRI
privileges on Radeon hardware. Essentially, a malicious program could submit a packet containing an offset (possibly in main memory) to be rendered from/to, while a separate thread switched that offset in userspace rapidly between a valid value and an invalid one. radeon_check_and_fixup_offset() would pull the offset in from user space, check it, and spit it back out to user space to be copied in later by the emit code. It would sometimes catch the bad value, but sometimes the malicious program could modify it after the check and get an invalid offset rendered from/to. Fix this by allocating a temporary buffer and copying the data in at once. While here, make the cliprects stuff not do the VERIFYAREA_READ and COPY_FROM_USER_UNCHECKED gymnastics, avoiding a lock order reversal on FreeBSD. Performance impact is negligible -- no difference on r200 to ~1% improvement on rv200 in quake3 tests (P4 1Ghz, demofour at 1024x768, n=4 or 5).
Diffstat (limited to 'shared-core/radeon_drv.h')
-rw-r--r--shared-core/radeon_drv.h31
1 files changed, 16 insertions, 15 deletions
diff --git a/shared-core/radeon_drv.h b/shared-core/radeon_drv.h
index 0932d5e6..b840ae6e 100644
--- a/shared-core/radeon_drv.h
+++ b/shared-core/radeon_drv.h
@@ -42,7 +42,7 @@
#define DRIVER_NAME "radeon"
#define DRIVER_DESC "ATI Radeon"
-#define DRIVER_DATE "20050125"
+#define DRIVER_DATE "20050207"
/* Interface history:
*
@@ -1005,25 +1005,26 @@ do { \
OUT_RING( val ); \
} while (0)
-#define OUT_RING_USER_TABLE( tab, sz ) do { \
+#define OUT_RING_TABLE( tab, sz ) do { \
int _size = (sz); \
- int __user *_tab = (tab); \
+ int *_tab = (int *)(tab); \
\
if (write + _size > mask) { \
- int i = (mask+1) - write; \
- if (DRM_COPY_FROM_USER_UNCHECKED( (int *)(ring+write), \
- _tab, i*4 )) \
- return DRM_ERR(EFAULT); \
+ int _i = (mask+1) - write; \
+ _size -= _i; \
+ while (_i > 0) { \
+ *(int *)(ring + write) = *_tab++; \
+ write++; \
+ _i--; \
+ } \
write = 0; \
- _size -= i; \
- _tab += i; \
+ _tab += _i; \
+ } \
+ while (_size > 0) { \
+ *(ring + write) = *_tab++; \
+ write++; \
+ _size--; \
} \
- \
- if (_size && DRM_COPY_FROM_USER_UNCHECKED( (int *)(ring+write), \
- _tab, _size*4 )) \
- return DRM_ERR(EFAULT); \
- \
- write += _size; \
write &= mask; \
} while (0)