History

drm/i915: prevent division by zero when asking for chipset power

This prevents an in-kernel division by zero which happens when we are asking for i915_chipset_val too quickly, or within a race condition between the power monitoring thread and userspace accesses via debugfs. The issue can be reproduced easily via the following command: while ``; do cat /sys/kernel/debug/dri/0/i915_emon_status; done This is particularly dangerous because it can be triggered by a non-privileged user by just reading the debugfs entry. This issue was also found independently by Konstantin Belousov <kostikbel@gmail.com>, who proposed a similar patch.

Eugeni Dodonov committed 15 years ago

Commit 4ed0b571 parent 03d00ac2 files · +11 −0Browse files

Unified · Split

2 files
  1. drivers/gpu/drm/i915/i915_dma.c +10 −0
  2. drivers/gpu/drm/i915/i915_drv.h +1 −0
drivers/gpu/drm/i915/i915_dma.c+10−0
@@ -1454,6 +1454,14 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) · 1453 unmodified lines
1454 1454
1455 diff1 = now - dev_priv->last_time1;1455 diff1 = now - dev_priv->last_time1;
1456 1456
1457 /* Prevent division-by-zero if we are asking too fast.
1458 * Also, we don't get interesting results if we are polling
1459 * faster than once in 10ms, so just return the saved value
1460 * in such cases.
1461 */
1462 if (diff1 <= 10)
1463 return dev_priv->chipset_power;
1464
1457 count1 = I915_READ(DMIEC);1465 count1 = I915_READ(DMIEC);
1458 count2 = I915_READ(DDREC);1466 count2 = I915_READ(DDREC);
1459 count3 = I915_READ(CSIEC);1467 count3 = I915_READ(CSIEC);
@@ -1484,6 +1492,8 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) · 24 unmodified lines
1484 dev_priv->last_count1 = total_count;1492 dev_priv->last_count1 = total_count;
1485 dev_priv->last_time1 = now;1493 dev_priv->last_time1 = now;
1486 1494
1495 dev_priv->chipset_power = ret;
1496
1487 return ret;1497 return ret;
1488}1498}
1489 1499
drivers/gpu/drm/i915/i915_drv.h+1−0
@@ -713,6 +713,7 @@ typedef struct drm_i915_private { · 712 unmodified lines
713 713
714 u64 last_count1;714 u64 last_count1;
715 unsigned long last_time1;715 unsigned long last_time1;
716 unsigned long chipset_power;
716 u64 last_count2;717 u64 last_count2;
717 struct timespec last_time2;718 struct timespec last_time2;
718 unsigned long gfx_power;719 unsigned long gfx_power;