Blame SOURCES/0298-script-Avoid-a-use-after-free-when-redefining-a-func.patch

5975ab
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
a4d572
From: Chris Coulson <chris.coulson@canonical.com>
a4d572
Date: Fri, 10 Jul 2020 14:41:45 +0100
5975ab
Subject: [PATCH] script: Avoid a use-after-free when redefining a function
5975ab
 during execution
a4d572
a4d572
Defining a new function with the same name as a previously defined
a4d572
function causes the grub_script and associated resources for the
a4d572
previous function to be freed. If the previous function is currently
a4d572
executing when a function with the same name is defined, this results
a4d572
in use-after-frees when processing subsequent commands in the original
a4d572
function.
a4d572
a4d572
Instead, reject a new function definition if it has the same name as
a4d572
a previously defined function, and that function is currently being
a4d572
executed. Although a behavioural change, this should be backwards
a4d572
compatible with existing configurations because they can't be
a4d572
dependent on the current behaviour without being broken.
a4d572
a4d572
Signed-off-by: Chris Coulson <chris.coulson@canonical.com>
a4d572
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
a4d572
Upstream-commit-id: f6253a1f540
a4d572
---
a4d572
 grub-core/script/execute.c  |  2 ++
a4d572
 grub-core/script/function.c | 16 +++++++++++++---
a4d572
 include/grub/script_sh.h    |  2 ++
a4d572
 grub-core/script/parser.y   |  3 ++-
a4d572
 4 files changed, 19 insertions(+), 4 deletions(-)
a4d572
a4d572
diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
09e3cc
index 528ddfd36..a1aadb9ee 100644
a4d572
--- a/grub-core/script/execute.c
a4d572
+++ b/grub-core/script/execute.c
a4d572
@@ -872,7 +872,9 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args)
a4d572
   old_scope = scope;
a4d572
   scope = &new_scope;
a4d572
 
a4d572
+  func->executing++;
a4d572
   ret = grub_script_execute (func->func);
a4d572
+  func->executing--;
a4d572
 
a4d572
   function_return = 0;
a4d572
   active_loops = loops;
a4d572
diff --git a/grub-core/script/function.c b/grub-core/script/function.c
09e3cc
index d36655e51..3aad04bf9 100644
a4d572
--- a/grub-core/script/function.c
a4d572
+++ b/grub-core/script/function.c
a4d572
@@ -34,6 +34,7 @@ grub_script_function_create (struct grub_script_arg *functionname_arg,
a4d572
   func = (grub_script_function_t) grub_malloc (sizeof (*func));
a4d572
   if (! func)
a4d572
     return 0;
a4d572
+  func->executing = 0;
a4d572
 
a4d572
   func->name = grub_strdup (functionname_arg->str);
a4d572
   if (! func->name)
a4d572
@@ -60,10 +61,19 @@ grub_script_function_create (struct grub_script_arg *functionname_arg,
a4d572
       grub_script_function_t q;
a4d572
 
a4d572
       q = *p;
a4d572
-      grub_script_free (q->func);
a4d572
-      q->func = cmd;
a4d572
       grub_free (func);
a4d572
-      func = q;
a4d572
+      if (q->executing > 0)
a4d572
+        {
a4d572
+          grub_error (GRUB_ERR_BAD_ARGUMENT,
a4d572
+		      N_("attempt to redefine a function being executed"));
a4d572
+          func = NULL;
a4d572
+        }
a4d572
+      else
a4d572
+        {
a4d572
+          grub_script_free (q->func);
a4d572
+          q->func = cmd;
a4d572
+          func = q;
a4d572
+        }
a4d572
     }
a4d572
   else
a4d572
     {
a4d572
diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h
09e3cc
index b382bcf09..6c48e0751 100644
a4d572
--- a/include/grub/script_sh.h
a4d572
+++ b/include/grub/script_sh.h
a4d572
@@ -361,6 +361,8 @@ struct grub_script_function
a4d572
 
a4d572
   /* The next element.  */
a4d572
   struct grub_script_function *next;
a4d572
+
a4d572
+  unsigned executing;
a4d572
 };
a4d572
 typedef struct grub_script_function *grub_script_function_t;
a4d572
 
a4d572
diff --git a/grub-core/script/parser.y b/grub-core/script/parser.y
09e3cc
index 4f0ab8319..f80b86b6f 100644
a4d572
--- a/grub-core/script/parser.y
a4d572
+++ b/grub-core/script/parser.y
a4d572
@@ -289,7 +289,8 @@ function: "function" "name"
a4d572
 	      grub_script_mem_free (state->func_mem);
a4d572
 	    else {
a4d572
 	      script->children = state->scripts;
a4d572
-	      grub_script_function_create ($2, script);
a4d572
+	      if (!grub_script_function_create ($2, script))
a4d572
+		grub_script_free (script);
a4d572
 	    }
a4d572
 
a4d572
 	    state->scripts = $<scripts>3;