Add "noescape" argument to cmdline creation
authorVladimir Serbinenko <phcoder@gmail.com>
Wed, 19 Jul 2023 13:09:47 +0000 (15:09 +0200)
committerJulian Andres Klode <jak@debian.org>
Sun, 2 Nov 2025 11:08:11 +0000 (12:08 +0100)
If OS parses in a way different from sh-like that GRUB does, escaping does
more harm than good. Note that allows to specify entire command line in a
single argument e.g. multiboot --noescape /kernel "a b c".

Gbp-Pq: Topic upstream
Gbp-Pq: Name Add-noescape-argument-to-cmdline-creation.patch

13 files changed:
grub-core/lib/cmdline.c
grub-core/loader/arm/linux.c
grub-core/loader/arm64/xen_boot.c
grub-core/loader/efi/linux.c
grub-core/loader/i386/linux.c
grub-core/loader/i386/multiboot_mbi.c
grub-core/loader/i386/pc/linux.c
grub-core/loader/i386/xen.c
grub-core/loader/mips/linux.c
grub-core/loader/multiboot_mbi2.c
grub-core/loader/powerpc/ieee1275/linux.c
grub-core/loader/sparc64/ieee1275/linux.c
include/grub/lib/cmdline.h

index ed0b149dca55b84ba42b51049baa9f5205493d18..cc1083e35ddf7f0d07178da8c1c812ceb344744f 100644 (file)
@@ -45,14 +45,14 @@ static unsigned int check_arg (char *c, int *has_space)
   return size;
 }
 
-unsigned int grub_loader_cmdline_size (int argc, char *argv[])
+unsigned int grub_loader_cmdline_size (int argc, char *argv[], int noescape)
 {
   int i;
   unsigned int size = 0;
 
   for (i = 0; i < argc; i++)
     {
-      size += check_arg (argv[i], 0);
+      size += noescape ? grub_strlen(argv[i]) : check_arg (argv[i], 0);
       size++; /* Separator space or NULL.  */
     }
 
@@ -64,16 +64,17 @@ unsigned int grub_loader_cmdline_size (int argc, char *argv[])
 
 grub_err_t
 grub_create_loader_cmdline (int argc, char *argv[], char *buf,
-                           grub_size_t size, enum grub_verify_string_type type)
+                           grub_size_t size, enum grub_verify_string_type type,
+                           int noescape)
 {
-  int i, space;
+  int i, space = 0;
   unsigned int arg_size;
   char *c, *orig_buf = buf;
 
   for (i = 0; i < argc; i++)
     {
       c = argv[i];
-      arg_size = check_arg(argv[i], &space);
+      arg_size = noescape ? grub_strlen(argv[i]) : check_arg(argv[i], &space);
       arg_size++; /* Separator space or NULL.  */
 
       if (size < arg_size)
@@ -81,21 +82,28 @@ grub_create_loader_cmdline (int argc, char *argv[], char *buf,
 
       size -= arg_size;
 
-      if (space)
-       *buf++ = '"';
-
-      while (*c)
+      if (noescape)
        {
-         if (*c == '\\' || *c == '\'' || *c == '"')
-           *buf++ = '\\';
-
-         *buf++ = *c;
-         c++;
+         grub_memcpy(buf, c, arg_size);
+         buf += arg_size;
        }
+      else
+       {
+         if (space)
+           *buf++ = '"';
 
-      if (space)
-       *buf++ = '"';
+         while (*c)
+           {
+             if (*c == '\\' || *c == '\'' || *c == '"')
+               *buf++ = '\\';
 
+             *buf++ = *c;
+             c++;
+           }
+
+         if (space)
+           *buf++ = '"';
+       }
       *buf++ = ' ';
     }
 
index 19ddedbc2ef9a6bfe197c2f1d6210eef45bef1c8..6a052a0dac46f17a7f6cea3392d1df768d52c3d2 100644 (file)
@@ -375,7 +375,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
   grub_loader_set (linux_boot, linux_unload, 0);
 
-  size = grub_loader_cmdline_size (argc, argv);
+  size = grub_loader_cmdline_size (argc, argv, 0);
   linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
   if (!linux_args)
     {
@@ -387,7 +387,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
   err = grub_create_loader_cmdline (argc, argv,
                                    linux_args + sizeof (LINUX_IMAGE) - 1, size,
-                                   GRUB_VERIFY_KERNEL_CMDLINE);
+                                   GRUB_VERIFY_KERNEL_CMDLINE, 0);
   if (err)
     goto fail;
 
index 14afec143fa9ad8e426b7439458d8c6bd0d0691b..c09e45ea09ae0acbb2465b44f3952b4981b7e7ae 100644 (file)
@@ -349,7 +349,7 @@ xen_boot_binary_load (struct xen_boot_binary *binary, grub_file_t file,
 
   if (argc > 1)
     {
-      binary->cmdline_size = grub_loader_cmdline_size (argc - 1, argv + 1);
+      binary->cmdline_size = grub_loader_cmdline_size (argc - 1, argv + 1, 0);
       binary->cmdline = grub_zalloc (binary->cmdline_size);
       if (!binary->cmdline)
        {
@@ -359,7 +359,7 @@ xen_boot_binary_load (struct xen_boot_binary *binary, grub_file_t file,
        }
       grub_create_loader_cmdline (argc - 1, argv + 1, binary->cmdline,
                                  binary->cmdline_size,
-                                 GRUB_VERIFY_KERNEL_CMDLINE);
+                                 GRUB_VERIFY_KERNEL_CMDLINE, 0);
       grub_dprintf ("xen_loader",
                    "Xen_boot cmdline @ %p %s, size: %d\n",
                    binary->cmdline, binary->cmdline, binary->cmdline_size);
index 41d1728ae37619eec504ae2dd6cd69cc1029a98a..bc385f2de7a619d1374e8a3c3a4aa7b25c6e0ec0 100644 (file)
@@ -528,7 +528,7 @@ fallback:
 
   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
 
-  cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE);
+  cmdline_size = grub_loader_cmdline_size (argc, argv, 0) + sizeof (LINUX_IMAGE);
   linux_args = grub_malloc (cmdline_size);
   if (!linux_args)
     {
@@ -539,7 +539,7 @@ fallback:
   err = grub_create_loader_cmdline (argc, argv,
                                    linux_args + sizeof (LINUX_IMAGE) - 1,
                                    cmdline_size,
-                                   GRUB_VERIFY_KERNEL_CMDLINE);
+                                   GRUB_VERIFY_KERNEL_CMDLINE, 0);
   if (err)
     goto fail;
 
index 12731feb20ba85b72a3400e8f18fab198c6ceb2f..9d77f64bf31f00587b20235d630356122b47a7cc 100644 (file)
@@ -1014,7 +1014,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
                                      + sizeof (LINUX_IMAGE) - 1,
                                      maximal_cmdline_size
                                      - (sizeof (LINUX_IMAGE) - 1),
-                                     GRUB_VERIFY_KERNEL_CMDLINE);
+                                     GRUB_VERIFY_KERNEL_CMDLINE, 0);
     if (err)
       goto fail;
   }
index bdaf67ad0120687411ac57928ad3b3b23134e6b4..3268270892df51bcc7e91de97cefcc8a4933797b 100644 (file)
@@ -668,7 +668,7 @@ grub_multiboot_init_mbi (int argc, char *argv[])
 
   grub_multiboot_free_mbi ();
 
-  len = grub_loader_cmdline_size (argc, argv);
+  len = grub_loader_cmdline_size (argc, argv, 0);
 
   cmdline = grub_malloc (len);
   if (! cmdline)
@@ -676,7 +676,7 @@ grub_multiboot_init_mbi (int argc, char *argv[])
   cmdline_size = len;
 
   return grub_create_loader_cmdline (argc, argv, cmdline,
-                                    cmdline_size, GRUB_VERIFY_KERNEL_CMDLINE);
+                                    cmdline_size, GRUB_VERIFY_KERNEL_CMDLINE, 0);
 }
 
 grub_err_t
@@ -694,7 +694,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
   newmod->size = size;
   newmod->next = 0;
 
-  len = grub_loader_cmdline_size (argc, argv);
+  len = grub_loader_cmdline_size (argc, argv, 0);
 
   newmod->cmdline = grub_malloc (len);
   if (! newmod->cmdline)
@@ -706,7 +706,7 @@ grub_multiboot_add_module (grub_addr_t start, grub_size_t size,
   total_modcmd += ALIGN_UP (len, 4);
 
   err = grub_create_loader_cmdline (argc, argv, newmod->cmdline,
-                                   newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE);
+                                   newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE, 0);
   if (err)
     {
       grub_free (newmod);
index 0c2a4ae51222cab69c35daf8990492be4e9b5702..6254e6b788517136f95fa7889e617971e8b6c257 100644 (file)
@@ -345,7 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
                                    + GRUB_LINUX_CL_OFFSET + sizeof (LINUX_IMAGE) - 1,
                                    maximal_cmdline_size
                                    - (sizeof (LINUX_IMAGE) - 1),
-                                   GRUB_VERIFY_KERNEL_CMDLINE);
+                                   GRUB_VERIFY_KERNEL_CMDLINE, 0);
   if (err)
     goto fail;
 
index dcdf005df9e795668a2e6447dde5d83fd4b9ab88..0d31a65bd319fb32b50451eac88447229e1a61fd 100644 (file)
@@ -649,7 +649,7 @@ grub_cmd_xen (grub_command_t cmd __attribute__ ((unused)),
   err = grub_create_loader_cmdline (argc - 1, argv + 1,
                                    (char *) xen_state.next_start.cmd_line,
                                    sizeof (xen_state.next_start.cmd_line) - 1,
-                                   GRUB_VERIFY_KERNEL_CMDLINE);
+                                   GRUB_VERIFY_KERNEL_CMDLINE, 0);
   if (err)
     return err;
 
@@ -909,7 +909,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
     return grub_errno;
   size = grub_file_size (file);
 
-  cmdline_len = grub_loader_cmdline_size (argc - 1, argv + 1);
+  cmdline_len = grub_loader_cmdline_size (argc - 1, argv + 1, 0);
 
   err = grub_relocator_alloc_chunk_addr (xen_state.relocator, &ch,
                                         xen_state.max_addr, cmdline_len);
@@ -918,7 +918,7 @@ grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
 
   err = grub_create_loader_cmdline (argc - 1, argv + 1,
                                    get_virtual_current_address (ch), cmdline_len,
-                                   GRUB_VERIFY_MODULE_CMDLINE);
+                                   GRUB_VERIFY_MODULE_CMDLINE, 0);
   if (err)
     goto fail;
 
index 7264ba2b663be0ef4c4a8d30b640199244f02c67..dedf61280000f3d800269c6fe52403f3d0e69627 100644 (file)
@@ -304,7 +304,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
 #ifdef GRUB_MACHINE_MIPS_QEMU_MIPS
   /* Create kernel command line.  */
-  size = grub_loader_cmdline_size(argc, argv);
+  size = grub_loader_cmdline_size(argc, argv, 0);
   params = grub_malloc (size + sizeof (LINUX_IMAGE));
   if (! params)
     {
@@ -314,7 +314,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
 
   grub_memcpy (params, LINUX_IMAGE, sizeof (LINUX_IMAGE));
   grub_create_loader_cmdline (argc, argv, params + sizeof (LINUX_IMAGE) - 1,
-                             size, GRUB_VERIFY_KERNEL_CMDLINE);
+                             size, GRUB_VERIFY_KERNEL_CMDLINE, 0);
 #else
   linux_argv = extra;
   argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground;
index 00a48413c01383991f7efc3e0e8322c540b8fb43..8a81a035985b2fa0d30390fd3464835953e5daab 100644 (file)
@@ -1037,7 +1037,7 @@ grub_multiboot2_init_mbi (int argc, char *argv[])
 
   grub_multiboot2_free_mbi ();
 
-  len = grub_loader_cmdline_size (argc, argv);
+  len = grub_loader_cmdline_size (argc, argv, 0);
 
   cmdline = grub_malloc (len);
   if (! cmdline)
@@ -1045,7 +1045,7 @@ grub_multiboot2_init_mbi (int argc, char *argv[])
   cmdline_size = len;
 
   return grub_create_loader_cmdline (argc, argv, cmdline, cmdline_size,
-                                    GRUB_VERIFY_KERNEL_CMDLINE);
+                                    GRUB_VERIFY_KERNEL_CMDLINE, 0);
 }
 
 grub_err_t
@@ -1062,7 +1062,7 @@ grub_multiboot2_add_module (grub_addr_t start, grub_size_t size,
   newmod->start = start;
   newmod->size = size;
 
-  len = grub_loader_cmdline_size (argc, argv);
+  len = grub_loader_cmdline_size (argc, argv, 0);
 
   newmod->cmdline = grub_malloc (len);
   if (! newmod->cmdline)
@@ -1074,7 +1074,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, GRUB_VERIFY_MODULE_CMDLINE);
+                                   newmod->cmdline_size, GRUB_VERIFY_MODULE_CMDLINE, 0);
   if (err)
     {
       grub_free (newmod->cmdline);
index 4864e5fb0d3e261f6eab7b231ebba6d91396de56..45461f26ae46ce6808ad00482796aefbbe14d094 100644 (file)
@@ -306,7 +306,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       goto out;
     }
 
-  size = grub_loader_cmdline_size(argc, argv);
+  size = grub_loader_cmdline_size(argc, argv, 0);
   linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
   if (! linux_args)
     goto out;
@@ -314,7 +314,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   /* Create kernel command line.  */
   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
   if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
-                                 size, GRUB_VERIFY_KERNEL_CMDLINE))
+                                 size, GRUB_VERIFY_KERNEL_CMDLINE, 0))
     goto out;
 
 out:
index ac2206f3c051bbf66b166be8b10a61ce3d9dbc7e..de31a079216644fbb25ab6fbd1e8a6157af057f6 100644 (file)
@@ -332,7 +332,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       goto out;
     }
 
-  size = grub_loader_cmdline_size(argc, argv);
+  size = grub_loader_cmdline_size(argc, argv, 0);
 
   linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
   if (! linux_args)
@@ -341,7 +341,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
   /* Create kernel command line.  */
   grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
   if (grub_create_loader_cmdline (argc, argv, linux_args + sizeof (LINUX_IMAGE) - 1,
-                                 size, GRUB_VERIFY_KERNEL_CMDLINE))
+                                 size, GRUB_VERIFY_KERNEL_CMDLINE, 0))
     goto out;
 
 out:
index cdca09b7a164c0f22f04bddd52c4fc4f61ea1a56..c1210ec21a69ad779ba5c71ff72fd23f016f613f 100644 (file)
@@ -25,8 +25,9 @@
 
 #define LINUX_IMAGE "BOOT_IMAGE="
 
-unsigned int grub_loader_cmdline_size (int argc, char *argv[]);
+unsigned int grub_loader_cmdline_size (int argc, char *argv[], int noescape);
 grub_err_t grub_create_loader_cmdline (int argc, char *argv[], char *buf,
-                                      grub_size_t size, enum grub_verify_string_type type);
+                                      grub_size_t size, enum grub_verify_string_type type,
+                                      int noescape);
 
 #endif /* ! GRUB_CMDLINE_HEADER */