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>
old_scope = scope;
scope = &new_scope;
+ func->executing++;
ret = grub_script_execute (func->func);
+ func->executing--;
function_return = 0;
active_loops = loops;
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)
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
{
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;
/* The next element. */
struct grub_script_function *next;
+
+ unsigned executing;
};
typedef struct grub_script_function *grub_script_function_t;