script: Avoid a use-after-free when redefining a function during execution
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>
This commit is contained in:
parent
1a8d9c9b4a
commit
426f57383d
4 changed files with 19 additions and 4 deletions
|
@ -838,7 +838,9 @@ grub_script_function_call (grub_script_function_t func, int argc, char **args)
|
||||||
old_scope = scope;
|
old_scope = scope;
|
||||||
scope = &new_scope;
|
scope = &new_scope;
|
||||||
|
|
||||||
|
func->executing++;
|
||||||
ret = grub_script_execute (func->func);
|
ret = grub_script_execute (func->func);
|
||||||
|
func->executing--;
|
||||||
|
|
||||||
function_return = 0;
|
function_return = 0;
|
||||||
active_loops = loops;
|
active_loops = loops;
|
||||||
|
|
|
@ -34,6 +34,7 @@ grub_script_function_create (struct grub_script_arg *functionname_arg,
|
||||||
func = (grub_script_function_t) grub_malloc (sizeof (*func));
|
func = (grub_script_function_t) grub_malloc (sizeof (*func));
|
||||||
if (! func)
|
if (! func)
|
||||||
return 0;
|
return 0;
|
||||||
|
func->executing = 0;
|
||||||
|
|
||||||
func->name = grub_strdup (functionname_arg->str);
|
func->name = grub_strdup (functionname_arg->str);
|
||||||
if (! func->name)
|
if (! func->name)
|
||||||
|
@ -60,11 +61,20 @@ grub_script_function_create (struct grub_script_arg *functionname_arg,
|
||||||
grub_script_function_t q;
|
grub_script_function_t q;
|
||||||
|
|
||||||
q = *p;
|
q = *p;
|
||||||
|
grub_free (func);
|
||||||
|
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);
|
grub_script_free (q->func);
|
||||||
q->func = cmd;
|
q->func = cmd;
|
||||||
grub_free (func);
|
|
||||||
func = q;
|
func = q;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
func->next = *p;
|
func->next = *p;
|
||||||
|
|
|
@ -289,7 +289,8 @@ function: "function" "name"
|
||||||
grub_script_mem_free (state->func_mem);
|
grub_script_mem_free (state->func_mem);
|
||||||
else {
|
else {
|
||||||
script->children = state->scripts;
|
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;
|
state->scripts = $<scripts>3;
|
||||||
|
|
|
@ -361,6 +361,8 @@ struct grub_script_function
|
||||||
|
|
||||||
/* The next element. */
|
/* The next element. */
|
||||||
struct grub_script_function *next;
|
struct grub_script_function *next;
|
||||||
|
|
||||||
|
unsigned executing;
|
||||||
};
|
};
|
||||||
typedef struct grub_script_function *grub_script_function_t;
|
typedef struct grub_script_function *grub_script_function_t;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue