1From 26349fcf80982b4d0120b73b2836e88bcf16853c Mon Sep 17 00:00:00 2001 2From: Chris Coulson <chris.coulson@canonical.com> 3Date: Fri, 10 Jul 2020 14:41:45 +0100 4Subject: [PATCH] script: Avoid a use-after-free when redefining a 5 function during execution 6MIME-Version: 1.0 7Content-Type: text/plain; charset=UTF-8 8Content-Transfer-Encoding: 8bit 9 10Defining a new function with the same name as a previously defined 11function causes the grub_script and associated resources for the 12previous function to be freed. If the previous function is currently 13executing when a function with the same name is defined, this results 14in use-after-frees when processing subsequent commands in the original 15function. 16 17Instead, reject a new function definition if it has the same name as 18a previously defined function, and that function is currently being 19executed. Although a behavioural change, this should be backwards 20compatible with existing configurations because they can't be 21dependent on the current behaviour without being broken. 22 23Fixes: CVE-2020-15706 24 25Signed-off-by: Chris Coulson <chris.coulson@canonical.com> 26Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> 27Signed-off-by: Stefan Sørensen <stefan.sorensen@spectralink.com> 28--- 29 grub-core/script/execute.c | 2 ++ 30 grub-core/script/function.c | 16 +++++++++++++--- 31 grub-core/script/parser.y | 3 ++- 32 include/grub/script_sh.h | 2 ++ 33 4 files changed, 19 insertions(+), 4 deletions(-) 34 35diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c 36index c8d6806fe..7e028e135 100644 37--- a/grub-core/script/execute.c 38+++ b/grub-core/script/execute.c 39@@ -838,7 +838,9 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args) 40 old_scope = scope; 41 scope = &new_scope; 42 43+ func->executing++; 44 ret = grub_script_execute (func->func); 45+ func->executing--; 46 47 function_return = 0; 48 active_loops = loops; 49diff --git a/grub-core/script/function.c b/grub-core/script/function.c 50index d36655e51..3aad04bf9 100644 51--- a/grub-core/script/function.c 52+++ b/grub-core/script/function.c 53@@ -34,6 +34,7 @@ grub_script_function_create (struct grub_script_arg *functionname_arg, 54 func = (grub_script_function_t) grub_malloc (sizeof (*func)); 55 if (! func) 56 return 0; 57+ func->executing = 0; 58 59 func->name = grub_strdup (functionname_arg->str); 60 if (! func->name) 61@@ -60,10 +61,19 @@ grub_script_function_create (struct grub_script_arg *functionname_arg, 62 grub_script_function_t q; 63 64 q = *p; 65- grub_script_free (q->func); 66- q->func = cmd; 67 grub_free (func); 68- func = q; 69+ if (q->executing > 0) 70+ { 71+ grub_error (GRUB_ERR_BAD_ARGUMENT, 72+ N_("attempt to redefine a function being executed")); 73+ func = NULL; 74+ } 75+ else 76+ { 77+ grub_script_free (q->func); 78+ q->func = cmd; 79+ func = q; 80+ } 81 } 82 else 83 { 84diff --git a/grub-core/script/parser.y b/grub-core/script/parser.y 85index 4f0ab8319..f80b86b6f 100644 86--- a/grub-core/script/parser.y 87+++ b/grub-core/script/parser.y 88@@ -289,7 +289,8 @@ function: "function" "name" 89 grub_script_mem_free (state->func_mem); 90 else { 91 script->children = state->scripts; 92- grub_script_function_create ($2, script); 93+ if (!grub_script_function_create ($2, script)) 94+ grub_script_free (script); 95 } 96 97 state->scripts = $<scripts>3; 98diff --git a/include/grub/script_sh.h b/include/grub/script_sh.h 99index b382bcf09..6c48e0751 100644 100--- a/include/grub/script_sh.h 101+++ b/include/grub/script_sh.h 102@@ -361,6 +361,8 @@ struct grub_script_function 103 104 /* The next element. */ 105 struct grub_script_function *next; 106+ 107+ unsigned executing; 108 }; 109 typedef struct grub_script_function *grub_script_function_t; 110 111-- 1122.26.2 113 114