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

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