From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Tue, 7 Feb 2017 02:10:14 +0100
Subject: [PATCH] verifiers: Add possibility to verify kernel and modules
 command lines

Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Ross Philipson <ross.philipson@oracle.com>
(backported from 4d4a8c96e3593d76fe7b025665ccdecc70a53c1f)
Signed-off-by: Daniel Axtens <dja@axtens.net>
---
 grub-core/commands/verifiers.c            | 14 ++++++++++++++
 grub-core/lib/cmdline.c                   |  7 ++++---
 grub-core/loader/arm/linux.c              |  8 ++++++--
 grub-core/loader/arm64/linux.c            | 10 +++++++---
 grub-core/loader/i386/bsd.c               |  6 ++++++
 grub-core/loader/i386/linux.c             | 16 +++++++++++-----
 grub-core/loader/i386/multiboot_mbi.c     | 16 ++++++++++------
 grub-core/loader/i386/pc/linux.c          | 13 ++++++++-----
 grub-core/loader/i386/pc/plan9.c          | 11 +++++++++++
 grub-core/loader/i386/xen.c               |  7 +++++++
 grub-core/loader/ia64/efi/linux.c         |  7 +++++++
 grub-core/loader/mips/linux.c             |  8 ++++++++
 grub-core/loader/multiboot_mbi2.c         |  8 +++-----
 grub-core/loader/powerpc/ieee1275/linux.c |  5 +++--
 grub-core/loader/sparc64/ieee1275/linux.c |  5 +++--
 grub-core/loader/xnu.c                    |  9 +++++++++
 include/grub/lib/cmdline.h                |  5 +++--
 include/grub/verify.h                     | 11 +++++++++++
 18 files changed, 131 insertions(+), 35 deletions(-)

diff --git a/grub-core/commands/verifiers.c b/grub-core/commands/verifiers.c
index fde88318d4c..59ea418a2d9 100644
--- a/grub-core/commands/verifiers.c
+++ b/grub-core/commands/verifiers.c
@@ -186,6 +186,20 @@ grub_verifiers_open (grub_file_t io, enum grub_file_type type)
   return NULL;
 }
 
+grub_err_t
+grub_verify_string (char *str, enum grub_verify_string_type type)
+{
+  struct grub_file_verifier *ver;
+  FOR_LIST_ELEMENTS(ver, grub_file_verifiers)
+    {
+      grub_err_t err;
+      err = ver->verify_string ? ver->verify_string (str, type) : GRUB_ERR_NONE;
+      if (err)
+	return err;
+    }
+  return GRUB_ERR_NONE;
+}
+
 GRUB_MOD_INIT(verifiers)
 {
   grub_file_filter_register (GRUB_FILE_FILTER_VERIFY, grub_verifiers_open);
diff --git a/grub-core/lib/cmdline.c b/grub-core/lib/cmdline.c
index d5c12957cad..463c3c65c79 100644
--- a/grub-core/lib/cmdline.c
+++ b/grub-core/lib/cmdline.c
@@ -75,8 +75,9 @@ unsigned int grub_loader_cmdline_size (int argc, char *argv[])
   return size;
 }
 
-int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
-				grub_size_t size)
+grub_err_t
+grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+			    grub_size_t size, enum grub_verify_string_type type)
 {
   int i, space;
   unsigned int arg_size;
@@ -130,5 +131,5 @@ int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
 		    "grub_kernel_cmdline", orig);
   grub_print_error();
 
-  return i;
+  return grub_verify_string (orig, type);
 }
diff --git a/grub-core/loader/arm/linux.c b/grub-core/loader/arm/linux.c
index ea29d7a724a..beceda52030 100644
--- a/grub-core/loader/arm/linux.c
+++ b/grub-core/loader/arm/linux.c
@@ -28,6 +28,7 @@
 #include <grub/cpu/linux.h>
 #include <grub/lib/cmdline.h>
 #include <grub/linux.h>
+#include <grub/verify.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -383,8 +384,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
   /* Create kernel command line.  */
   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-  grub_create_loader_cmdline (argc, argv,
-			      linux_args + sizeof (LINUX_IMAGE) - 1, size);
+  err = grub_create_loader_cmdline (argc, argv,
+				    linux_args + sizeof (LINUX_IMAGE) - 1, size,
+				    GRUB_VERIFY_KERNEL_CMDLINE);
+  if (err)
+    goto fail;
 
   return GRUB_ERR_NONE;
 
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index 7a076c13171..48ea66596ad 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -33,6 +33,7 @@
 #include <grub/efi/pe32.h>
 #include <grub/i18n.h>
 #include <grub/lib/cmdline.h>
+#include <grub/verify.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -403,9 +404,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-  grub_create_loader_cmdline (argc, argv,
-			      linux_args + sizeof (LINUX_IMAGE) - 1,
-			      cmdline_size);
+  err = grub_create_loader_cmdline (argc, argv,
+				    linux_args + sizeof (LINUX_IMAGE) - 1,
+				    cmdline_size,
+				    GRUB_VERIFY_KERNEL_CMDLINE);
+  if (err)
+    goto fail;
 
   if (grub_errno == GRUB_ERR_NONE)
     {
diff --git a/grub-core/loader/i386/bsd.c b/grub-core/loader/i386/bsd.c
index 8306b415abd..45a71509956 100644
--- a/grub-core/loader/i386/bsd.c
+++ b/grub-core/loader/i386/bsd.c
@@ -36,6 +36,7 @@
 #include <grub/bsdlabel.h>
 #include <grub/crypto.h>
 #include <grub/safemath.h>
+#include <grub/verify.h>
 #ifdef GRUB_MACHINE_PCBIOS
 #include <grub/machine/int.h>
 #endif
@@ -418,6 +419,8 @@ grub_freebsd_add_meta_module (const char *filename, const char *type,
 			      grub_addr_t addr, grub_uint32_t size)
 {
   const char *name;
+  grub_err_t err;
+
   name = grub_strrchr (filename, '/');
   if (name)
     name++;
@@ -471,6 +474,9 @@ grub_freebsd_add_meta_module (const char *filename, const char *type,
 	      *(p++) = ' ';
 	    }
 	  *p = 0;
+	  err = grub_verify_string (cmdline, GRUB_VERIFY_MODULE_CMDLINE);
+	  if (err)
+	    return err;
 	}
     }
 
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index aa2cbc4e7eb..ef8fcb9e1b6 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -1039,11 +1039,17 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   if (!linux_cmdline)
     goto fail;
   grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-  grub_create_loader_cmdline (argc, argv,
-			      linux_cmdline
-			      + sizeof (LINUX_IMAGE) - 1,
-			      maximal_cmdline_size
-			      - (sizeof (LINUX_IMAGE) - 1));
+  {
+    grub_err_t err;
+    err = grub_create_loader_cmdline (argc, argv,
+				      linux_cmdline
+				      + sizeof (LINUX_IMAGE) - 1,
+				      maximal_cmdline_size
+				      - (sizeof (LINUX_IMAGE) - 1),
+				      GRUB_VERIFY_KERNEL_CMDLINE);
+    if (err)
+      goto fail;
+  }
 
   len = prot_file_size;
   grub_memcpy (prot_mode_mem, kernel + kernel_offset, len);
diff --git a/grub-core/loader/i386/multiboot_mbi.c b/grub-core/loader/i386/multiboot_mbi.c
index 9d3466d6ace..525446b5687 100644
--- a/grub-core/loader/i386/multiboot_mbi.c
+++ b/grub-core/loader/i386/multiboot_mbi.c
@@ -676,10 +676,8 @@ grub_multiboot_init_mbi (int argc, char *argv[])
     return grub_errno;
   cmdline_size = len;
 
-  grub_create_loader_cmdline (argc, argv, cmdline,
-			      cmdline_size);
-
-  return GRUB_ERR_NONE;
+  return grub_create_loader_cmdline (argc, argv, cmdline,
+				     cmdline_size, GRUB_VERIFY_KERNEL_CMDLINE);
 }
 
 grub_err_t
@@ -688,6 +686,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
 {
   struct module *newmod;
   grub_size_t len = 0;
+  grub_err_t err;
 
   newmod = grub_malloc (sizeof (*newmod));
   if (!newmod)
@@ -707,8 +706,13 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
   newmod->cmdline_size = len;
   total_modcmd += ALIGN_UP (len, 4);
 
-  grub_create_loader_cmdline (argc, argv, newmod->cmdline,
-			      newmod->cmdline_size);
+  err = grub_create_loader_cmdline (argc, argv, newmod->cmdline,
+				    newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE);
+  if (err)
+    {
+      grub_free (newmod);
+      return grub_errno;
+    }
 
   if (modules_last)
     modules_last->next = newmod;
diff --git a/grub-core/loader/i386/pc/linux.c b/grub-core/loader/i386/pc/linux.c
index b5c28c6580e..f631225f59b 100644
--- a/grub-core/loader/i386/pc/linux.c
+++ b/grub-core/loader/i386/pc/linux.c
@@ -348,11 +348,14 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   /* Create kernel command line.  */
   grub_memcpy ((char *)grub_linux_real_chunk + GRUB_LINUX_CL_OFFSET,
 		LINUX_IMAGE, sizeof (LINUX_IMAGE));
-  grub_create_loader_cmdline (argc, argv,
-			      (char *)grub_linux_real_chunk
-			      + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1,
-			      maximal_cmdline_size
-			      - (sizeof (LINUX_IMAGE) - 1));
+  err = grub_create_loader_cmdline (argc, argv,
+				    (char *)grub_linux_real_chunk
+				    + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1,
+				    maximal_cmdline_size
+				    - (sizeof (LINUX_IMAGE) - 1),
+				    GRUB_VERIFY_KERNEL_CMDLINE);
+  if (err)
+    goto fail;
 
   if (grub_linux_is_bzimage)
     grub_linux_prot_target = GRUB_LINUX_BZIMAGE_ADDR;
diff --git a/grub-core/loader/i386/pc/plan9.c b/grub-core/loader/i386/pc/plan9.c
index 0351090daf8..37550155df7 100644
--- a/grub-core/loader/i386/pc/plan9.c
+++ b/grub-core/loader/i386/pc/plan9.c
@@ -33,6 +33,7 @@
 #include <grub/mm.h>
 #include <grub/cpu/relocator.h>
 #include <grub/extcmd.h>
+#include <grub/verify.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -505,6 +506,7 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[])
   configptr = grub_stpcpy (configptr, "bootfile=");
   configptr = grub_stpcpy (configptr, bootpath);
   *configptr++ = '\n';
+  char *cmdline = configptr;
   {
     int i;
     for (i = 1; i < argc; i++)
@@ -513,6 +515,15 @@ grub_cmd_plan9 (grub_extcmd_context_t ctxt, int argc, char *argv[])
 	*configptr++ = '\n';
       }
   }
+
+  {
+    grub_err_t err;
+    *configptr = '\0';
+    err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
+    if (err)
+      goto fail;
+  }
+
   configptr = grub_stpcpy (configptr, fill_ctx.pmap);
 
   {
diff --git a/grub-core/loader/i386/xen.c b/grub-core/loader/i386/xen.c
index 82350d3a178..07a4837c532 100644
--- a/grub-core/loader/i386/xen.c
+++ b/grub-core/loader/i386/xen.c
@@ -41,6 +41,7 @@
 #include <grub/linux.h>
 #include <grub/i386/memory.h>
 #include <grub/safemath.h>
+#include <grub/verify.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -649,6 +650,9 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
   grub_create_loader_cmdline (argc - 1, argv + 1,
 			      (char *) xen_state.next_start.cmd_line,
 			      sizeof (xen_state.next_start.cmd_line) - 1);
+  err = grub_verify_string (xen_state.next_start.cmd_line, GRUB_VERIFY_MODULE_CMDLINE);
+  if (err)
+    return err;
 
   file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
   if (!file)
@@ -916,6 +920,9 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
 
   grub_create_loader_cmdline (argc - 1, argv + 1,
 			      get_virtual_current_address (ch), cmdline_len);
+  err = grub_verify_string (get_virtual_current_address (ch), GRUB_VERIFY_MODULE_CMDLINE);
+  if (err)
+    goto fail;
 
   xen_state.module_info_page[xen_state.n_modules].cmdline =
     xen_state.max_addr - xen_state.modules_target_start;
diff --git a/grub-core/loader/ia64/efi/linux.c b/grub-core/loader/ia64/efi/linux.c
index 750330d4572..e325fe0ee83 100644
--- a/grub-core/loader/ia64/efi/linux.c
+++ b/grub-core/loader/ia64/efi/linux.c
@@ -33,6 +33,7 @@
 #include <grub/i18n.h>
 #include <grub/env.h>
 #include <grub/linux.h>
+#include <grub/verify.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -543,6 +544,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       p = grub_stpcpy (p, argv[i]);
     }
   cmdline[10] = '=';
+
+  *p = '\0';
+
+  err = grub_verify_string (cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
+  if (err)
+    goto fail;
   
   boot_param->command_line = (grub_uint64_t) cmdline;
   boot_param->efi_systab = (grub_uint64_t) grub_efi_system_table;
diff --git a/grub-core/loader/mips/linux.c b/grub-core/loader/mips/linux.c
index 10358854458..20135ce253d 100644
--- a/grub-core/loader/mips/linux.c
+++ b/grub-core/loader/mips/linux.c
@@ -327,6 +327,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   linux_argv++;
   linux_args += ALIGN_UP (sizeof ("a0"), 4);
 
+  char *params = linux_args;
+
 #ifdef GRUB_MACHINE_MIPS_LOONGSON
   {
     unsigned mtype = grub_arch_machine;
@@ -352,6 +354,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
     }
 
+  *linux_args = '\0';
+
+  err = grub_verify_string (params, GRUB_VERIFY_KERNEL_CMDLINE);
+  if (err)
+    return err;
+
   /* Reserve space for rd arguments.  */
   rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground;
   linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-core/loader/multiboot_mbi2.c
index 3cfb47650a0..f64a857e394 100644
--- a/grub-core/loader/multiboot_mbi2.c
+++ b/grub-core/loader/multiboot_mbi2.c
@@ -1077,10 +1077,8 @@ grub_multiboot2_init_mbi (int argc, char *argv[])
     return grub_errno;
   cmdline_size = len;
 
-  grub_create_loader_cmdline (argc, argv, cmdline,
-			      cmdline_size);
-
-  return GRUB_ERR_NONE;
+  return grub_create_loader_cmdline (argc, argv, cmdline, cmdline_size,
+				     GRUB_VERIFY_KERNEL_CMDLINE);
 }
 
 grub_err_t
@@ -1109,7 +1107,7 @@ grub_multiboot2_add_module (grub_addr_t start, grub_size_t size,
   total_modcmd += ALIGN_UP (len, MULTIBOOT_TAG_ALIGN);
 
   err = grub_create_loader_cmdline (argc, argv, newmod->cmdline,
-				    newmod->cmdline_size);
+				    newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE);
   if (err)
     {
       grub_free (newmod->cmdline);
diff --git a/grub-core/loader/powerpc/ieee1275/linux.c b/grub-core/loader/powerpc/ieee1275/linux.c
index 6e814649f31..c114e7df4fb 100644
--- a/grub-core/loader/powerpc/ieee1275/linux.c
+++ b/grub-core/loader/powerpc/ieee1275/linux.c
@@ -302,8 +302,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
   /* Create kernel command line.  */
   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-  grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
-			      size);
+  if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
+				  size))
+    goto out;
 
 out:
 
diff --git a/grub-core/loader/sparc64/ieee1275/linux.c b/grub-core/loader/sparc64/ieee1275/linux.c
index 67ef0488324..abe46faa012 100644
--- a/grub-core/loader/sparc64/ieee1275/linux.c
+++ b/grub-core/loader/sparc64/ieee1275/linux.c
@@ -340,8 +340,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
   /* Create kernel command line.  */
   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
-  grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
-			      size);
+  if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
+				  size, GRUB_VERIFY_KERNEL_CMDLINE))
+    goto out;
 
 out:
   if (elf)
diff --git a/grub-core/loader/xnu.c b/grub-core/loader/xnu.c
index 9f78abb05f9..5944dc5eafc 100644
--- a/grub-core/loader/xnu.c
+++ b/grub-core/loader/xnu.c
@@ -35,6 +35,7 @@
 #include <grub/i18n.h>
 #include <grub/efi/sb.h>
 #include <grub/safemath.h>
+#include <grub/verify.h>
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -429,6 +430,10 @@ grub_cmd_xnu_kernel (grub_command_t cmd __attribute__ ((unused)),
   if (ptr != grub_xnu_cmdline)
     *(ptr - 1) = 0;
 
+  err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
+  if (err)
+    return err;
+
 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
   err = grub_efiemu_autocore ();
   if (err)
@@ -538,6 +543,10 @@ grub_cmd_xnu_kernel64 (grub_command_t cmd __attribute__ ((unused)),
   if (ptr != grub_xnu_cmdline)
     *(ptr - 1) = 0;
 
+  err = grub_verify_string (grub_xnu_cmdline, GRUB_VERIFY_KERNEL_CMDLINE);
+  if (err)
+    return err;
+
 #if defined (__i386) && !defined (GRUB_MACHINE_EFI)
   err = grub_efiemu_autocore ();
   if (err)
diff --git a/include/grub/lib/cmdline.h b/include/grub/lib/cmdline.h
index 1fe8d017971..cdca09b7a16 100644
--- a/include/grub/lib/cmdline.h
+++ b/include/grub/lib/cmdline.h
@@ -21,11 +21,12 @@
 #define GRUB_CMDLINE_HEADER	1
 
 #include <grub/types.h>
+#include <grub/verify.h>
 
 #define LINUX_IMAGE "BOOT_IMAGE="
 
 unsigned int grub_loader_cmdline_size (int argc, char *argv[]);
-int grub_create_loader_cmdline (int argc, char *argv[], char *buf,
-				grub_size_t size);
+grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf,
+				       grub_size_t size, enum grub_verify_string_type type);
 
 #endif /* ! GRUB_CMDLINE_HEADER */
diff --git a/include/grub/verify.h b/include/grub/verify.h
index 298120f5776..9f892d8fedb 100644
--- a/include/grub/verify.h
+++ b/include/grub/verify.h
@@ -25,6 +25,12 @@ enum grub_verify_flags
     GRUB_VERIFY_FLAGS_SINGLE_CHUNK	= 2
   };
 
+enum grub_verify_string_type
+  {
+    GRUB_VERIFY_KERNEL_CMDLINE,
+    GRUB_VERIFY_MODULE_CMDLINE,
+  };
+
 struct grub_file_verifier
 {
   struct grub_file_verifier *next;
@@ -48,6 +54,8 @@ struct grub_file_verifier
 
   grub_err_t (*fini) (void *context);
   void (*close) (void *context);
+
+  grub_err_t (*verify_string) (char *str, enum grub_verify_string_type type);
 };
 
 extern struct grub_file_verifier *grub_file_verifiers;
@@ -63,3 +71,6 @@ grub_verifier_unregister (struct grub_file_verifier *ver)
 {
   grub_list_remove (GRUB_AS_LIST (ver));
 }
+
+grub_err_t
+grub_verify_string (char *str, enum grub_verify_string_type type);
