mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 05:33:09 +00:00
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. Reported-by: Konstantin Belousov <kostikbel@gmail.com> Acked-by: Jesse Barnes <jbarnes@virtuousgeek.org> Acked-by: Keith Packard <keithp@keithp.com> Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: <stable@vger.kernel.org> Signed-off-by: Eugeni Dodonov <eugeni.dodonov@intel.com> Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
parent
03d00ac53f
commit
4ed0b57745
@ -1454,6 +1454,14 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
|
|||||||
|
|
||||||
diff1 = now - dev_priv->last_time1;
|
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);
|
count1 = I915_READ(DMIEC);
|
||||||
count2 = I915_READ(DDREC);
|
count2 = I915_READ(DDREC);
|
||||||
count3 = I915_READ(CSIEC);
|
count3 = I915_READ(CSIEC);
|
||||||
@ -1484,6 +1492,8 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
|
|||||||
dev_priv->last_count1 = total_count;
|
dev_priv->last_count1 = total_count;
|
||||||
dev_priv->last_time1 = now;
|
dev_priv->last_time1 = now;
|
||||||
|
|
||||||
|
dev_priv->chipset_power = ret;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,6 +713,7 @@ typedef struct drm_i915_private {
|
|||||||
|
|
||||||
u64 last_count1;
|
u64 last_count1;
|
||||||
unsigned long last_time1;
|
unsigned long last_time1;
|
||||||
|
unsigned long chipset_power;
|
||||||
u64 last_count2;
|
u64 last_count2;
|
||||||
struct timespec last_time2;
|
struct timespec last_time2;
|
||||||
unsigned long gfx_power;
|
unsigned long gfx_power;
|
||||||
|
Loading…
Reference in New Issue
Block a user