diff options
author | Ben Hutchings <ben@decadent.org.uk> | 2009-08-23 11:59:04 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2009-08-30 19:09:30 -0400 |
commit | 7dc482dfeeeefcfd000d4271c4626937406756d7 (patch) | |
tree | 2ec9a70ecad5f7cb94136d53d98d587837f05ef3 | |
parent | 70967ab9c0c9017645d167d33675eab996633631 (diff) |
drm/r128: Add test for initialisation to all ioctls that require it
Almost all r128's private ioctls require that the CCE state has
already been initialised. However, most do not test that this has
been done, and will proceed to dereference a null pointer. This may
result in a security vulnerability, since some ioctls are
unprivileged.
This adds a macro for the common initialisation test and changes all
ioctl implementations that require prior initialisation to use that
macro.
Also, r128_do_init_cce() does not test that the CCE state has not
been initialised already. Repeated initialisation may lead to a crash
or resource leak. This adds that test.
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/r128/r128_cce.c | 18 | ||||
-rw-r--r-- | drivers/gpu/drm/r128/r128_drv.h | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/r128/r128_state.c | 36 |
3 files changed, 41 insertions, 21 deletions
diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index 15252f60bbd3..4c39a407aa4a 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c | |||
@@ -346,6 +346,11 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) | |||
346 | 346 | ||
347 | DRM_DEBUG("\n"); | 347 | DRM_DEBUG("\n"); |
348 | 348 | ||
349 | if (dev->dev_private) { | ||
350 | DRM_DEBUG("called when already initialized\n"); | ||
351 | return -EINVAL; | ||
352 | } | ||
353 | |||
349 | dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL); | 354 | dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL); |
350 | if (dev_priv == NULL) | 355 | if (dev_priv == NULL) |
351 | return -ENOMEM; | 356 | return -ENOMEM; |
@@ -647,6 +652,8 @@ int r128_cce_start(struct drm_device *dev, void *data, struct drm_file *file_pri | |||
647 | 652 | ||
648 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 653 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
649 | 654 | ||
655 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
656 | |||
650 | if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) { | 657 | if (dev_priv->cce_running || dev_priv->cce_mode == R128_PM4_NONPM4) { |
651 | DRM_DEBUG("while CCE running\n"); | 658 | DRM_DEBUG("while CCE running\n"); |
652 | return 0; | 659 | return 0; |
@@ -669,6 +676,8 @@ int r128_cce_stop(struct drm_device *dev, void *data, struct drm_file *file_priv | |||
669 | 676 | ||
670 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 677 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
671 | 678 | ||
679 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
680 | |||
672 | /* Flush any pending CCE commands. This ensures any outstanding | 681 | /* Flush any pending CCE commands. This ensures any outstanding |
673 | * commands are exectuted by the engine before we turn it off. | 682 | * commands are exectuted by the engine before we turn it off. |
674 | */ | 683 | */ |
@@ -706,10 +715,7 @@ int r128_cce_reset(struct drm_device *dev, void *data, struct drm_file *file_pri | |||
706 | 715 | ||
707 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 716 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
708 | 717 | ||
709 | if (!dev_priv) { | 718 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
710 | DRM_DEBUG("called before init done\n"); | ||
711 | return -EINVAL; | ||
712 | } | ||
713 | 719 | ||
714 | r128_do_cce_reset(dev_priv); | 720 | r128_do_cce_reset(dev_priv); |
715 | 721 | ||
@@ -726,6 +732,8 @@ int r128_cce_idle(struct drm_device *dev, void *data, struct drm_file *file_priv | |||
726 | 732 | ||
727 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 733 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
728 | 734 | ||
735 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
736 | |||
729 | if (dev_priv->cce_running) { | 737 | if (dev_priv->cce_running) { |
730 | r128_do_cce_flush(dev_priv); | 738 | r128_do_cce_flush(dev_priv); |
731 | } | 739 | } |
@@ -739,6 +747,8 @@ int r128_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_ | |||
739 | 747 | ||
740 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 748 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
741 | 749 | ||
750 | DEV_INIT_TEST_WITH_RETURN(dev->dev_private); | ||
751 | |||
742 | return r128_do_engine_reset(dev); | 752 | return r128_do_engine_reset(dev); |
743 | } | 753 | } |
744 | 754 | ||
diff --git a/drivers/gpu/drm/r128/r128_drv.h b/drivers/gpu/drm/r128/r128_drv.h index 797a26c42dab..3c60829d82e9 100644 --- a/drivers/gpu/drm/r128/r128_drv.h +++ b/drivers/gpu/drm/r128/r128_drv.h | |||
@@ -422,6 +422,14 @@ static __inline__ void r128_update_ring_snapshot(drm_r128_private_t * dev_priv) | |||
422 | * Misc helper macros | 422 | * Misc helper macros |
423 | */ | 423 | */ |
424 | 424 | ||
425 | #define DEV_INIT_TEST_WITH_RETURN(_dev_priv) \ | ||
426 | do { \ | ||
427 | if (!_dev_priv) { \ | ||
428 | DRM_ERROR("called with no initialization\n"); \ | ||
429 | return -EINVAL; \ | ||
430 | } \ | ||
431 | } while (0) | ||
432 | |||
425 | #define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ | 433 | #define RING_SPACE_TEST_WITH_RETURN( dev_priv ) \ |
426 | do { \ | 434 | do { \ |
427 | drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \ | 435 | drm_r128_ring_buffer_t *ring = &dev_priv->ring; int i; \ |
diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index 026a48c95c8f..af2665cf4718 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c | |||
@@ -1244,14 +1244,18 @@ static void r128_cce_dispatch_stipple(struct drm_device * dev, u32 * stipple) | |||
1244 | static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) | 1244 | static int r128_cce_clear(struct drm_device *dev, void *data, struct drm_file *file_priv) |
1245 | { | 1245 | { |
1246 | drm_r128_private_t *dev_priv = dev->dev_private; | 1246 | drm_r128_private_t *dev_priv = dev->dev_private; |
1247 | drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; | 1247 | drm_r128_sarea_t *sarea_priv; |
1248 | drm_r128_clear_t *clear = data; | 1248 | drm_r128_clear_t *clear = data; |
1249 | DRM_DEBUG("\n"); | 1249 | DRM_DEBUG("\n"); |
1250 | 1250 | ||
1251 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1251 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1252 | 1252 | ||
1253 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
1254 | |||
1253 | RING_SPACE_TEST_WITH_RETURN(dev_priv); | 1255 | RING_SPACE_TEST_WITH_RETURN(dev_priv); |
1254 | 1256 | ||
1257 | sarea_priv = dev_priv->sarea_priv; | ||
1258 | |||
1255 | if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS) | 1259 | if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS) |
1256 | sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; | 1260 | sarea_priv->nbox = R128_NR_SAREA_CLIPRECTS; |
1257 | 1261 | ||
@@ -1312,6 +1316,8 @@ static int r128_cce_flip(struct drm_device *dev, void *data, struct drm_file *fi | |||
1312 | 1316 | ||
1313 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1317 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1314 | 1318 | ||
1319 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
1320 | |||
1315 | RING_SPACE_TEST_WITH_RETURN(dev_priv); | 1321 | RING_SPACE_TEST_WITH_RETURN(dev_priv); |
1316 | 1322 | ||
1317 | if (!dev_priv->page_flipping) | 1323 | if (!dev_priv->page_flipping) |
@@ -1331,6 +1337,8 @@ static int r128_cce_swap(struct drm_device *dev, void *data, struct drm_file *fi | |||
1331 | 1337 | ||
1332 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1338 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1333 | 1339 | ||
1340 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
1341 | |||
1334 | RING_SPACE_TEST_WITH_RETURN(dev_priv); | 1342 | RING_SPACE_TEST_WITH_RETURN(dev_priv); |
1335 | 1343 | ||
1336 | if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS) | 1344 | if (sarea_priv->nbox > R128_NR_SAREA_CLIPRECTS) |
@@ -1354,10 +1362,7 @@ static int r128_cce_vertex(struct drm_device *dev, void *data, struct drm_file * | |||
1354 | 1362 | ||
1355 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1363 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1356 | 1364 | ||
1357 | if (!dev_priv) { | 1365 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
1358 | DRM_ERROR("called with no initialization\n"); | ||
1359 | return -EINVAL; | ||
1360 | } | ||
1361 | 1366 | ||
1362 | DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", | 1367 | DRM_DEBUG("pid=%d index=%d count=%d discard=%d\n", |
1363 | DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); | 1368 | DRM_CURRENTPID, vertex->idx, vertex->count, vertex->discard); |
@@ -1410,10 +1415,7 @@ static int r128_cce_indices(struct drm_device *dev, void *data, struct drm_file | |||
1410 | 1415 | ||
1411 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1416 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1412 | 1417 | ||
1413 | if (!dev_priv) { | 1418 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
1414 | DRM_ERROR("called with no initialization\n"); | ||
1415 | return -EINVAL; | ||
1416 | } | ||
1417 | 1419 | ||
1418 | DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID, | 1420 | DRM_DEBUG("pid=%d buf=%d s=%d e=%d d=%d\n", DRM_CURRENTPID, |
1419 | elts->idx, elts->start, elts->end, elts->discard); | 1421 | elts->idx, elts->start, elts->end, elts->discard); |
@@ -1476,6 +1478,8 @@ static int r128_cce_blit(struct drm_device *dev, void *data, struct drm_file *fi | |||
1476 | 1478 | ||
1477 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1479 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1478 | 1480 | ||
1481 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
1482 | |||
1479 | DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx); | 1483 | DRM_DEBUG("pid=%d index=%d\n", DRM_CURRENTPID, blit->idx); |
1480 | 1484 | ||
1481 | if (blit->idx < 0 || blit->idx >= dma->buf_count) { | 1485 | if (blit->idx < 0 || blit->idx >= dma->buf_count) { |
@@ -1501,6 +1505,8 @@ static int r128_cce_depth(struct drm_device *dev, void *data, struct drm_file *f | |||
1501 | 1505 | ||
1502 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1506 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1503 | 1507 | ||
1508 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
1509 | |||
1504 | RING_SPACE_TEST_WITH_RETURN(dev_priv); | 1510 | RING_SPACE_TEST_WITH_RETURN(dev_priv); |
1505 | 1511 | ||
1506 | ret = -EINVAL; | 1512 | ret = -EINVAL; |
@@ -1531,6 +1537,8 @@ static int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file | |||
1531 | 1537 | ||
1532 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1538 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1533 | 1539 | ||
1540 | DEV_INIT_TEST_WITH_RETURN(dev_priv); | ||
1541 | |||
1534 | if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) | 1542 | if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32))) |
1535 | return -EFAULT; | 1543 | return -EFAULT; |
1536 | 1544 | ||
@@ -1555,10 +1563,7 @@ static int r128_cce_indirect(struct drm_device *dev, void *data, struct drm_file | |||
1555 | 1563 | ||
1556 | LOCK_TEST_WITH_RETURN(dev, file_priv); | 1564 | LOCK_TEST_WITH_RETURN(dev, file_priv); |
1557 | 1565 | ||
1558 | if (!dev_priv) { | 1566 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
1559 | DRM_ERROR("called with no initialization\n"); | ||
1560 | return -EINVAL; | ||
1561 | } | ||
1562 | 1567 | ||
1563 | DRM_DEBUG("idx=%d s=%d e=%d d=%d\n", | 1568 | DRM_DEBUG("idx=%d s=%d e=%d d=%d\n", |
1564 | indirect->idx, indirect->start, indirect->end, | 1569 | indirect->idx, indirect->start, indirect->end, |
@@ -1620,10 +1625,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi | |||
1620 | drm_r128_getparam_t *param = data; | 1625 | drm_r128_getparam_t *param = data; |
1621 | int value; | 1626 | int value; |
1622 | 1627 | ||
1623 | if (!dev_priv) { | 1628 | DEV_INIT_TEST_WITH_RETURN(dev_priv); |
1624 | DRM_ERROR("called with no initialization\n"); | ||
1625 | return -EINVAL; | ||
1626 | } | ||
1627 | 1629 | ||
1628 | DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); | 1630 | DRM_DEBUG("pid=%d\n", DRM_CURRENTPID); |
1629 | 1631 | ||