r2719 - in trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian: . patches patches/series
Simon Horman
horms@costa.debian.org
Tue, 15 Mar 2005 08:48:32 +0100
Author: horms
Date: 2005-03-15 08:48:31 +0100 (Tue, 15 Mar 2005)
New Revision: 2719
Added:
trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/radeon-race.dpatch
trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-15
Modified:
trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
Log:
[Security] Fix race in radeon driver which can result in local privelage escalation. (closes: #297203)
Modified: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog 2005-03-14 23:06:42 UTC (rev 2718)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/changelog 2005-03-15 07:48:31 UTC (rev 2719)
@@ -1,3 +1,10 @@
+kernel-source-2.6.8 (2.6.8-15) UNRELEASED; urgency=low
+
+ * [Security] Fix race in radeon driver which can result
+ in local privelage escalation. (Simon Horman) (closes: #297203)
+
+ -- Simon Horman <horms@debian.org> Tue, 15 Mar 2005 14:27:46 +0900
+
kernel-source-2.6.8 (2.6.8-14) unstable; urgency=high
* Backport more scsi-ioctl fixes: add CMD_WARNED, remove dulicate
Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/radeon-race.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/radeon-race.dpatch 2005-03-14 23:06:42 UTC (rev 2718)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/radeon-race.dpatch 2005-03-15 07:48:31 UTC (rev 2719)
@@ -0,0 +1,600 @@
+#! /bin/sh -e
+## <PATCHNAME>.dpatch by <PATCH_AUTHOR@EMAI>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: drm: fix race condition in radeon driver
+## DP: Patch author: Eric Anholt <anholt@freebsd.org>
+## DP: Upstream status: backport
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+# origin: airlied (BitKeeper)
+# cset: 1.1982.56.2 (2.6) key=42088d17CO1mOAfgW4R46WRTm9gkwA
+# URL: http://linux.bkbits.net:8080/linux-2.6/gnupatch@42088d17CO1mOAfgW4R46WRTm9gkwA
+# inclusion: upstream
+# descrition: drm: fix race condition in radeon driver
+# revision date: Tue, 15 Mar 2005 14:20:00 +0900
+#
+# S rset: ChangeSet|1.1982.56.1..1.1982.56.2
+# I rset: drivers/char/drm/radeon_drv.h|1.38..1.39
+# I rset: drivers/char/drm/radeon_state.c|1.43..1.44
+# I rset: drivers/char/drm/drm_os_linux.h|1.21..1.22
+#
+# Key:
+# S: Skipped ChangeSet file only
+# O: Original Followed by Updated
+# U: Updated Included with updated range of versions
+# I: Included Included verbatim
+# E: Excluded Excluded on request from user
+# D: Deleted Manually deleted by subsequent user edit
+# R: Revised Manually revised by subsequent user edit
+#
+#
+# This is a BitKeeper generated diff -Nru style patch.
+#
+# ChangeSet
+# 2005/02/08 20:57:43+11:00 airlied@starflyer.(none)
+# drm: fix race condition in radeon driver
+#
+# 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)
+#
+# From: Eric Anholt <anholt@freebsd.org>
+# Signed-off-by: Dave Airlie <airlied@linux.ie>
+#
+# drivers/char/drm/radeon_state.c
+# 2005/02/08 20:57:35+11:00 airlied@starflyer.(none) +68 -87
+# drm: fix race condition in radeon driver
+#
+# 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)
+#
+# From: Eric Anholt <anholt@freebsd.org>
+# Signed-off-by: Dave Airlie <airlied@linux.ie>
+#
+# drivers/char/drm/radeon_drv.h
+# 2005/02/08 20:57:35+11:00 airlied@starflyer.(none) +15 -13
+# drm: fix race condition in radeon driver
+#
+# 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)
+#
+# From: Eric Anholt <anholt@freebsd.org>
+# Signed-off-by: Dave Airlie <airlied@linux.ie>
+#
+# drivers/char/drm/drm_os_linux.h
+# 2005/02/08 20:57:35+11:00 airlied@starflyer.(none) +0 -3
+# drm: fix race condition in radeon driver
+#
+# 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)
+#
+# From: Eric Anholt <anholt@freebsd.org>
+# Signed-off-by: Dave Airlie <airlied@linux.ie>
+#
+#
+===== drivers/char/drm/radeon_drv.h 1.38 vs 1.39 =====
+--- 1.38/drivers/char/drm/radeon_drv.h 2005-01-27 17:51:20 +09:00
++++ 1.39/drivers/char/drm/radeon_drv.h 2005-02-08 18:57:35 +09:00
+@@ -1027,25 +1027,27 @@ do { \
+ } 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; \
+ } \
+ \
+- if (_size && DRM_COPY_FROM_USER_UNCHECKED( (int *)(ring+write), \
+- _tab, _size*4 )) \
+- return DRM_ERR(EFAULT); \
+- \
+- write += _size; \
++ while (_size > 0) { \
++ *(ring + write) = *_tab++; \
++ write++; \
++ _size--; \
++ } \
+ write &= mask; \
+ } while (0)
+
+===== drivers/char/drm/radeon_state.c 1.43 vs 1.44 =====
+--- 1.43/drivers/char/drm/radeon_state.c 2005-01-27 17:51:20 +09:00
++++ 1.44/drivers/char/drm/radeon_state.c 2005-02-08 18:57:35 +09:00
+@@ -93,21 +93,6 @@ static __inline__ int radeon_check_and_f
+ return 0;
+ }
+
+-static __inline__ int radeon_check_and_fixup_offset_user( drm_radeon_private_t *dev_priv,
+- drm_file_t *filp_priv,
+- u32 __user *offset ) {
+- u32 off;
+-
+- DRM_GET_USER_UNCHECKED( off, offset );
+-
+- if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &off ) )
+- return DRM_ERR( EINVAL );
+-
+- DRM_PUT_USER_UNCHECKED( offset, off );
+-
+- return 0;
+-}
+-
+ static __inline__ int radeon_check_and_fixup_packets( drm_radeon_private_t *dev_priv,
+ drm_file_t *filp_priv,
+ int id,
+@@ -115,18 +100,18 @@ static __inline__ int radeon_check_and_f
+ switch ( id ) {
+
+ case RADEON_EMIT_PP_MISC:
+- if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+- &data[( RADEON_RB3D_DEPTHOFFSET
+- - RADEON_PP_MISC ) / 4] ) ) {
++ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
++ &data[( RADEON_RB3D_DEPTHOFFSET
++ - RADEON_PP_MISC ) / 4] ) ) {
+ DRM_ERROR( "Invalid depth buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+ break;
+
+ case RADEON_EMIT_PP_CNTL:
+- if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+- &data[( RADEON_RB3D_COLOROFFSET
+- - RADEON_PP_CNTL ) / 4] ) ) {
++ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
++ &data[( RADEON_RB3D_COLOROFFSET
++ - RADEON_PP_CNTL ) / 4] ) ) {
+ DRM_ERROR( "Invalid colour buffer offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+@@ -138,8 +123,8 @@ static __inline__ int radeon_check_and_f
+ case R200_EMIT_PP_TXOFFSET_3:
+ case R200_EMIT_PP_TXOFFSET_4:
+ case R200_EMIT_PP_TXOFFSET_5:
+- if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+- &data[0] ) ) {
++ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
++ &data[0] ) ) {
+ DRM_ERROR( "Invalid R200 texture offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+@@ -148,9 +133,9 @@ static __inline__ int radeon_check_and_f
+ case RADEON_EMIT_PP_TXFILTER_0:
+ case RADEON_EMIT_PP_TXFILTER_1:
+ case RADEON_EMIT_PP_TXFILTER_2:
+- if ( radeon_check_and_fixup_offset_user( dev_priv, filp_priv,
+- &data[( RADEON_PP_TXOFFSET_0
+- - RADEON_PP_TXFILTER_0 ) / 4] ) ) {
++ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
++ &data[( RADEON_PP_TXOFFSET_0
++ - RADEON_PP_TXFILTER_0 ) / 4] ) ) {
+ DRM_ERROR( "Invalid R100 texture offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+@@ -164,9 +149,8 @@ static __inline__ int radeon_check_and_f
+ case R200_EMIT_PP_CUBIC_OFFSETS_5: {
+ int i;
+ for ( i = 0; i < 5; i++ ) {
+- if ( radeon_check_and_fixup_offset_user( dev_priv,
+- filp_priv,
+- &data[i] ) ) {
++ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv,
++ &data[i] ) ) {
+ DRM_ERROR( "Invalid R200 cubic texture offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+@@ -250,17 +234,11 @@ static __inline__ int radeon_check_and_f
+ drm_file_t *filp_priv,
+ drm_radeon_cmd_buffer_t *cmdbuf,
+ unsigned int *cmdsz ) {
+- u32 tmp[4];
+- u32 __user *cmd = (u32 __user *)cmdbuf->buf;
+-
+- if ( DRM_COPY_FROM_USER_UNCHECKED( tmp, cmd, sizeof( tmp ) ) ) {
+- DRM_ERROR( "Failed to copy data from user space\n" );
+- return DRM_ERR( EFAULT );
+- }
++ u32 *cmd = (u32 *) cmdbuf->buf;
+
+- *cmdsz = 2 + ( ( tmp[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 );
++ *cmdsz = 2 + ( ( cmd[0] & RADEON_CP_PACKET_COUNT_MASK ) >> 16 );
+
+- if ( ( tmp[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) {
++ if ( ( cmd[0] & 0xc0000000 ) != RADEON_CP_PACKET3 ) {
+ DRM_ERROR( "Not a type 3 packet\n" );
+ return DRM_ERR( EINVAL );
+ }
+@@ -271,32 +249,27 @@ static __inline__ int radeon_check_and_f
+ }
+
+ /* Check client state and fix it up if necessary */
+- if ( tmp[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */
++ if ( cmd[0] & 0x8000 ) { /* MSB of opcode: next DWORD GUI_CNTL */
+ u32 offset;
+
+- if ( tmp[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL
++ if ( cmd[1] & ( RADEON_GMC_SRC_PITCH_OFFSET_CNTL
+ | RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+- offset = tmp[2] << 10;
++ offset = cmd[2] << 10;
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+ DRM_ERROR( "Invalid first packet offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+- tmp[2] = ( tmp[2] & 0xffc00000 ) | offset >> 10;
++ cmd[2] = ( cmd[2] & 0xffc00000 ) | offset >> 10;
+ }
+
+- if ( ( tmp[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) &&
+- ( tmp[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
+- offset = tmp[3] << 10;
++ if ( ( cmd[1] & RADEON_GMC_SRC_PITCH_OFFSET_CNTL ) &&
++ ( cmd[1] & RADEON_GMC_DST_PITCH_OFFSET_CNTL ) ) {
++ offset = cmd[3] << 10;
+ if ( radeon_check_and_fixup_offset( dev_priv, filp_priv, &offset ) ) {
+ DRM_ERROR( "Invalid second packet offset\n" );
+ return DRM_ERR( EINVAL );
+ }
+- tmp[3] = ( tmp[3] & 0xffc00000 ) | offset >> 10;
+- }
+-
+- if ( DRM_COPY_TO_USER_UNCHECKED( cmd, tmp, sizeof( tmp ) ) ) {
+- DRM_ERROR( "Failed to copy data to user space\n" );
+- return DRM_ERR( EFAULT );
++ cmd[3] = ( cmd[3] & 0xffc00000 ) | offset >> 10;
+ }
+ }
+
+@@ -2473,7 +2446,7 @@ static int radeon_emit_packets(
+ {
+ int id = (int)header.packet.packet_id;
+ int sz, reg;
+- int __user *data = (int __user *)cmdbuf->buf;
++ int *data = (int *)cmdbuf->buf;
+ RING_LOCALS;
+
+ if (id >= RADEON_MAX_STATE_PACKETS)
+@@ -2494,7 +2467,7 @@ static int radeon_emit_packets(
+
+ BEGIN_RING(sz+1);
+ OUT_RING( CP_PACKET0( reg, (sz-1) ) );
+- OUT_RING_USER_TABLE( data, sz );
++ OUT_RING_TABLE( data, sz );
+ ADVANCE_RING();
+
+ cmdbuf->buf += sz * sizeof(int);
+@@ -2508,7 +2481,6 @@ static __inline__ int radeon_emit_scalar
+ drm_radeon_cmd_buffer_t *cmdbuf )
+ {
+ int sz = header.scalars.count;
+- int __user *data = (int __user *)cmdbuf->buf;
+ int start = header.scalars.offset;
+ int stride = header.scalars.stride;
+ RING_LOCALS;
+@@ -2517,7 +2489,7 @@ static __inline__ int radeon_emit_scalar
+ OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) );
+ OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
+ OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) );
+- OUT_RING_USER_TABLE( data, sz );
++ OUT_RING_TABLE( cmdbuf->buf, sz );
+ ADVANCE_RING();
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+@@ -2532,7 +2504,6 @@ static __inline__ int radeon_emit_scalar
+ drm_radeon_cmd_buffer_t *cmdbuf )
+ {
+ int sz = header.scalars.count;
+- int __user *data = (int __user *)cmdbuf->buf;
+ int start = ((unsigned int)header.scalars.offset) + 0x100;
+ int stride = header.scalars.stride;
+ RING_LOCALS;
+@@ -2541,7 +2512,7 @@ static __inline__ int radeon_emit_scalar
+ OUT_RING( CP_PACKET0( RADEON_SE_TCL_SCALAR_INDX_REG, 0 ) );
+ OUT_RING( start | (stride << RADEON_SCAL_INDX_DWORD_STRIDE_SHIFT));
+ OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_SCALAR_DATA_REG, sz-1 ) );
+- OUT_RING_USER_TABLE( data, sz );
++ OUT_RING_TABLE( cmdbuf->buf, sz );
+ ADVANCE_RING();
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+@@ -2554,7 +2525,6 @@ static __inline__ int radeon_emit_vector
+ drm_radeon_cmd_buffer_t *cmdbuf )
+ {
+ int sz = header.vectors.count;
+- int __user *data = (int __user *)cmdbuf->buf;
+ int start = header.vectors.offset;
+ int stride = header.vectors.stride;
+ RING_LOCALS;
+@@ -2563,7 +2533,7 @@ static __inline__ int radeon_emit_vector
+ OUT_RING( CP_PACKET0( RADEON_SE_TCL_VECTOR_INDX_REG, 0 ) );
+ OUT_RING( start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
+ OUT_RING( CP_PACKET0_TABLE( RADEON_SE_TCL_VECTOR_DATA_REG, (sz-1) ) );
+- OUT_RING_USER_TABLE( data, sz );
++ OUT_RING_TABLE( cmdbuf->buf, sz );
+ ADVANCE_RING();
+
+ cmdbuf->buf += sz * sizeof(int);
+@@ -2578,7 +2548,6 @@ static int radeon_emit_packet3( drm_devi
+ {
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ unsigned int cmdsz;
+- int __user *cmd = (int __user *)cmdbuf->buf;
+ int ret;
+ RING_LOCALS;
+
+@@ -2591,7 +2560,7 @@ static int radeon_emit_packet3( drm_devi
+ }
+
+ BEGIN_RING( cmdsz );
+- OUT_RING_USER_TABLE( cmd, cmdsz );
++ OUT_RING_TABLE( cmdbuf->buf, cmdsz );
+ ADVANCE_RING();
+
+ cmdbuf->buf += cmdsz * 4;
+@@ -2608,7 +2577,6 @@ static int radeon_emit_packet3_cliprect(
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ drm_clip_rect_t box;
+ unsigned int cmdsz;
+- int __user *cmd = (int __user *)cmdbuf->buf;
+ int ret;
+ drm_clip_rect_t __user *boxes = cmdbuf->boxes;
+ int i = 0;
+@@ -2627,7 +2595,7 @@ static int radeon_emit_packet3_cliprect(
+
+ do {
+ if ( i < cmdbuf->nbox ) {
+- if (DRM_COPY_FROM_USER_UNCHECKED( &box, &boxes[i], sizeof(box) ))
++ if (DRM_COPY_FROM_USER( &box, &boxes[i], sizeof(box) ))
+ return DRM_ERR(EFAULT);
+ /* FIXME The second and subsequent times round
+ * this loop, send a WAIT_UNTIL_3D_IDLE before
+@@ -2650,7 +2618,7 @@ static int radeon_emit_packet3_cliprect(
+ }
+
+ BEGIN_RING( cmdsz );
+- OUT_RING_USER_TABLE( cmd, cmdsz );
++ OUT_RING_TABLE( cmdbuf->buf, cmdsz );
+ ADVANCE_RING();
+
+ } while ( ++i < cmdbuf->nbox );
+@@ -2703,7 +2671,8 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ int idx;
+ drm_radeon_cmd_buffer_t cmdbuf;
+ drm_radeon_cmd_header_t header;
+- int orig_nbox;
++ int orig_nbox, orig_bufsz;
++ char *kbuf=NULL;
+
+ LOCK_TEST_WITH_RETURN( dev, filp );
+
+@@ -2720,24 +2689,29 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ RING_SPACE_TEST_WITH_RETURN( dev_priv );
+ VB_AGE_TEST_WITH_RETURN( dev_priv );
+
++ debian/patches/series/2.6.8-15
++ if (cmdbuf.bufsz > 64*1024 || cmdbuf.bufsz<0) {
++ return DRM_ERR(EINVAL);
++ }
+
+- if (DRM_VERIFYAREA_READ( cmdbuf.buf, cmdbuf.bufsz ))
+- return DRM_ERR(EFAULT);
+-
+- if (cmdbuf.nbox &&
+- DRM_VERIFYAREA_READ(cmdbuf.boxes,
+- cmdbuf.nbox * sizeof(drm_clip_rect_t)))
+- return DRM_ERR(EFAULT);
++ /* Allocate an in-kernel area and copy in the cmdbuf. Do this to avoid
++ * races between checking values and using those values in other code,
++ * and simply to avoid a lot of function calls to copy in data.
++ */
++ orig_bufsz = cmdbuf.bufsz;
++ if (orig_bufsz != 0) {
++ kbuf = drm_alloc(cmdbuf.bufsz, DRM_MEM_DRIVER);
++ if (kbuf == NULL)
++ return DRM_ERR(ENOMEM);
++ if (DRM_COPY_FROM_USER(kbuf, cmdbuf.buf, cmdbuf.bufsz))
++ return DRM_ERR(EFAULT);
++ cmdbuf.buf = kbuf;
++ }
+
+ orig_nbox = cmdbuf.nbox;
+
+ while ( cmdbuf.bufsz >= sizeof(header) ) {
+-
+- if (DRM_GET_USER_UNCHECKED( header.i, (int __user *)cmdbuf.buf )) {
+- DRM_ERROR("__get_user %p\n", cmdbuf.buf);
+- return DRM_ERR(EFAULT);
+- }
+
++ header.i = *(int *)cmdbuf.buf;
+ cmdbuf.buf += sizeof(header);
+ cmdbuf.bufsz -= sizeof(header);
+
+@@ -2746,7 +2720,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ DRM_DEBUG("RADEON_CMD_PACKET\n");
+ if (radeon_emit_packets( dev_priv, filp_priv, header, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_packets failed\n");
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ break;
+
+@@ -2754,7 +2728,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ DRM_DEBUG("RADEON_CMD_SCALARS\n");
+ if (radeon_emit_scalars( dev_priv, header, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_scalars failed\n");
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ break;
+
+@@ -2762,7 +2736,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ DRM_DEBUG("RADEON_CMD_VECTORS\n");
+ if (radeon_emit_vectors( dev_priv, header, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_vectors failed\n");
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ break;
+
+@@ -2772,14 +2746,14 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ if ( idx < 0 || idx >= dma->buf_count ) {
+ DRM_ERROR( "buffer index %d (of %d max)\n",
+ idx, dma->buf_count - 1 );
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+
+ buf = dma->buflist[idx];
+ if ( buf->filp != filp || buf->pending ) {
+ DRM_ERROR( "bad buffer %p %p %d\n",
+ buf->filp, filp, buf->pending);
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+
+ radeon_cp_discard_buffer( dev, buf );
+@@ -2789,7 +2763,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ DRM_DEBUG("RADEON_CMD_PACKET3\n");
+ if (radeon_emit_packet3( dev, filp_priv, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_packet3 failed\n");
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ break;
+
+@@ -2797,7 +2771,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ DRM_DEBUG("RADEON_CMD_PACKET3_CLIP\n");
+ if (radeon_emit_packet3_cliprect( dev, filp_priv, &cmdbuf, orig_nbox )) {
+ DRM_ERROR("radeon_emit_packet3_clip failed\n");
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ break;
+
+@@ -2805,7 +2779,7 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ DRM_DEBUG("RADEON_CMD_SCALARS2\n");
+ if (radeon_emit_scalars2( dev_priv, header, &cmdbuf )) {
+ DRM_ERROR("radeon_emit_scalars2 failed\n");
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ break;
+
+@@ -2813,21 +2787,28 @@ int radeon_cp_cmdbuf( DRM_IOCTL_ARGS )
+ DRM_DEBUG("RADEON_CMD_WAIT\n");
+ if (radeon_emit_wait( dev, header.wait.flags )) {
+ DRM_ERROR("radeon_emit_wait failed\n");
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ break;
+ default:
+ DRM_ERROR("bad cmd_type %d at %p\n",
+ header.header.cmd_type,
+ cmdbuf.buf - sizeof(header));
+- return DRM_ERR(EINVAL);
++ goto err;
+ }
+ }
+
++ if (orig_bufsz != 0)
++ drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
+
+ DRM_DEBUG("DONE\n");
+ COMMIT_RING();
+ return 0;
++
++err:
++ if (orig_bufsz != 0)
++ drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER);
++ return DRM_ERR(EINVAL);
+ }
+
+
+===== drivers/char/drm/drm_os_linux.h 1.21 vs 1.22 =====
+--- 1.21/drivers/char/drm/drm_os_linux.h 2004-10-24 15:44:47 +09:00
++++ 1.22/drivers/char/drm/drm_os_linux.h 2005-02-08 18:57:35 +09:00
+@@ -96,9 +96,6 @@ static __inline__ int mtrr_del (int reg,
+ __copy_to_user(arg1, arg2, arg3)
+ #define DRM_GET_USER_UNCHECKED(val, uaddr) \
+ __get_user(val, uaddr)
+-#define DRM_PUT_USER_UNCHECKED(uaddr, val) \
+- __put_user(val, uaddr)
+-
+
+ #define DRM_GET_PRIV_WITH_RETURN(_priv, _filp) _priv = _filp->private_data
+
Added: trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-15
===================================================================
--- trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-15 2005-03-14 23:06:42 UTC (rev 2718)
+++ trunk/kernel/source/kernel-source-2.6.8-2.6.8/debian/patches/series/2.6.8-15 2005-03-15 07:48:31 UTC (rev 2719)
@@ -0,0 +1 @@
++ radeon-race.dpatch