Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ed0b577 authored by Eugeni Dodonov's avatar Eugeni Dodonov Committed by Keith Packard
Browse files

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: default avatarKonstantin Belousov <kostikbel@gmail.com>
Acked-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Acked-by: default avatarKeith Packard <keithp@keithp.com>
Reviewed-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarEugeni Dodonov <eugeni.dodonov@intel.com>
Signed-off-by: default avatarKeith Packard <keithp@keithp.com>
parent 03d00ac5
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1454,6 +1454,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);
@@ -1484,6 +1492,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;
}

+1 −0
Original line number Diff line number Diff line
@@ -713,6 +713,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;