summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2010-02-24 17:17:13 +1000
committerGreg Kroah-Hartman <gregkh@suse.de>2010-07-05 11:15:55 -0700
commit1a0c0aa4945dfa8ac3adc2818e166b40eb5dc346 (patch)
treeed6ea4cf66d7a6b31c4374f83d8eba13f54d6498 /drivers
parent1fe767793d2a19f6852153987ae49a2ac6412a69 (diff)
downloadkernel-crypto-1a0c0aa4945dfa8ac3adc2818e166b40eb5dc346.tar.gz
kernel-crypto-1a0c0aa4945dfa8ac3adc2818e166b40eb5dc346.tar.xz
kernel-crypto-1a0c0aa4945dfa8ac3adc2818e166b40eb5dc346.zip
drm/radeon: r100/r200 ums: block ability for userspace app to trash 0 page and beyond
commit 566d84d172161cb6c0c4dd834c34abbac6bf7b38 upstream. radeon's have a special ability to passthrough writes in their internal memory space directly to PCI, this ability means that if some of the internal surfaces like the depth buffer point at 0x0, any writes to these will go directly to RAM at 0x0 via PCI busmastering. Now mesa used to always emit clears after emitting state, since the radeon mesa driver was refactored a year or more ago, it was found it could generate a clear request without ever sending any setup state to the card. So the clear would attempt to clear the depth buffer at 0x0, which would overwrite main memory at this point. fs corruption ensues. Also once one app did this correctly, it would never get set back to 0 making this messy to reproduce. The kernel should block this from happening as mesa runs without privs, though it does require the user be connected to the current running X session. This patch implements a check to make sure the depth offset has been set before a depth clear occurs and if it finds one it prints a warning and ignores the depth clear request. There is also a mesa fix to avoid sending the badness going into mesa. This only affects r100/r200 GPUs in user modesetting mode. Signed-off-by: Dave Airlie <airlied@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/radeon/radeon_cp.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_state.c6
3 files changed, 9 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c
index f129bbb8bbc..419630dd207 100644
--- a/drivers/gpu/drm/radeon/radeon_cp.c
+++ b/drivers/gpu/drm/radeon/radeon_cp.c
@@ -1646,6 +1646,7 @@ static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_pri
radeon_cp_load_microcode(dev_priv);
radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
+ dev_priv->have_z_offset = 0;
radeon_do_engine_reset(dev);
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
diff --git a/drivers/gpu/drm/radeon/radeon_drv.h b/drivers/gpu/drm/radeon/radeon_drv.h
index c57ad606504..ebaee618d44 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.h
+++ b/drivers/gpu/drm/radeon/radeon_drv.h
@@ -268,6 +268,8 @@ typedef struct drm_radeon_private {
u32 scratch_ages[5];
+ int have_z_offset;
+
/* starting from here on, data is preserved accross an open */
uint32_t flags; /* see radeon_chip_flags */
resource_size_t fb_aper_offset;
diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c
index 067167cb39c..fc2685f3545 100644
--- a/drivers/gpu/drm/radeon/radeon_state.c
+++ b/drivers/gpu/drm/radeon/radeon_state.c
@@ -101,6 +101,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
DRM_ERROR("Invalid depth buffer offset\n");
return -EINVAL;
}
+ dev_priv->have_z_offset = 1;
break;
case RADEON_EMIT_PP_CNTL:
@@ -876,6 +877,11 @@ static void radeon_cp_dispatch_clear(struct drm_device * dev,
if (tmp & RADEON_BACK)
flags |= RADEON_FRONT;
}
+ if (flags & (RADEON_DEPTH|RADEON_STENCIL)) {
+ if (!dev_priv->have_z_offset)
+ printk_once(KERN_ERR "radeon: illegal depth clear request. Buggy mesa detected - please update.\n");
+ flags &= ~(RADEON_DEPTH | RADEON_STENCIL);
+ }
if (flags & (RADEON_FRONT | RADEON_BACK)) {