efi_loader: NULL dereference in EFI console
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Tue, 16 Mar 2021 11:56:57 +0000 (12:56 +0100)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Fri, 19 Mar 2021 19:47:25 +0000 (20:47 +0100)
Even if CONFIG_DM_VIDEO=y and stdout="vidconsole", a video device may not
be available. Check the return values of the relevant functions.

If no video output device is available, assume that the serial console is
in use.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
lib/efi_loader/efi_console.c

index c400355..6040f3a 100644 (file)
@@ -254,7 +254,7 @@ static bool cout_mode_matches(struct cout_mode *mode, int rows, int cols)
 }
 
 /**
- * query_console_serial() - query console size
+ * query_console_serial() - query serial console size
  *
  * When using a serial console or the net console we can only devise the
  * terminal size by querying the terminal using ECMA-48 control sequences.
@@ -300,6 +300,37 @@ out:
 }
 
 /**
+ * query_vidconsole() - query video console size
+ *
+ *
+ * @rows:      pointer to return number of rows
+ * @cols:      pointer to return number of columns
+ * Returns:    0 on success
+ */
+static int __maybe_unused query_vidconsole(int *rows, int *cols)
+{
+       const char *stdout_name = env_get("stdout");
+       struct stdio_dev *stdout_dev;
+       struct udevice *dev;
+       struct vidconsole_priv *priv;
+
+       if (!stdout_name || strncmp(stdout_name, "vidconsole", 10))
+               return -ENODEV;
+       stdout_dev = stdio_get_by_name("vidconsole");
+       if (!stdout_dev)
+               return -ENODEV;
+       dev = stdout_dev->priv;
+       if (!dev)
+               return -ENODEV;
+       priv = dev_get_uclass_priv(dev);
+       if (!priv)
+               return -ENODEV;
+       *rows = priv->rows;
+       *cols = priv->cols;
+       return 0;
+}
+
+/**
  * query_console_size() - update the mode table.
  *
  * By default the only mode available is 80x25. If the console has at least 50
@@ -308,21 +339,15 @@ out:
  */
 static void query_console_size(void)
 {
-       const char *stdout_name = env_get("stdout");
        int rows = 25, cols = 80;
+       int ret = -ENODEV;
 
-       if (stdout_name && !strncmp(stdout_name, "vidconsole", 10) &&
-           IS_ENABLED(CONFIG_DM_VIDEO)) {
-               struct stdio_dev *stdout_dev =
-                       stdio_get_by_name("vidconsole");
-               struct udevice *dev = stdout_dev->priv;
-               struct vidconsole_priv *priv =
-                       dev_get_uclass_priv(dev);
-               rows = priv->rows;
-               cols = priv->cols;
-       } else if (query_console_serial(&rows, &cols)) {
+       if IS_ENABLED(CONFIG_DM_VIDEO)
+               ret = query_vidconsole(&rows, &cols);
+       if (ret)
+               ret = query_console_serial(&rows, &cols);
+       if (ret)
                return;
-       }
 
        /* Test if we can have Mode 1 */
        if (cols >= 80 && rows >= 50) {