Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/sunxi Don't allocate edid informations on stack...



details:   https://anonhg.NetBSD.org/src/rev/b75e205c273b
branches:  trunk
changeset: 842658:b75e205c273b
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Fri Jul 19 10:54:26 2019 +0000

description:
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.

diffstat:

 sys/arch/arm/sunxi/sunxi_hdmi.c |  43 +++++++++++++++++++++-------------------
 1 files changed, 23 insertions(+), 20 deletions(-)

diffs (135 lines):

diff -r e29386b98b78 -r b75e205c273b sys/arch/arm/sunxi/sunxi_hdmi.c
--- a/sys/arch/arm/sunxi/sunxi_hdmi.c   Fri Jul 19 08:49:44 2019 +0000
+++ b/sys/arch/arm/sunxi/sunxi_hdmi.c   Fri Jul 19 10:54:26 2019 +0000
@@ -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 <jmcneill%invisible.ca@localhost>
@@ -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 @@
        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 @@
 
        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 @@
        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 @@
        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 @@
                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 @@
                }
        }
 
+       kmem_free(edid, EDID_BLOCK_SIZE);
        return found_hdmi ? DISPLAY_MODE_HDMI : DISPLAY_MODE_DVI;
 }
 



Home | Main Index | Thread Index | Old Index