All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drm/drm_edid: Read within initialized memory bounds (fix off by one)
@ 2021-04-19  3:04 Greg Steuck
  0 siblings, 0 replies; only message in thread
From: Greg Steuck @ 2021-04-19  3:04 UTC (permalink / raw)
  To: dri-devel

This is my first patch which I tested to work on OpenBSD and then
confirmed compiling in Linux.

From c4f815bf0fa55a3a68caa7c721ea3dd8ac5c3d29 Mon Sep 17 00:00:00 2001
From: Greg Steuck <linux-drm@nest.cx>
Date: Thu, 15 Apr 2021 21:44:57 -0700
Subject: [PATCH] drm/drm_edid: Read within initialized memory bounds (fix off
 by one)

The problem manifests as a memory out of bounds kernel panic in
OpenBSD which uses this code. The buggy error reporting code path
likely never runs with nominal hardware.

drm_do_get_edid at carp used to invoke connector_bad_edid was num_exts
of 1 even though edid at that point is only allocated a memory block
of size EDID_LENGTH. This in turn led to drm_edid_block_checksum
trying to read memory in the range [edid + EDID_LENGTH, edid +
2*EDID_LENGTH) i.e. outside the allocated boundaries. A similar if a
bit more complicated analysis applies to the other call to
connector_bad_edid. Switching to using valid_extensions limits
connector_bad_edid memory reading to the memory previously written by
drm_do_get_edid.

OpenBSD bug report https://marc.info/?l=openbsd-bugs&m=161794843427437

Signed-off-by: Greg Steuck <linux-drm@nest.cx>
---
 drivers/gpu/drm/drm_edid.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 81d5f2524246..f731bf7ac715 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1831,20 +1831,20 @@ drm_do_probe_ddc_edid(void *data, u8 *buf, unsigned int block, size_t len)
 }
 
 static void connector_bad_edid(struct drm_connector *connector,
-			       u8 *edid, int num_blocks)
+			       u8 *edid, int valid_extensions)
 {
 	int i;
 	u8 num_of_ext = edid[0x7e];
 
 	/* Calculate real checksum for the last edid extension block data */
 	connector->real_edid_checksum =
-		drm_edid_block_checksum(edid + num_of_ext * EDID_LENGTH);
+		drm_edid_block_checksum(edid + valid_extensions * EDID_LENGTH);
 
 	if (connector->bad_edid_counter++ && !drm_debug_enabled(DRM_UT_KMS))
 		return;
 
 	drm_dbg_kms(connector->dev, "%s: EDID is invalid:\n", connector->name);
-	for (i = 0; i < num_blocks; i++) {
+	for (i = 0; i <= valid_extensions; i++) {
 		u8 *block = edid + i * EDID_LENGTH;
 		char prefix[20];
 
@@ -1983,7 +1983,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
 	if (valid_extensions != edid[0x7e]) {
 		u8 *base;
 
-		connector_bad_edid(connector, edid, edid[0x7e] + 1);
+		connector_bad_edid(connector, edid, valid_extensions);
 
 		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
 		edid[0x7e] = valid_extensions;
@@ -2011,7 +2011,7 @@ struct edid *drm_do_get_edid(struct drm_connector *connector,
 	return (struct edid *)edid;
 
 carp:
-	connector_bad_edid(connector, edid, 1);
+	connector_bad_edid(connector, edid, 0);
 out:
 	kfree(edid);
 	return NULL;
-- 
2.31.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2021-04-19  6:43 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-04-19  3:04 [PATCH] drm/drm_edid: Read within initialized memory bounds (fix off by one) Greg Steuck

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.