aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorRoland Scheidegger <rscheidegger_lists@hispeed.ch>2006-10-24 07:45:00 -0400
committerDave Airlie <airlied@linux.ie>2006-10-24 07:45:00 -0400
commita1aa28970316d7fb606321d5ab7fb3873641ab54 (patch)
treeb19fcde58aedd1c59e202893d96a80de59a41df0 /drivers/char
parent7059abedd2f04b68bd7e1a79c9c72f7aeee134c0 (diff)
drm: radeon: only allow specific type-3 packetss through verifier
only allow specific type-3 packets to pass the verifier instead of all for r100/r200 as others might be unsafe (r300 already does this), and add checking for these we need but aren't safe. Check the RADEON_CP_INDX_BUFFER packet on both r200 and r300 as it isn't safe neither. Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/drm/r300_cmdbuf.c33
-rw-r--r--drivers/char/drm/radeon_state.c109
2 files changed, 138 insertions, 4 deletions
diff --git a/drivers/char/drm/r300_cmdbuf.c b/drivers/char/drm/r300_cmdbuf.c
index 26bdf2ca59d7..d14477ba3679 100644
--- a/drivers/char/drm/r300_cmdbuf.c
+++ b/drivers/char/drm/r300_cmdbuf.c
@@ -538,6 +538,36 @@ static __inline__ int r300_emit_bitblt_multi(drm_radeon_private_t *dev_priv,
538 return 0; 538 return 0;
539} 539}
540 540
541static __inline__ int r300_emit_indx_buffer(drm_radeon_private_t *dev_priv,
542 drm_radeon_kcmd_buffer_t *cmdbuf)
543{
544 u32 *cmd = (u32 *) cmdbuf->buf;
545 int count, ret;
546 RING_LOCALS;
547
548 count=(cmd[0]>>16) & 0x3fff;
549
550 if ((cmd[1] & 0x8000ffff) != 0x80000810) {
551 DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
552 return DRM_ERR(EINVAL);
553 }
554 ret = r300_check_offset(dev_priv, cmd[2]);
555 if (ret) {
556 DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
557 return DRM_ERR(EINVAL);
558 }
559
560 BEGIN_RING(count+2);
561 OUT_RING(cmd[0]);
562 OUT_RING_TABLE((int *)(cmdbuf->buf + 4), count + 1);
563 ADVANCE_RING();
564
565 cmdbuf->buf += (count+2)*4;
566 cmdbuf->bufsz -= (count+2)*4;
567
568 return 0;
569}
570
541static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv, 571static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
542 drm_radeon_kcmd_buffer_t *cmdbuf) 572 drm_radeon_kcmd_buffer_t *cmdbuf)
543{ 573{
@@ -578,10 +608,11 @@ static __inline__ int r300_emit_raw_packet3(drm_radeon_private_t *dev_priv,
578 case RADEON_CNTL_BITBLT_MULTI: 608 case RADEON_CNTL_BITBLT_MULTI:
579 return r300_emit_bitblt_multi(dev_priv, cmdbuf); 609 return r300_emit_bitblt_multi(dev_priv, cmdbuf);
580 610
611 case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
612 return r300_emit_indx_buffer(dev_priv, cmdbuf);
581 case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */ 613 case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */
582 case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */ 614 case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */
583 case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */ 615 case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */
584 case RADEON_CP_INDX_BUFFER: /* DRAW_INDX_2 without INDX_BUFFER seems to lock up the gpu */
585 case RADEON_WAIT_FOR_IDLE: 616 case RADEON_WAIT_FOR_IDLE:
586 case RADEON_CP_NOP: 617 case RADEON_CP_NOP:
587 /* these packets are safe */ 618 /* these packets are safe */
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index feac5f005d47..6e04fdd732ac 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -275,6 +275,8 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
275 unsigned int *cmdsz) 275 unsigned int *cmdsz)
276{ 276{
277 u32 *cmd = (u32 *) cmdbuf->buf; 277 u32 *cmd = (u32 *) cmdbuf->buf;
278 u32 offset, narrays;
279 int count, i, k;
278 280
279 *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); 281 *cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16);
280 282
@@ -288,10 +290,106 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
288 return DRM_ERR(EINVAL); 290 return DRM_ERR(EINVAL);
289 } 291 }
290 292
291 /* Check client state and fix it up if necessary */ 293 switch(cmd[0] & 0xff00) {
292 if (cmd[0] & 0x8000) { /* MSB of opcode: next DWORD GUI_CNTL */ 294 /* XXX Are there old drivers needing other packets? */
293 u32 offset;
294 295
296 case RADEON_3D_DRAW_IMMD:
297 case RADEON_3D_DRAW_VBUF:
298 case RADEON_3D_DRAW_INDX:
299 case RADEON_WAIT_FOR_IDLE:
300 case RADEON_CP_NOP:
301 case RADEON_3D_CLEAR_ZMASK:
302/* case RADEON_CP_NEXT_CHAR:
303 case RADEON_CP_PLY_NEXTSCAN:
304 case RADEON_CP_SET_SCISSORS: */ /* probably safe but will never need them? */
305 /* these packets are safe */
306 break;
307
308 case RADEON_CP_3D_DRAW_IMMD_2:
309 case RADEON_CP_3D_DRAW_VBUF_2:
310 case RADEON_CP_3D_DRAW_INDX_2:
311 case RADEON_3D_CLEAR_HIZ:
312 /* safe but r200 only */
313 if (dev_priv->microcode_version != UCODE_R200) {
314 DRM_ERROR("Invalid 3d packet for r100-class chip\n");
315 return DRM_ERR(EINVAL);
316 }
317 break;
318
319 case RADEON_3D_LOAD_VBPNTR:
320 count = (cmd[0] >> 16) & 0x3fff;
321
322 if (count > 18) { /* 12 arrays max */
323 DRM_ERROR("Too large payload in 3D_LOAD_VBPNTR (count=%d)\n",
324 count);
325 return DRM_ERR(EINVAL);
326 }
327
328 /* carefully check packet contents */
329 narrays = cmd[1] & ~0xc000;
330 k = 0;
331 i = 2;
332 while ((k < narrays) && (i < (count + 2))) {
333 i++; /* skip attribute field */
334 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
335 DRM_ERROR
336 ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
337 k, i);
338 return DRM_ERR(EINVAL);
339 }
340 k++;
341 i++;
342 if (k == narrays)
343 break;
344 /* have one more to process, they come in pairs */
345 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[i])) {
346 DRM_ERROR
347 ("Invalid offset (k=%d i=%d) in 3D_LOAD_VBPNTR packet.\n",
348 k, i);
349 return DRM_ERR(EINVAL);
350 }
351 k++;
352 i++;
353 }
354 /* do the counts match what we expect ? */
355 if ((k != narrays) || (i != (count + 2))) {
356 DRM_ERROR
357 ("Malformed 3D_LOAD_VBPNTR packet (k=%d i=%d narrays=%d count+1=%d).\n",
358 k, i, narrays, count + 1);
359 return DRM_ERR(EINVAL);
360 }
361 break;
362
363 case RADEON_3D_RNDR_GEN_INDX_PRIM:
364 if (dev_priv->microcode_version != UCODE_R100) {
365 DRM_ERROR("Invalid 3d packet for r200-class chip\n");
366 return DRM_ERR(EINVAL);
367 }
368 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[1])) {
369 DRM_ERROR("Invalid rndr_gen_indx offset\n");
370 return DRM_ERR(EINVAL);
371 }
372 break;
373
374 case RADEON_CP_INDX_BUFFER:
375 if (dev_priv->microcode_version != UCODE_R200) {
376 DRM_ERROR("Invalid 3d packet for r100-class chip\n");
377 return DRM_ERR(EINVAL);
378 }
379 if ((cmd[1] & 0x8000ffff) != 0x80000810) {
380 DRM_ERROR("Invalid indx_buffer reg address %08X\n", cmd[1]);
381 return DRM_ERR(EINVAL);
382 }
383 if (radeon_check_and_fixup_offset(dev_priv, filp_priv, &cmd[2])) {
384 DRM_ERROR("Invalid indx_buffer offset is %08X\n", cmd[2]);
385 return DRM_ERR(EINVAL);
386 }
387 break;
388
389 case RADEON_CNTL_HOSTDATA_BLT:
390 case RADEON_CNTL_PAINT_MULTI:
391 case RADEON_CNTL_BITBLT_MULTI:
392 /* MSB of opcode: next DWORD GUI_CNTL */
295 if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL 393 if (cmd[1] & (RADEON_GMC_SRC_PITCH_OFFSET_CNTL
296 | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) { 394 | RADEON_GMC_DST_PITCH_OFFSET_CNTL)) {
297 offset = cmd[2] << 10; 395 offset = cmd[2] << 10;
@@ -313,6 +411,11 @@ static __inline__ int radeon_check_and_fixup_packet3(drm_radeon_private_t *
313 } 411 }
314 cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10; 412 cmd[3] = (cmd[3] & 0xffc00000) | offset >> 10;
315 } 413 }
414 break;
415
416 default:
417 DRM_ERROR("Invalid packet type %x\n", cmd[0] & 0xff00);
418 return DRM_ERR(EINVAL);
316 } 419 }
317 420
318 return 0; 421 return 0;