]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
script: Avoid a use-after-free when redefining a function during execution
authorChris Coulson <chris.coulson@canonical.com>
Fri, 10 Jul 2020 13:41:45 +0000 (14:41 +0100)
committerDaniel Kiper <daniel.kiper@oracle.com>
Wed, 29 Jul 2020 14:55:48 +0000 (16:55 +0200)
Defining a new function with the same name as a previously defined
function causes the grub_script and associated resources for the
previous function to be freed. If the previous function is currently
executing when a function with the same name is defined, this results
in use-after-frees when processing subsequent commands in the original
function.

Instead, reject a new function definition if it has the same name as
a previously defined function, and that function is currently being
executed. Although a behavioural change, this should be backwards
compatible with existing configurations because they can't be
dependent on the current behaviour without being broken.

Fixes: CVE-2020-15706
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
grub-core/script/execute.c
grub-core/script/function.c
grub-core/script/parser.y
include/grub/script_sh.h

index 8a9161cc85192e86145733f174222df23a813b48..ce83edd4b1fe5f22f571fba2416c036151a168bb 100644 (file)
@@ -838,7 +838,9 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args)
   old_scope = scope;
   scope = &new_scope;
 
+  func->executing++;
   ret = grub_script_execute (func->func);
+  func->executing--;
 
   function_return = 0;
   active_loops = loops;
index d36655e510fed843f1e41d4e2b06ad9009a7af74..3aad04bf9dde49bca01f9cefa3ecadb0afc04009 100644 (file)
@@ -34,6 +34,7 @@ grub_script_function_create (struct grub_script_arg *functionname_arg,
   func = (grub_script_function_t) grub_malloc (sizeof (*func));
   if (! func)
     return 0;
+  func->executing = 0;
 
   func->name = grub_strdup (functionname_arg->str);
   if (! func->name)
@@ -60,10 +61,19 @@ grub_script_function_create (struct grub_script_arg *functionname_arg,
       grub_script_function_t q;
 
       q = *p;
-      grub_script_free (q->func);
-      q->func = cmd;
       grub_free (func);
-      func = q;
+      if (q->executing > 0)
+        {
+          grub_error (GRUB_ERR_BAD_ARGUMENT,
+                     N_("attempt to redefine a function being executed"));
+          func = NULL;
+        }
+      else
+        {
+          grub_script_free (q->func);
+          q->func = cmd;
+          func = q;
+        }
     }
   else
     {
index 4f0ab8319e35c21454f3a30da83d59f0498a58a7..f80b86b6f1546259e384432030299abdc469860c 100644 (file)
@@ -289,7 +289,8 @@ function: "function" "name"
              grub_script_mem_free (state->func_mem);
            else {
              script->children = state->scripts;
-             grub_script_function_create ($2, script);
+             if (!grub_script_function_create ($2, script))
+               grub_script_free (script);
            }
 
            state->scripts = $<scripts>3;
index b382bcf09bc8b1c683d72b6f8d8450fac216581d..6c48e0751224743556aacf93be06cf8735e2d60f 100644 (file)
@@ -361,6 +361,8 @@ struct grub_script_function
 
   /* The next element.  */
   struct grub_script_function *next;
+
+  unsigned executing;
 };
 typedef struct grub_script_function *grub_script_function_t;