summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <anholt@freebsd.org>2005-11-08 09:02:02 +0000
committerEric Anholt <anholt@freebsd.org>2005-11-08 09:02:02 +0000
commit2c6308fe54c10075379cb00506d5519e0ced1076 (patch)
treea12d969c378fa8be237cd59a510234ee71a6a20c
parent4b2235d2e089a512b26ecd66ae42ea279fbb1df2 (diff)
Correct a LOR on FreeBSD by allocating a temporary buffer and doing a
single COPY_FROM_USER into it, rather than VERIFYAREA followed by many COPY_FROM_USER_UNCHECKEDs.
-rw-r--r--shared-core/mach64_state.c31
1 files changed, 16 insertions, 15 deletions
diff --git a/shared-core/mach64_state.c b/shared-core/mach64_state.c
index 45dd55d5..964d4c58 100644
--- a/shared-core/mach64_state.c
+++ b/shared-core/mach64_state.c
@@ -479,25 +479,29 @@ static int mach64_do_get_frames_queued(drm_mach64_private_t * dev_priv)
/* Copy and verify a client submited buffer.
* FIXME: Make an assembly optimized version
*/
-static __inline__ int copy_and_verify_from_user(u32 * to, const u32 * from,
+static __inline__ int copy_and_verify_from_user(u32 *to,
+ const u32 __user *ufrom,
unsigned long bytes)
{
unsigned long n = bytes; /* dwords remaining in buffer */
+ u32 *from, *orig_from;
- if (DRM_VERIFYAREA_READ(from, n)) {
- DRM_ERROR("%s: verify_area\n", __FUNCTION__);
+ from = drm_alloc(bytes, DRM_MEM_DRIVER);
+ if (from == NULL)
+ return ENOMEM;
+
+ if (DRM_COPY_FROM_USER(from, ufrom, bytes)) {
+ drm_free(from, bytes, DRM_MEM_DRIVER);
return DRM_ERR(EFAULT);
}
+ orig_from = from; /* we'll be modifying the "from" ptr, so save it */
n >>= 2;
while (n > 1) {
u32 data, reg, count;
- if (DRM_GET_USER_UNCHECKED(data, from++)) {
- DRM_ERROR("%s: get_user\n", __FUNCTION__);
- return DRM_ERR(EFAULT);
- }
+ data = *from++;
n--;
@@ -513,28 +517,25 @@ static __inline__ int copy_and_verify_from_user(u32 * to, const u32 * from,
if ((reg >= 0x0190 && reg < 0x01c1) ||
(reg >= 0x01ca && reg <= 0x01cf)) {
*to++ = data;
- if (DRM_COPY_FROM_USER_UNCHECKED
- (to, from, count << 2)) {
- DRM_ERROR("%s: copy_from_user\n",
- __FUNCTION__);
- return DRM_ERR(EFAULT);
- }
+ memcpy(to, from, count << 2);
+ from += count;
to += count;
} else {
DRM_ERROR("%s: Got bad command: 0x%04x\n",
__FUNCTION__, reg);
+ drm_free(orig_from, bytes, DRM_MEM_DRIVER);
return DRM_ERR(EACCES);
}
-
- from += count;
} else {
DRM_ERROR
("%s: Got bad command count(=%u) dwords remaining=%lu\n",
__FUNCTION__, count, n);
+ drm_free(orig_from, bytes, DRM_MEM_DRIVER);
return DRM_ERR(EINVAL);
}
}
+ drm_free(orig_from, bytes, DRM_MEM_DRIVER);
if (n == 0)
return 0;
else {