Skip to content

Commit

Permalink
drm/i915: prevent division by zero when asking for chipset power
Browse files Browse the repository at this point in the history
commit 4ed0b57 upstream.

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
<[email protected]>, who proposed a similar patch.

Reported-by: Konstantin Belousov <[email protected]>
Acked-by: Jesse Barnes <[email protected]>
Acked-by: Keith Packard <[email protected]>
Reviewed-by: Chris Wilson <[email protected]>
Signed-off-by: Eugeni Dodonov <[email protected]>
Signed-off-by: Keith Packard <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Eugeni Dodonov authored and gregkh committed Jan 6, 2012
1 parent bd43f8f commit 183647b
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 0 deletions.
10 changes: 10 additions & 0 deletions drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,14 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)

diff1 = now - dev_priv->last_time1;

/* Prevent division-by-zero if we are asking too fast.
* Also, we don't get interesting results if we are polling
* faster than once in 10ms, so just return the saved value
* in such cases.
*/
if (diff1 <= 10)
return dev_priv->chipset_power;

count1 = I915_READ(DMIEC);
count2 = I915_READ(DDREC);
count3 = I915_READ(CSIEC);
Expand Down Expand Up @@ -1481,6 +1489,8 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
dev_priv->last_count1 = total_count;
dev_priv->last_time1 = now;

dev_priv->chipset_power = ret;

return ret;
}

Expand Down
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,7 @@ typedef struct drm_i915_private {

u64 last_count1;
unsigned long last_time1;
unsigned long chipset_power;
u64 last_count2;
struct timespec last_time2;
unsigned long gfx_power;
Expand Down

0 comments on commit 183647b

Please sign in to comment.