Module Name:    src
Committed By:   bouyer
Date:           Fri Jul 19 10:54:26 UTC 2019

Modified Files:
        src/sys/arch/arm/sunxi: sunxi_hdmi.c

Log Message:
Don't allocate edid informations on stack, it's too large (struct edid_info is
near 3KB), and causes a stack overflow, corrupting proc0's struct pcb.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/sys/arch/arm/sunxi/sunxi_hdmi.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/sunxi/sunxi_hdmi.c
diff -u src/sys/arch/arm/sunxi/sunxi_hdmi.c:1.6 src/sys/arch/arm/sunxi/sunxi_hdmi.c:1.7
--- src/sys/arch/arm/sunxi/sunxi_hdmi.c:1.6	Sun Jan 27 02:08:37 2019
+++ src/sys/arch/arm/sunxi/sunxi_hdmi.c	Fri Jul 19 10:54:26 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: sunxi_hdmi.c,v 1.6 2019/01/27 02:08:37 pgoyette Exp $ */
+/* $NetBSD: sunxi_hdmi.c,v 1.7 2019/07/19 10:54:26 bouyer Exp $ */
 
 /*-
  * Copyright (c) 2014 Jared D. McNeill <jmcne...@invisible.ca>
@@ -29,12 +29,13 @@
 #include "opt_ddb.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sunxi_hdmi.c,v 1.6 2019/01/27 02:08:37 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sunxi_hdmi.c,v 1.7 2019/07/19 10:54:26 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
 #include <sys/device.h>
 #include <sys/intr.h>
+#include <sys/kmem.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/proc.h>
@@ -650,6 +651,8 @@ sunxi_hdmi_do_enable(struct sunxi_hdmi_s
 	delay(1000);
 }
 
+#define EDID_BLOCK_SIZE 128
+
 static int
 sunxi_hdmi_read_edid_block(struct sunxi_hdmi_softc *sc, uint8_t *data,
     uint8_t block)
@@ -663,27 +666,23 @@ sunxi_hdmi_read_edid_block(struct sunxi_
 
 	wbuf[0] = block;	/* start address */
 
-	if ((error = iic_exec(tag, I2C_OP_READ_WITH_STOP, DDC_ADDR, wbuf, 1,
-	    data, 128, I2C_F_POLL)) != 0) {
-		iic_release_bus(tag, I2C_F_POLL);
-		return error;
-	}
+	error = iic_exec(tag, I2C_OP_READ_WITH_STOP, DDC_ADDR, wbuf, 1,
+	    data, EDID_BLOCK_SIZE, I2C_F_POLL);
 	iic_release_bus(tag, I2C_F_POLL);
-
-	return 0;
+	return error;
 }
 
 static void
 sunxi_hdmi_read_edid(struct sunxi_hdmi_softc *sc)
 {
 	const struct videomode *mode;
-	char edid[128];
-	struct edid_info ei;
+	char *edid;
+	struct edid_info *eip;
 	int retry = 4;
 	u_int display_mode;
 
-	memset(edid, 0, sizeof(edid));
-	memset(&ei, 0, sizeof(ei));
+	edid = kmem_zalloc(EDID_BLOCK_SIZE, KM_SLEEP);
+	eip = kmem_zalloc(sizeof(struct edid_info), KM_SLEEP);
 
 	while (--retry > 0) {
 		if (!sunxi_hdmi_read_edid_block(sc, edid, 0))
@@ -692,18 +691,18 @@ sunxi_hdmi_read_edid(struct sunxi_hdmi_s
 	if (retry == 0) {
 		device_printf(sc->sc_dev, "failed to read EDID\n");
 	} else {
-		if (edid_parse(edid, &ei) != 0) {
+		if (edid_parse(edid, eip) != 0) {
 			device_printf(sc->sc_dev, "failed to parse EDID\n");
 		}
 #ifdef SUNXI_HDMI_DEBUG
 		else {
-			edid_print(&ei);
+			edid_print(eip);
 		}
 #endif
 	}
 
 	if (sc->sc_display_mode == DISPLAY_MODE_AUTO)
-		display_mode = sunxi_hdmi_get_display_mode(sc, &ei);
+		display_mode = sunxi_hdmi_get_display_mode(sc, eip);
 	else
 		display_mode = sc->sc_display_mode;
 
@@ -712,13 +711,13 @@ sunxi_hdmi_read_edid(struct sunxi_hdmi_s
 	device_printf(sc->sc_dev, "%s mode (%s)\n",
 	    display_mode == DISPLAY_MODE_HDMI ? "HDMI" : "DVI", forced);
 
-	strlcpy(sc->sc_display_vendor, ei.edid_vendorname,
+	strlcpy(sc->sc_display_vendor, eip->edid_vendorname,
 	    sizeof(sc->sc_display_vendor));
-	strlcpy(sc->sc_display_product, ei.edid_productname,
+	strlcpy(sc->sc_display_product, eip->edid_productname,
 	    sizeof(sc->sc_display_product));
 	sc->sc_current_display_mode = display_mode;
 
-	mode = ei.edid_preferred_mode;
+	mode = eip->edid_preferred_mode;
 	if (mode == NULL)
 		mode = pick_mode_by_ref(640, 480, 60);
 
@@ -735,15 +734,18 @@ sunxi_hdmi_read_edid(struct sunxi_hdmi_s
 		delay(20000);
 		sunxi_hdmi_video_enable(sc, true);
 	}
+	kmem_free(edid, EDID_BLOCK_SIZE);
+	kmem_free(eip, sizeof(struct edid_info));
 }
 
 static u_int
 sunxi_hdmi_get_display_mode(struct sunxi_hdmi_softc *sc,
     const struct edid_info *ei)
 {
-	char edid[128];
+	char *edid;
 	bool found_hdmi = false;
 	unsigned int n, p;
+	edid = kmem_zalloc(EDID_BLOCK_SIZE, KM_SLEEP);
 
 	/*
 	 * Scan through extension blocks, looking for a CEA-861-D v3
@@ -818,6 +820,7 @@ next_block:
 		}
 	}
 
+	kmem_free(edid, EDID_BLOCK_SIZE);
 	return found_hdmi ? DISPLAY_MODE_HDMI : DISPLAY_MODE_DVI;
 }
 

Reply via email to